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" />
Related
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
if (type=="dialer") {
String timestamp = list.get(position).get(Constants.DATE);
holder.txtTimestamp.setVisibility(View.VISIBLE);
holder.imgDelete.setVisibility(View.GONE);
holder.txtTimestamp.setText(getDate(Long.parseLong(timestamp),"dd/MM/yyyy hh:mm:ss"));
if (Integer.parseInt(callType) == CallLog.Calls.BLOCKED_TYPE)
holder.imgCallType.setImageDrawable(context.getResources().getDrawable(R.drawable.block));
if (Integer.parseInt(callType) == CallLog.Calls.BLOCKED_TYPE)
holder.imgCallType.setImageDrawable(context.getResources().getDrawable(R.drawable.rejected));
if (Integer.parseInt(callType) == CallLog.Calls.OUTGOING_TYPE)
holder.imgCallType.setImageDrawable(context.getResources().getDrawable(R.drawable.outgoing_call));
if (Integer.parseInt(callType) == CallLog.Calls.INCOMING_TYPE)
holder.imgCallType.setImageDrawable(context.getResources().getDrawable(R.drawable.incoming_call));
if (Integer.parseInt(callType) == CallLog.Calls.MISSED_TYPE)
holder.imgCallType.setImageDrawable(context.getResources().getDrawable(R.drawable.missed_call));
if (Integer.parseInt(callType) == CallLog.Calls.ANSWERED_EXTERNALLY_TYPE)
holder.imgCallType.setImageDrawable(context.getResources().getDrawable(R.drawable.call_received));
}else if (type=="contact") {
holder.txtTimestamp.setVisibility(View.GONE);
holder.imgCallType.setVisibility(View.GONE);
holder.imgDelete.setVisibility(View.GONE);
}else if (type=="favourite"){
holder.txtTimestamp.setVisibility(View.GONE);
holder.imgCallType.setVisibility(View.GONE);
}
// listener
Bitmap finalBitmap = imgBitmap;
holder.imgPic.setOnLongClickListener(view -> {
CustomDialog imageDialog = new CustomDialog(activity,R.layout.image_dialog,"","","", finalBitmap);
imageDialog.setCancelable(true);
imageDialog.show();
return false;
});
holder.itemView.setOnLongClickListener(view->{
if (type=="dialer"){
}else if (type=="contact"){
Intent intent = new Intent(context, ContactDetailsActivity.class);
intent.putExtra("id",list.get(position).get(Constants.ID));
context.startActivity(intent);
}else if (type=="favourite"){
Intent intent = new Intent(context, FavouriteContactDetailsActivity.class);
intent.putExtra(Constants.FAVOURITE_ID,list.get(position).get(Constants.FAVOURITE_ID));
intent.putExtra(Constants.ID,list.get(position).get(Constants.ID));
ActivityOptions anim = ActivityOptions.makeSceneTransitionAnimation(activity);
context.startActivity(intent, anim.toBundle());
}
return false;
});
holder.imgDelete.setOnClickListener(v->{
SqliteFavourite sqliteFavourite = new SqliteFavourite(context.getApplicationContext());
boolean check = sqliteFavourite.deleteData("",list.get(position).get(Constants.ID));
if (check)
Snackbar.make(v,"Successfully deleted",Snackbar.LENGTH_SHORT).show();
else Snackbar.make(v,"Error occurred when deleting",Snackbar.LENGTH_SHORT).show();
});
holder.itemView.setOnClickListener(view->{
call(activity,phoneNumber);
});
I was using these code in an adapter.
#Override
public int getItemCount() {
return list.size();
}
#Override
public int getItemViewType(int position) {
return position;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView txtContactName,txtContactNumber,txtTimestamp;
ImageView imgPic,imgCallType,imgDelete;
ConstraintLayout contactItem;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
txtContactName = itemView.findViewById(R.id.txtName);
txtContactNumber = itemView.findViewById(R.id.txtContactNumber);
txtTimestamp = itemView.findViewById(R.id.txtTimestamp);
imgPic = itemView.findViewById(R.id.imgContact);
imgCallType = itemView.findViewById(R.id.imgCallType);
contactItem = itemView.findViewById(R.id.contactItem);
imgDelete = itemView.findViewById(R.id.imgDeleteContact);
}
}
Whenever I am clicking on first or second item then I can hear the clickListener. But when I click on 3rd 4th or higher item then I can't hear the clickListener. Even I had set a selector there but the selector is only working for 1st and 2nd
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/contactItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/selector"
android:clickable="true">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/imgContact"
android:layout_width="50dp"
android:layout_height="0dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:src="#drawable/user_profile"
app:civ_border_color="#FF000000"
app:civ_border_width="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="SpeakableTextPresentCheck" />
<TextView
android:id="#+id/txtName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="Name"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="#+id/txtContactNumber"
app:layout_constraintEnd_toStartOf="#+id/imgCallType"
app:layout_constraintStart_toEndOf="#+id/imgContact"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/txtContactNumber"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="Contact Number"
app:layout_constraintBottom_toTopOf="#id/txtTimestamp"
app:layout_constraintEnd_toStartOf="#+id/imgCallType"
app:layout_constraintStart_toEndOf="#+id/imgContact"
app:layout_constraintTop_toBottomOf="#+id/txtName" />
<TextView
android:id="#+id/txtTimestamp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="TextView"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="#+id/txtContactNumber"
app:layout_constraintStart_toEndOf="#+id/imgContact"
app:layout_constraintTop_toBottomOf="#id/txtContactNumber" />
<ImageView
android:id="#+id/imgCallType"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="#drawable/call_received"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/imgDeleteContact"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/selector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#android:drawable/ic_menu_delete" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
When I scroll down then I can hear the listener but whenever I am on top at that layout then I can't access the listener in 3rd or more. Why it's happening? I am not getting any error in logcat. Although I can't click on some items why? I had tried to use holder.contactItem.setOn.... but it wasn't working also.
When I scroll down I can listen the click. But whenever I am at top I can't listen. But I wonder I can click on Image. I meant holder.imgPic.setOnLongClickListener......
I have set onTouchListener to itemView but it's working. It's only not working for onCLickListener and onLongClickListener (As I said earlier it's working when I scroll down).
I have tried
android:focusable="false"
android:clickable="false"
android:longClickable="false"
although I was facing the same issue. I had used them in Constraint Layout which I declared as contactItem. Then I had tried holder.contactItem instead of holder.itemView
I get a null pointer exception when doing this
i am trying to set the value of total in BindViewHolder to my amount textview in my cart activity.
is there any way i can the total value to the amount textview? Either from the bindViewHolder or from On Create function?
i have tried severval methods including setText and findviewbyId but none seems to work , i still get the error in the logcat either Null Pointer Exception or attempt to invoke virtual method on a null reference.......
var CartItems = ArrayList<CartItemsModel>()
val adapter = CartAdapter(CartItems)
cart_recyclerview.adapter = adapter
cart_recyclerview.layoutManager = LinearLayoutManager(this)
CoroutineScope(Dispatchers.IO).launch {
try {
val snapshotquery = Firebase.firestore.collection("Profiles").document("User").collection("Cart Items").get().await()
for (document in snapshotquery.documents) {
val cartitems = document.toObject<CartItemsModel>()
withContext(Dispatchers.Main){
CartItems.add(cartitems!!)
Toast.makeText(this#cart_activity, "Suu" ,Toast.LENGTH_SHORT).show()
adapter.notifyDataSetChanged()
}
}
}catch (e: Exception){
withContext(Dispatchers.Main){
Toast.makeText(this#cart_activity, e.message, Toast.LENGTH_SHORT).show()
}
}
}
class CartAdapter(
var cartitems : List<CartItemsModel>
): RecyclerView.Adapter<CartAdapter.CartViewHolder>(){
inner class CartViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CartViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.cart_recycler_ui, parent, false)
return CartViewHolder(view)
}
override fun getItemCount(): Int {
return cartitems.size
}
override fun onBindViewHolder(holder: CartViewHolder, position: Int) {
holder.itemView.apply {
name_of_item_in_cart.text = cartitems[position].Name
cart_item_price.text = "$"+cartitems[position].Price
cart_item_quantity.text = cartitems[position].Quantity+"X"
Glide.with(this).load(cartitems[position].Image.toString()).into(img_of_item_in_cart)
if (cartitems[position].Price !=null){
val a = cartitems[position].Price!!.toDouble()
val b = cartitems[position].Quantity!!.toDouble()
val total : Double = a * b
//total is the value I want to set to my cart activity's textview
}
}
}
}
class CartItemsModel {
var Name:String? =null
var Image:String?=null
var Price:String?=null
var Quantity:String?=null
constructor()
constructor(Name:String,Image:String,Price:String,Quantity:String) {
this.Name = Name
this.Image = Image
this.Price = Price
this.Quantity = Quantity
}
}
//My cart Activity
<?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="match_parent"
tools:context=".cart_activity">
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.15" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.05" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/artifika"
android:text="My Order"
android:textColor="#color/black"
android:textSize="30sp"
app:layout_constraintLeft_toLeftOf="#id/guideline10"
app:layout_constraintTop_toTopOf="#id/guideline9" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.90" />
<TextView
android:id="#+id/back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:fontFamily="#font/alegreya"
android:text="Shop"
android:textColor="#color/black"
android:textSize="18sp"
app:layout_constraintLeft_toLeftOf="#id/guideline10"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/cart_recyclerview"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="48dp"
app:layout_constraintBottom_toTopOf="#+id/textView4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/textView2" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.70" />
<TextView
android:id="#+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/artifika"
android:text="Total"
android:textColor="#color/black"
android:textSize="30sp"
app:layout_constraintLeft_toLeftOf="#id/guideline10"
app:layout_constraintTop_toBottomOf="#id/guideline12" />
<TextView
android:id="#+id/amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/artifika"
android:textColor="#color/black"
android:textSize="30sp"
app:layout_constraintRight_toLeftOf="#id/guideline11"
app:layout_constraintTop_toTopOf="#id/guideline12" />
<Button
android:id="#+id/checkout_button"
style="#style/Theme.Ambergris"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="#font/aref_ruqaa"
android:text="Checkout"
android:textAllCaps="false"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="#id/guideline13"
app:layout_constraintLeft_toLeftOf="#id/guideline10"
app:layout_constraintRight_toLeftOf="#id/guideline11"
app:layout_constraintTop_toBottomOf="#id/amount" />
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline13"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="1" />
</androidx.constraintlayout.widget.ConstraintLayout>
In CartAdapter pass amount textview as parameter like this
class CartAdapter(
var cartitems : List<CartItemsModel>, var txtAmount: TextView
): RecyclerView.Adapter<CartAdapter.CartViewHolder>(){........
and then set it in onBindViewHolder as below
txtAmount.text = total
and while attaching adapter to recycler in cart activity pass your textview id like
val adapter = CartAdapter(CartItems,amount)
you can pass context from cart activity to adapter class like-
val adapter = CartAdapter(context,CartItems)
create a function setAmount
fun setAmount(var total){
txtAmount.text = total
}
in adapter class you can receive it like
class CartAdapter(
var context: Context var cartitems : List<CartItemsModel>
): RecyclerView.Adapter<CartAdapter.CartViewHolder>(){........}
call the function in view holder
override fun onBindViewHolder(holder: CartViewHolder, position: Int) {
holder.itemView.apply {
if (cartitems[position].Price !=null){
val a = cartitems[position].Price!!.toDouble()
val b = cartitems[position].Quantity!!.toDouble()
val total : Double = a * b
(context as CartActivity).setAmount(total)
//total is the value will set to in cart activity's textview
}
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 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("")
}