I'm making a recipe search application using forkify API. I get such json (let's take pizza recipes for example). I've made a recycler and searchable, but the recipes themselves are given as a link to the site with that recipe (see source_url in the json). I've made a webview for this, but there's one problem. I need to get that source_url and have it match the recipe I clicked on. I tried to make an additional element in resycler, small invisible textview, and put source_url there, so when I clicked on it, it would take text and pass it to a variable and load it as url into webview. (Very silly solution, but I didn't think of another one.) It's not what I had in mind. Basically my code works, but the url is not passed from all textViews. I've been observing its behaviour and I can only assume that it loads every 4 in vertical mode and every 2 in horizontal mode. And this is not what I need. Please help me to solve this problem. Below is my code:
Adapter:
#JvmOverloads
fun RecyclerView.affectOnItemClicks(
onClick: ((position: Int, view: View) -> Unit)? = null,
onLongClick: ((position: Int, view: View) -> Unit)? = null
) {
this.addOnChildAttachStateChangeListener(
RecyclerItemClickListener(
this,
onClick,
onLongClick
)
)
}
class RecyclerAdapter(
private val dataset: List<Recipe>
)
: RecyclerView.Adapter<RecyclerAdapter.FoodHolder>() {
inner class FoodHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bindRecipe(recipe: Recipe) {
itemView.textView.text = recipe.title
itemView.textView3.text = recipe.publisher
itemView.imageView.load(recipe.image_url) {
// placeholder image is the image used
// when our image url fails to load.
placeholder(R.drawable.ic_baseline_error_24)
}
itemView.helptv.text = recipe.source_url
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerAdapter.FoodHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.recyclerview_item_row, parent, false)
return FoodHolder(view)
}
override fun onBindViewHolder(holder: RecyclerAdapter.FoodHolder, position: Int) {
holder.bindRecipe(dataset.get(position))
}
override fun getItemCount(): Int = dataset.size
}
The code in the MainActivity where I put the text from that textview into an auxiliary variable and then switch to another activation:
ConstandVar.browser_url = helptv.text.toString()
val intent = Intent(this,BrowserActivity::class.java)
startActivity(intent)
layout recyclerview:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<com.google.android.material.card.MaterialCardView
android:id="#+id/materialCardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_marginBottom="5dp"
android:clickable="false"
app:cardElevation="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:state_dragged="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/item_constraint"
android:layout_width="match_parent"
android:layout_height="120dp"
android:padding="5dp">
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="#tools:sample/avatars" />
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="90dp"
android:layout_marginTop="5dp"
android:text="Title"
android:textColor="#000000"
android:textSize="22sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="publisher: The Pioner Women"
android:textColor="#E57373"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/imageView"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/helptv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="1sp"
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>
Receive json method:
fun getRecipe(callback: (List) -> Unit) {
val apiService = AppModule.provideRetrofitInstance(ConstandVar.BASE_URL)
apiService.getRecipe(food).enqueue(object : Callback<requestdata> {
override fun onFailure(call: Call<requestdata>, t: Throwable) {
Log.d("tag", "getRecipe Error")
}
override fun onResponse(call: Call<requestdata>, response: Response<requestdata>) {
return response.body()!!.recipes?.let { callback(it) }!!
}
})
Any help would be much appreciated, thanks in advance!
Please make little bit change to make adapter like that way
read most of comment ,
RecyclerView itemClickListener in Kotlin
create callback listener and return url in main activity
Related
I am working on the recycler view, but I face one problem: the item alignment is not correct. How can I solve this problem?
I need the items to match the parent's width.
What I want
Problem
Code :-
Adapter -
class CancelBookingAdapter(
val data: List<CancelReasonsResponse.Data>,
val callBack: CancelBookingCallBack
) : RecyclerView.Adapter<CancelBookingAdapter.ViewHolder>() {
var selectedPosition = -1
var comments = ""
class ViewHolder(val binding: CancelAdapterBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = CancelAdapterBinding.inflate(LayoutInflater.from(parent.context),null,false)
val lp = RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
return ViewHolder(binding)
}
enter code here
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.binding.apply {
tvReasonText.text = data[position].title
if (selectedPosition == -1) {
comments = ""
}else {
comments = data[position].title
}
if (selectedPosition == position) {
llReason.setBackgroundResource(R.drawable.selected_box)
}else {
llReason.setBackgroundResource(R.drawable.cancel_outline)
}
llReason.setOnClickListener {
selectedPosition = holder.adapterPosition
callBack.onClickCheckBox(data[position].id, comments)
selectedPosition = position
notifyDataSetChanged()
}
}
}
override fun getItemCount(): Int {
return data.size
}
}
interface CancelBookingCallBack {
fun onClickCheckBox(reasonId: Int, comment: String)
}
Item XML -
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="#+id/llReason"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="#dimen/_12sdp"
android:gravity="center"
android:background="#drawable/cancel_outline"
android:layout_marginBottom="#dimen/_12sdp">
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tvReasonText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/space_grotesk_bold"
android:gravity="center"
android:text="#string/cancel_booking"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.appcompat.widget.LinearLayoutCompat>
android:layout_width="match_parent"
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tvReasonText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="#font/space_grotesk_bold"
android:gravity="center"
android:text="#string/cancel_booking"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
With this code you can maximize the width.
android:layout_width="match_parent"
or
android:layout_width="0dp"
this code will help you to center the text
android:textAlignment="center"
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tvReasonText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:fontFamily="#font/space_grotesk_bold"
android:gravity="center"
android:text="#string/cancel_booking"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
I got some problems with NullPointerExceptions but I got no clue how to fix it
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.LinearLayout.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
at com.example.bputs.MainActivity.setupUI(MainActivity.kt:63)
at com.example.bputs.MainActivity.onCreate(MainActivity.kt:31)
I can find the problem is in the MainActivity, but let me know how to change it so here's the MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var productViewModel: ProductViewModel
private lateinit var bottomSheet : BottomSheetBehavior<*>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide()
setupUI()
}
private fun setupUI() {
productViewModel = ViewModelProvider(this).get(ProductViewModel::class.java)
rv_main_product.apply {
layoutManager = if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
GridLayoutManager(this#MainActivity, 2)
} else {
GridLayoutManager(this#MainActivity,4)
}
adapter = ProductsAdapter(mutableListOf(), this#MainActivity, productViewModel)
}
rv_selected_produk.apply {
layoutManager = LinearLayoutManager(this#MainActivity)
adapter = SelectedProductAdapter(mutableListOf(), this#MainActivity, productViewModel)
}
bottomSheet = BottomSheetBehavior.from(detail_order)
bottomSheet.state = BottomSheetBehavior.STATE_HIDDEN
detailBtn.setOnClickListener {
if (bottomSheet.state == BottomSheetBehavior.STATE_COLLAPSED || bottomSheet.state == BottomSheetBehavior.STATE_HIDDEN) {
bottomSheet.state = BottomSheetBehavior.STATE_EXPANDED
} else {
bottomSheet.state = BottomSheetBehavior.STATE_HIDDEN
}
}
productViewModel.fetchDummy()
productViewModel.listenToProducts().observe(this, Observer {
rv_main_product.adapter?.let { p ->
if (p is ProductsAdapter) {
p.updateList(it)
}
}
})
And here's the XML page
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:background="#color/warnaUtama">
<LinearLayout
android:id="#+id/layout_atas"
android:layout_width="match_parent"
android:layout_height="100dp">
<ImageView
android:layout_width="70dp"
android:layout_height="70dp"
android:src="#drawable/logo"
android:layout_marginTop="20dp"
android:layout_marginLeft="18dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/poppinssemibold"
android:layout_centerHorizontal="true"
android:text="Beautyper"
android:textSize="38dp"
android:layout_marginTop="20dp"
android:paddingLeft="25dp"
android:textColor="#color/warnaKedua"/>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_main_product"
android:layout_width="match_parent"
android:layout_height="560dp"
android:layout_marginTop="100dp"
android:padding="8dp"/>
<include layout="#layout/cart"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginRight="20dp"
android:layout_marginLeft="20dp"
android:layout_marginBottom="10dp"
android:weightSum="2"
android:layout_gravity="bottom"
android:background="#drawable/btn_shape">
<TextView
android:id="#+id/checkoutBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Checkout"
android:paddingStart="16dp"
android:padding="8dp"
android:fontFamily="#font/poppinsbold"
android:textColor="#color/white"
android:layout_weight="1.5"/>
<ImageView
android:id="#+id/detailBtn"
android:layout_gravity="center_vertical"
android:layout_width="20dp"
android:layout_height="35dp"
android:layout_marginRight="10dp"
android:layout_weight="0.5"
android:src="#drawable/ic_baseline_expand_less_24"/>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Please help me out of this problem, I'm new at this so now I'm Stuck. What can I do with the LinearLayout?
I don't quite understand your code because you have removed lines that I feel would help me understand a little more. What if from the log I can understand that the problem may be due to 2 things that I imagine:
You may be placing the id of detailBtn wrong, because the log says that your LinearLayout contains a ClickListener event, but I don't see it in the code
You are calling setOnClickListener when the fragment is in another state than OnCreate, I'm not sure if the bottomSheet changes this state, but it could be the problem too. Because of this the app may not find the view.
I want to achieve expand and collapse in RecyclerView as mentioned in gif. By taping and swiping down & up.
I have tried below,
https://stackoverflow.com/a/13381228/11630822
that is fine but not what I expected.
I have used RecyclerView for listing all Notification inside the app. If anyone have any ideas or experience , then please share with me. Any help will be appreciated. Thanks in advance.
In most of the sites, able to find way to acheive swipe left and right, but not swipe up and down. I want to achieve swipe up and down as like swipe left and swipe right.
In the gif I didnt use arrow for expand and collapse, I just swiped up and down. I want to achieve the samething in recyclerview inside the app.
You can use Transition or Animator that changes visibility of section to be expanded/collapsed, or ConstraintSet with different layouts.
Easiest one is to use motionLayout with different to layouts and constraintSets to change from one layout to another on button click. You can change between layouts with
val constraintSet = ConstraintSet()
constraintSet.clone(this, R.layout.layout_collapsed)
val transition = ChangeBounds()
transition.interpolator = AccelerateInterpolator(1.0f)
transition.setDuration(300)
TransitionManager.beginDelayedTransition(YOUR_VIEW, transition)
constraintSet.applyTo(YOUR_VIEW)
Expansion/collapse animation in gif with using Transitions that changes direction of button with rotating x, and expand/collapse setting item visibility and starting TransitionManager.beginDelayed transition
RotateX.kt
class RotateX : Transition {
#Keep
constructor() : super()
#Keep
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
override fun getTransitionProperties(): Array<String> {
return TRANSITION_PROPERTIES
}
override fun captureStartValues(transitionValues: TransitionValues) {
captureValues(transitionValues)
}
override fun captureEndValues(transitionValues: TransitionValues) {
captureValues(transitionValues)
}
override fun createAnimator(
sceneRoot: ViewGroup,
startValues: TransitionValues?,
endValues: TransitionValues?
): Animator? {
if (startValues == null || endValues == null) return null
val startRotation = startValues.values[PROP_ROTATION] as Float
val endRotation = endValues.values[PROP_ROTATION] as Float
if (startRotation == endRotation) return null
val view = endValues.view
// ensure the pivot is set
view.pivotX = view.width / 2f
view.pivotY = view.height / 2f
return ObjectAnimator.ofFloat(view, View.ROTATION_X, startRotation, endRotation)
}
private fun captureValues(transitionValues: TransitionValues) {
val view = transitionValues.view
if (view == null || view.width <= 0 || view.height <= 0) return
transitionValues.values[PROP_ROTATION] = view.rotationX
}
companion object {
private const val PROP_ROTATION = "iosched:rotate:rotation"
private val TRANSITION_PROPERTIES = arrayOf(PROP_ROTATION)
}
}
create xml file that targets expand button
<?xml version="1.0" encoding="utf-8"?>
<transitionSet
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:interpolator/fast_out_slow_in">
<transition class="com.smarttoolfactory.tutorial3_1transitions.transition.RotateX">
<targets>
<target android:targetId="#id/ivExpand" />
</targets>
</transition>
<autoTransition android:duration="200" />
</transitionSet>
My layout to be expanded or collapsed
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<com.google.android.material.card.MaterialCardView
android:id="#+id/cardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="4dp"
android:layout_marginVertical="2dp"
android:clickable="true"
android:focusable="true"
android:transitionName="#string/transition_card_view"
app:cardCornerRadius="0dp"
app:cardElevation="0dp"
app:cardPreventCornerOverlap="false">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/ivAvatar"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="#drawable/avatar_1_raster" />
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/ivExpand"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:padding="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ic_baseline_expand_more_24" />
<TextView
android:id="#+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="6dp"
android:text="Some Title"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintStart_toEndOf="#+id/ivAvatar"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tvDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="?android:textColorSecondary"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="#+id/tvTitle"
app:layout_constraintTop_toBottomOf="#id/tvTitle"
tools:text="Tuesday 7pm" />
<TextView
android:id="#+id/tvBody"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:ellipsize="end"
android:lines="1"
android:text="#string/bacon_ipsum_short"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="#+id/ivAvatar"
app:layout_constraintTop_toBottomOf="#id/tvDate" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:orientation="horizontal"
android:overScrollMode="never"
android:visibility="gone"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tvBody"
tools:listitem="#layout/item_image_destination" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</layout>
Change visibility of items to collapse or expand with
private fun setUpExpandedStatus() {
if (isExpanded) {
binding.recyclerView.visibility = View.VISIBLE
binding.ivExpand.rotationX = 180f
} else {
binding.recyclerView.visibility = View.GONE
binding.ivExpand.rotationX = 0f
}
}
Start animation
val parent = (itemView.parent as? ViewGroup)
val transition = TransitionInflater.from(itemView.context)
.inflateTransition(R.transition.icon_expand_toggle)
TransitionManager.beginDelayedTransition(parent, transition)
isExpanded = !isExpanded
setUpExpandedStatus()
I created animation and transitions samples including the one on the gif, you can check them out there.
I have a RecyclerView with a list of names being pulled from a firebase realtime database, as well with phone numbers, emails and addresses. I have created a layout for the cards shown in RecyclerView. I want them to only display the name and image until clicked. Once clicked they expand and show the phone number, email and address. I have done all this but the final problem I am facing is with setVisibility for the RelativeLayout inside the layout.xml for RecyclerView, since it's a different xml from the one that belongs to the activity my app keeps crashing. I have tried multiple solutions for problems similar to mine but I could never find someone with the same problem that I was facing.
Now if I use this code:
mUserInfoLayout = (RelativeLayout) findViewById(R.id.user_additional_info_layout);
mUserInfoLayout.setVisibility(View.INVISIBLE);
I get this error
Attempt to invoke virtual method 'void android.widget.RelativeLayout.setVisibility(int)' on a null object reference
However If I use the code provided below nothing happens the Layout stays visible.
My MainActivity.java OnCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAuth = FirebaseAuth.getInstance();
//Firebase
mUserDatabase = FirebaseDatabase.getInstance().getReference().child("Users");
mUserDatabase.keepSynced(true);
//mUserSingleMainLayout = (RelativeLayout) findViewById(R.id.user_single_main_layout);
mUsersList = (RecyclerView) findViewById(R.id.users_list);
mUsersList.setHasFixedSize(true);
mUsersList.setLayoutManager(new LinearLayoutManager(this));
View usersingleView = getLayoutInflater().inflate(R.layout.users_single_layout, null);
mUserInfoLayout = (RelativeLayout) usersingleView.findViewById(R.id.user_additional_info_layout);
mUserInfoLayout.setVisibility(View.INVISIBLE);
//Buttons
mUserAdd = (FloatingActionButton) findViewById(R.id.user_add_btn);
mUserAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent createuserIntent = new Intent(MainActivity.this, CreateUserActivity.class);
startActivity(createuserIntent);
}
});
}
My activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/user_add_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginEnd="20dp"
android:layout_marginBottom="20dp"
app:fabSize="normal"
app:rippleColor="#color/colorPrimary"
android:src="#drawable/ic_add_white_24dp"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/users_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"/>
</RelativeLayout>
My user_single_layout.xml the layout file used in RecyclerView
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/user_single_image"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="15dp"
android:layout_marginTop="15dp"
android:layout_marginBottom="15dp"
android:src="#drawable/account_circle" />
<TextView
android:id="#+id/user_single_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="100dp"
android:layout_marginTop="20dp"
android:text="#string/display_name_users"
android:textColor="#color/colorBlack"
android:textSize="18sp" />
<RelativeLayout
android:id="#+id/user_additional_info_layout"
android:animateLayoutChanges="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/user_single_name"
android:layout_marginTop="10dp"
android:layout_alignParentStart="true"
android:layout_marginStart="100dp">
<ImageView
android:id="#+id/user_phone_image"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentStart="true"
android:layout_alignTop="#+id/user_single_phone"
android:src="#drawable/ic_phone_black_24dp"/>
<ImageView
android:id="#+id/user_email_image"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentStart="true"
android:layout_alignTop="#+id/user_single_email"
android:layout_below="#+id/user_phone_image"
android:src="#drawable/ic_email_black_24dp"/>
<ImageView
android:id="#+id/user_address_image"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentStart="true"
android:layout_alignTop="#+id/user_single_address"
android:src="#drawable/ic_map_marker_black_24dp" />
<TextView
android:id="#+id/user_single_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/user_phone_image"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:text="Phone" />
<TextView
android:id="#+id/user_single_email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_below="#+id/user_single_phone"
android:layout_toRightOf="#+id/user_email_image"
android:layout_marginTop="10dp"
android:text="Email" />
<TextView
android:id="#+id/user_single_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:layout_below="#+id/user_single_email"
android:layout_toRightOf="#id/user_address_image"
android:text="Address" />
</RelativeLayout>
</RelativeLayout>
In the user_single_layout.xml I want to make the "#+id/user_additional_info_layout" RelativeLayout invisible programatically inside MainActivity.java
Edit
My answer is focused on the Fragment lifecycle. The Activity lifecycle is different and does not contain the method I suggested.
The problem is the view that you are trying to access is null. The view is not yet inflated in the onCreate method and is therefore not yet available.
No view related logic should be executed within onCreate().
You need to use the onViewCreated() method to access your views which has the following signature:
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
}
Therefore I suggest you move all of your view related logic into this method.
First, move your code to recyclerView adapter.
Second, make relativeLayout visibility to gone and change it to linearLayout.
Third, use this code for expanding it.
private fun animateView(
view: View,
duration: Long,
initialHeight: Int,
targetHeight: Int,
onAnimationEnd: () -> Unit = {}
) {
view.apply {
val animator = ValueAnimator.ofInt(initialHeight, targetHeight)
animator.addUpdateListener {
layoutParams.height = it.animatedValue as Int
requestLayout()
if (it.animatedValue as Int > 2) {
//Make the view visible in java
//yourview.setVisibility(View.Visible)
show()
}
}
animator.addListener(object : Animator.AnimatorListener {
override fun onAnimationEnd(animation: Animator) {
layoutParams.height = targetHeight
onAnimationEnd.invoke()
}
override fun onAnimationStart(animation: Animator) {
}
override fun onAnimationCancel(animation: Animator) {}
override fun onAnimationRepeat(animation: Animator) {}
})
animator.interpolator = AccelerateDecelerateInterpolator()
animator.duration = duration
animator.start()
}
}
fun View.expandAnimation(duration: Long) {
measure(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
val initialHeight = 0
val targetHeight = measuredHeight
layoutParams.height = 0
animateView(this, duration, initialHeight, targetHeight)
}
fun View.collapseAnimation(duration: Long) {
val initialHeight = measuredHeight
val targetHeight = 0
animateView(this, duration, initialHeight, targetHeight) {
hide()
}
}
fun View.hide() {
this.apply {
visibility = View.GONE
}
}
fun View.show() {
this.apply {
visibility = View.VISIBLE
}
}
You can easily convert this code to java
sry I don't have time to convert it myself
I want to implement a little chat app and therefore i need a send button which clears the input field and sends the message (for now just adding an element to a recycler view). I've implemented the OnClickListener Interface and added my fragment as Listener to the button but somehow onClick is never called.
class MainFragment : Fragment(), View.OnClickListener {
private val messageList = ArrayList<MessageData>()
val interactor = MainInteractor()
private lateinit var viewModel: MainViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
initRecycler()
InputButton.setOnClickListener(this)
return inflater.inflate(R.layout.main_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
}
private fun initRecycler(){
messageList.add(MessageData("Das ist die erste Nachricht", 0))
messageList.add(MessageData("Das ist die zweite Nachricht", 1))
messageList.add(MessageData("Das ist die dritte Nachricht,\nwelche über 2 Zeilen geht", 0))
val recyclerView: RecyclerView = recycler
val manager: RecyclerView.LayoutManager = LinearLayoutManager(requireActivity())
val adapter: RecyclerView.Adapter<*> = MessageAdapter(messageList)
recyclerView.layoutManager = manager
recyclerView.adapter = adapter
}
private fun sendMessage(){
messageList.add(MessageData(input_field.text.toString(), 0))
input_field.setText("")
}
override fun onClick(v: View?) {
Toast.makeText(context,"Button Pressed",Toast.LENGTH_SHORT).show()
sendMessage()
}
}
Thats the code from my Fragment and my layout looks like this
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/gray"
tools:context=".ui.main.MainFragment">
<TextView
android:id="#+id/ueberschrift"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Chat"
android:textColor="#color/yellow"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="5dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:background="#color/yellow"
app:layout_constraintTop_toBottomOf="#+id/ueberschrift"
tools:layout_editor_absoluteX="1dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler"
android:layout_width="match_parent"
android:layout_height="0dp"
android:scrollbars="vertical"
android:layout_marginTop="20dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
app:layout_constraintTop_toBottomOf="#+id/divider"
app:layout_constraintBottom_toTopOf="#+id/textInputLayout">
</androidx.recyclerview.widget.RecyclerView>
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/textInputLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginBottom="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#id/InputButton"
app:layout_constraintBottom_toBottomOf="parent"
tools:layout_editor_absoluteX="1dp"
android:textColorHint="#FFFFFF">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/input_field"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="2"
android:textColor="#FFFFFF"
android:hint="Your Message"
/>
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="#+id/InputButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="20dp"
android:layout_marginStart="10dp"
android:text="Send"
android:textColor="#2E2E2E"
android:background = "#color/yellow"
app:layout_constraintStart_toEndOf="#id/textInputLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#id/textInputLayout"
app:layout_constraintBottom_toBottomOf="#id/textInputLayout"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
This should not be so difficult as this is a basic Android mechanic but I dont have a clue why this isnt working. What am I missing?
Try setting your on click listener this way:
class MainFragment : Fragment(R.layout.main_fragment) {
//...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
InputButton.setOnClickListener {
InputButton.setOnClickListener(this)
sendMessage()
}
}
}
You should notify adapter about data changes:
private fun sendMessage(){
messageList.add(MessageData(input_field.text.toString(), 0))
recycler.adapter.notifyDataSetChanged()
input_field.setText("")
}