follow unfollow feed with observer pattern android app - android

I am building an android app which has follow and unfollow feature. I have 3 pages inside ViewPager in main home. Feed consist of post of the users based on interest.
For example, user A follows user B, that posts the article in 3 different interest food, travel and tech. In this case, user A will be able to see his all the post in the 3 different places. What I want is that if user A who follows B unfollow the user B from any of the page it will just get removed from all the pages and refresh the feed.
I want to observe that follow and unfollow event based on the user action and refresh the feed.
How to build observer for this pattern. I am open to use anything expect BroadcastReceiver.
feed_item.xml
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
android:id="#+id/parent_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="6dp"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
app:cardCornerRadius="4dp"
app:cardElevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="6dp"
android:orientation="horizontal">
<com.facebook.drawee.view.SimpleDraweeView
android:id="#+id/profilePicture"
android:layout_width="40dp"
android:layout_height="40dp"
fresco:roundedCornerRadius="#dimen/feed_rect_card_radius" />
<LinearLayout
android:id="#+id/linearlayout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="8dp"
android:orientation="vertical">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:maxLines="1"
android:textColor="#color/darkTextColor" />
<TextView
android:id="#+id/data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:fontFamily="#font/noto_sans_bold"
android:textColor="#747474"
android:textSize="10sp" />
</LinearLayout>
</LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="#+id/followBtn"
style="#style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center"
android:layout_marginEnd="32dp"
android:fontFamily="#font/noto_sans_bold"
android:gravity="center"
android:text="#string/follow"
android:textColor="#color/green"
android:textSize="10sp"
app:rippleColor="#color/green"
app:strokeColor="#color/green" />
<ImageView
android:id="#+id/pop_up_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|top"
android:layout_marginTop="4dp"
android:contentDescription="#null"
android:padding="2dp"
android:src="#drawable/ic_more_dark" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="4dp"
android:paddingTop="8dp"
android:paddingEnd="4dp"
android:paddingBottom="8dp">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp">
<com.facebook.drawee.view.SimpleDraweeView
android:id="#+id/image"
android:layout_width="124dp"
android:layout_height="80dp"
fresco:roundedCornerRadius="#dimen/feed_rect_card_radius" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="4dp"
android:contentDescription="#null"
android:src="#drawable/ic_play_circle_feature" />
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="#dimen/item_offset">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/post_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:ellipsize="end"
android:fontFamily="#font/noto_sans_bold"
android:gravity="start|top"
android:maxLines="2"
android:textColor="#color/darkTextColor"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="#+id/post_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:fontFamily="#font/noto_sans"
android:gravity="start"
android:lineSpacingExtra="4dp"
android:maxLines="2"
android:padding="2dp"
android:textSize="12sp"
android:visibility="gone" />
</LinearLayout>
<LinearLayout
android:id="#+id/categoryLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="horizontal" />
<FrameLayout
android:id="#+id/whatsAppShare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:foreground="?attr/selectableItemBackground"
android:padding="4dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="#null"
android:src="#drawable/ic_whatsapp_fill" />
</FrameLayout>
</FrameLayout>
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
FeedAdapter
class FeedAdapter(private val mContext: Context, val fg: FragmentManager, val nodes: ArrayList<Feed.Item>, val tagId: Int) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var showLoader: Boolean = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ViewTypes.FEED -> FeedItemVH(LayoutInflater.from(mContext).inflate(R.layout.feed_item, parent, false))
else -> FooterViewHolder(LayoutInflater.from(mContext).inflate(R.layout.layout_footer, parent, false))
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is FeedItemVH -> feedItemView(holder, nodes[position].fragments().feedItem())
else -> {
if (showLoader) (holder as FooterViewHolder).itemView.footerLoader.visibility = View.VISIBLE
else (holder as FooterViewHolder).itemView.footerLoader.visibility = View.GONE
}
}
}
private fun feedItemView(holder: FeedItemVH, feed: FeedItem) {
holder.followBtn.setOnClickListener {
//API call to follow/unfollow user and broadcast the result.
}
}
override fun getItemCount(): Int {
return when (nodes.size) {
0 -> 0
else -> nodes.size + 1
}
}
override fun getItemViewType(position: Int): Int {
return when {
position != 0 && position == itemCount - 1 -> ViewTypes.LOADER
else -> {
ViewTypes.FEED
}
}
}
fun showLoader(status: Boolean) {
showLoader = status
Handler().post { this.notifyDataSetChanged() }
}
interface ViewTypes {
companion object {
const val FEED = 1
const val LOADER = 2
}
}
}
Any type of help would be appreciated. Thanks!

Related

Problem in some views in items row of recyclerview "not showing like design preview"

I trying to practice some android lessons that contains recyclerview topic, currently I succeed to implement all api and response but there's one problem with my item_article_preview.xml.
The title and description of news doesn't shows in emulator like it's in design preview
After running the app
here's my xml row
<?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:orientation="vertical"
android:padding="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="2"
android:orientation="horizontal">
<ImageView
android:id="#+id/ivArticleImage"
android:layout_width="0dp"
android:layout_height="90dp"
android:layout_weight="0.8"
android:scaleType="centerCrop" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.2"
android:orientation="vertical">
<TextView
android:id="#+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:ellipsize="end"
android:maxLines="2"
android:textColor="#color/black"
android:textSize="15sp"
android:textStyle="bold"
tools:text="TITLE" />
<TextView
android:id="#+id/tvDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:ellipsize="end"
android:maxLines="3"
android:textColor="#color/black"
android:text="DESCRIPTION" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="#+id/tvSource"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="SOURCE"
android:textColor="#android:color/black" />
<TextView
android:id="#+id/tvPublishedAt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="PUBLISHED AT"
android:textColor="#android:color/black"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvSource" />
</LinearLayout>
I tried other row design but it didn't show the title and descreption at all
<?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="8dp">
<ImageView
android:id="#+id/ivArticleImage"
android:layout_width="160dp"
android:layout_height="90dp"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tvSource"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="SOURCE"
android:textColor="#android:color/black"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/ivArticleImage" />
<TextView
android:id="#+id/tvTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:ellipsize="end"
android:maxLines="3"
android:text="TITLE"
android:textColor="#android:color/black"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toRightOf="#+id/ivArticleImage"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tvDescription"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:ellipsize="end"
android:maxLines="5"
android:text="DESCRIPTION"
android:textColor="#android:color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/ivArticleImage"
app:layout_constraintTop_toBottomOf="#+id/tvTitle" />
<TextView
android:id="#+id/tvPublishedAt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="PUBLISHED AT"
android:textColor="#android:color/black"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvSource" />
</androidx.constraintlayout.widget.ConstraintLayout>
RecyclerView XML
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvBreakingNews"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="#+id/paginationProgressBar"
style="?attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
android:background="#android:color/transparent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
my adapter class
private const val TAG = "NewsAdapter"
class NewsAdapter : RecyclerView.Adapter<NewsAdapter.ArticleViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
val binding = ItemRowBinding.inflate(LayoutInflater.from(parent.context))
return ArticleViewHolder(binding)
}
override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
val article = differ.currentList[position]
// holder.bind(article)
holder.binding.apply {
Glide.with(this.root).load(article.urlToImage).into(ivArticleImage)
tvSource.text = article.source.name
tvTitle.text = article.title
tvDescription.text = article.description
tvPublishedAt.text = article.publishedAt
this#NewsAdapter.setOnItemClickListener {
onItemClickListener?.let {
it(article)
}
}
}
}
override fun getItemCount(): Int {
return differ.currentList.size
}
inner class ArticleViewHolder( val binding: ItemRowBinding) :
RecyclerView.ViewHolder(binding.root) {
private var onItemClickListener: ((Article) -> Unit)? = null
private fun setOnItemClickListener(listener: (Article) -> Unit) {
onItemClickListener = listener
}
private val diffCallBack = object : DiffUtil.ItemCallback<Article>() {
override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this, diffCallBack)
}
ACTIVITY:
val list : MutableList<Item> = mutableListOf()
list.add(Item("TITLE", "DESCRITION", "ESPN", "2022-08-02T14:32:47Z"))
val rv = findViewById<RecyclerView>(R.id.rvBreakingNews)
rv.layoutManager = LinearLayoutManager(applicationContext)
rv.adapter = RvAdapter(list)
ADAPTER
class RvAdapter(private var list : List<Item>) : RecyclerView.Adapter<RvAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.title.setText(list[position].getTitle())
holder.desc.setText(list[position].getDescription())
holder.source.setText(list[position].getSource())
holder.published.setText(list[position].getPublished())
}
// return the number of the items in the list
override fun getItemCount(): Int {
return list.size
}
// Holds the views for adding it to image and text
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val title : TextView = itemView.findViewById(R.id.tvTitle)
val desc : TextView = itemView.findViewById(R.id.tvDescription)
val source : TextView = itemView.findViewById(R.id.tvSource)
val published : TextView = itemView.findViewById(R.id.tvPublishedAt)
val imageView : ImageView = itemView.findViewById(R.id.ivArticleImage)
}
}
ACTIVITY XML (SAME AS YOURS):
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="#+id/paginationProgressBar"
style="?attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
android:background="#android:color/transparent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
ITEM XML(SAME AS YOURS):
<?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:orientation="vertical"
android:padding="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="2"
android:orientation="horizontal">
<ImageView
android:id="#+id/ivArticleImage"
android:layout_width="0dp"
android:layout_height="90dp"
android:layout_weight="0.8"
android:background="#android:drawable/sym_def_app_icon"
android:scaleType="centerCrop" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.2"
android:orientation="vertical">
<TextView
android:id="#+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:ellipsize="end"
android:maxLines="2"
android:textColor="#color/black"
android:textSize="15sp"
android:textStyle="bold"
tools:text="TITLE" />
<TextView
android:id="#+id/tvDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:ellipsize="end"
android:maxLines="3"
android:textColor="#color/black"
android:text="DESCRIPTION" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="#+id/tvSource"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="SOURCE"
android:textColor="#android:color/black" />
<TextView
android:id="#+id/tvPublishedAt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="PUBLISHED AT"
android:textColor="#android:color/black"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvSource" />
</LinearLayout>
I found the problem causes this spilled of screen, here in this line
val binding = ItemRowBinding.inflate(LayoutInflater.from(parent.context))
you just inflated the inflater of a parent but there are two parameters is missing,
the viewGroup which it "parent and attachToRoot = false
edit your onCreateViewHolder like this
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ItemRowBinding.inflate(inflater,parent,false)
return ArticleViewHolder(binding)
}

Implement binding into RecycleView Adapter Android Kotlin

So hello, I have a little problem here.
I can't implement my binding properly into adapter for RecycleView. I need it to display my products in cart as you can see in the code below. I am a beginner with adapter, so please help me.
CartItemsListAdapter.kt *here is where I want to implement binding*
class CartItemsListAdapter(
private val context: Context,
private var list: ArrayList<CartItem>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
RecyclerView.ViewHolder {
return MyViewHolder(
LayoutInflater.from(context).inflate(
R.layout.item_cart_layout,
parent,
false
)
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val model = list[position]
if (holder is MyViewHolder) {
Glide.with(context)
.load(model.image)
.placeholder(R.drawable.ic_launcher)
.into(/*binding.ivCartItemImage*/)
//binding.tvCartItemPrice.text = model.price
//binding.tvCartItemTitle.text = model.title
}
}
override fun getItemCount(): Int {
return list.size
}
private class MyViewHolder(view: View) : RecyclerView.ViewHolder(view)
}
activity_cart_list.xml *xml file for reference and from where I want to take those bindings*
<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=".ui.activities.CartListActivity">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar_cart_list_activity"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="?attr/colorSecondary">
<ImageView
android:id="#+id/arrow_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/ic_arrow_left"
android:hapticFeedbackEnabled="true"
android:layout_marginTop="16sp"
android:padding="24dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_gravity="top"
android:contentDescription="#string/back_button" />
<com.example.trieskask.utils.OswaldBold
android:id="#+id/tv_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="My cart"
android:textSize="26sp"
android:elevation="3dp"
android:textStyle="bold" />
</androidx.appcompat.widget.Toolbar>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_cart_items_list"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="#id/ll_checkout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/toolbar_cart_list_activity" />
<com.example.trieskask.utils.OswaldRegular
android:id="#+id/tv_no_cart_item_found"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="No cart item found!"
android:textAlignment="center"
app:layout_constraintBottom_toTopOf="#id/ll_checkout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/toolbar_cart_list_activity" />
<LinearLayout
android:id="#+id/ll_checkout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSecondary"
android:elevation="4dp"
android:orientation="vertical"
android:padding="16dp"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.example.trieskask.utils.OswaldLight
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Subtotal:" />
<com.example.trieskask.utils.OswaldLight
android:id="#+id/tv_sub_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="center"
tools:text="$100" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.example.trieskask.utils.OswaldLight
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Shipping charge:" />
<com.example.trieskask.utils.OswaldLight
android:id="#+id/tv_shipping_charge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="center"
tools:text="$10" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.example.trieskask.utils.OswaldBold
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Total Amount" />
<com.example.trieskask.utils.OswaldBold
android:id="#+id/tv_total_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="center"
tools:text="$110" />
</LinearLayout>
<com.example.trieskask.utils.OswaldButton
android:id="#+id/btn_checkout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="16dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="16dp"
android:background="#drawable/btn_ripple_effect"
android:foreground="?attr/selectableItemBackground"
android:gravity="center"
android:text="Checkoutt"
android:textColor="#android:color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Thanks for any kind of help
You can refactor your MyViewHolder class to require an ActivityCartListBinding as a constructor argument. Then your onCreateViewHolder function will look like:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ActivityCartListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return MyViewHolder(binding)
}
And finally your onBindViewHolder:
override fun onBindViewHolder(
holder: RecyclerView.ViewHolder,
position: Int
) {
val model = list[position]
if (holder is MyViewHolder) {
Glide.with(context)
.load(model.image)
.placeholder(R.drawable.ic_launcher)
.into(/*binding.ivCartItemImage*/)
holder.getBinding().tvCartItemPrice.text = model.price
holder.getBinding().tvCartItemTitle.text = model.title
}
}
View Holder
private class MyViewHolder(val binding: ActivityCartListBinding) : RecyclerView.ViewHolder(binding.root)
This should solve your issue.

How to test(tdd) an element inside child recycler view?

add to cart errorI've used a recycler view inside another recycler view. While using test-driven development, I was trying to test the click functionality of add to cart button code as follows:
MenuDishAdapter- child recycler view
MenuAdapter- parent recycler view
class MenuAdapter(private val context: Context, val menuList:List<MenuData>, val menuActivity: MenuActivity):RecyclerView.Adapter<MenuAdapter.MenuViewHolder>() {
class MenuViewHolder(private val itemBinding:RvDishGroupBinding):RecyclerView.ViewHolder(itemBinding.root) {
val dishGroupBinding:RvDishGroupBinding = itemBinding
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MenuViewHolder = MenuViewHolder(
RvDishGroupBinding.inflate(LayoutInflater.from(parent.context), parent, false))
#SuppressLint("CutPasteId")
override fun onBindViewHolder(holder: MenuViewHolder, position: Int) {
val getPos= menuList[position]
holder.dishGroupBinding.dishCatgTypeMtv.text=getPos.categoryType
val adapter = MenuDishAdapter(context, menuList[position].categoryDish, menuActivity, )
holder.dishGroupBinding.dishLl.adapter= adapter
/*Logger.i("Menu list size ${menuList.size}")
Logger.i("Menu list $menuList")*/
if(position==menuList.size-1)
{
holder.dishGroupBinding.rvGroupSeparatorVw.visibility= View.GONE
}
}
override fun getItemCount(): Int = menuList.size
}
class MenuDishAdapter(
private val context: Context,
val menuList: List<DishData>,
val menuActivity: MenuActivity
) :
RecyclerView.Adapter<MenuDishAdapter.MenuDishViewHolder>() {
class MenuDishViewHolder(private val dishItem: RvDishItemBinding) :
RecyclerView.ViewHolder(dishItem.root) {
val dishItemBinding = dishItem
}
var isFavourite: Boolean = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MenuDishViewHolder =
MenuDishViewHolder(
RvDishItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
)
override fun onBindViewHolder(holder: MenuDishViewHolder, position: Int) {
val getPos= menuList[position]
Glide.with(context).load(getPos.dishImage).placeholder(R.drawable.img_dessert).into( holder.dishItemBinding.rvDishImgIv)
holder.dishItemBinding.rvDishNameMtv.text= getPos.dishName
if(getPos.dishDescription.isNullOrEmpty())
{
holder.dishItemBinding.rvDishDescriptionMtv.visibility=View.GONE
}
else
{
holder.dishItemBinding.rvDishDescriptionMtv.text= getPos.dishDescription
}
holder.dishItemBinding.rvDishPriceMtv.text= "$"+ getPos.dishPrice
if(!getPos.isVeg)
{
holder.dishItemBinding.rvDishTypeIv.backgroundTintList=
ContextCompat.getColorStateList(menuActivity, R.color.red)
}
holder.dishItemBinding.rvDishCustomizationMtv.text= context.getString(R.string.your_customisations_are)+" Radish, Mushroom, carrots, turnip, radish"
holder.dishItemBinding.rvDishFavMarkIb.setOnClickListener {
if(isFavourite)
{
holder.dishItemBinding.rvDishFavMarkIb.setBackgroundResource(R.drawable.ic_unfav)
Toast.makeText(context, "${getPos.dishName} removed from Favourite. ", Toast.LENGTH_SHORT).show()
notifyDataSetChanged()
isFavourite= false
}
else
{
holder.dishItemBinding.rvDishFavMarkIb.setBackgroundResource(R.drawable.ic_fav)
Toast.makeText(context, "${getPos.dishName} marked Favourite. ", Toast.LENGTH_SHORT).show()
notifyDataSetChanged()
isFavourite=true
}
}
holder.dishItemBinding.rvAddToCartBtn.setOnClickListener {
Utils.printShortToast(context, "${getPos.dishName} added to the cart")
}
holder.dishItemBinding.rvDishCustomizeBtn.setOnClickListener {
Utils.printShortToast(context, "${getPos.dishName} customised")
}
}
override fun getItemCount(): Int = menuList.size
}
XML for MenuDishAdapter
<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="133dp"
android:layout_marginStart="6dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="6dp"
android:id="#+id/rv_dish_item_ll">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/detail_parent_cl"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:id="#+id/rv_dish_img_cv"
android:layout_width="109dp"
android:layout_height="104dp"
android:elevation="5dp"
app:cardCornerRadius="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/rv_dish_img_iv"
android:layout_width="109dp"
android:layout_height="104dp"
android:scaleType="fitXY"
tools:src="#drawable/img_fav_2" />
</androidx.cardview.widget.CardView>
<androidx.appcompat.widget.LinearLayoutCompat
android:id="#+id/dish_details_ll"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="0dp"
android:orientation="vertical"
android:weightSum="5"
app:layout_constraintBottom_toBottomOf="#id/rv_dish_img_cv"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/rv_dish_img_cv"
app:layout_constraintTop_toTopOf="#id/rv_dish_img_cv">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/dish_name_cl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<com.google.android.material.textview.MaterialTextView
android:id="#+id/rv_dish_name_mtv"
style="#style/TextAppearance.MdcTypographyStyles.Body22"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:layout_marginEnd="8dp"
android:ellipsize="end"
android:gravity="start"
android:maxLines="1"
android:textColor="#color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#id/rv_dish_type_iv"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Masala Noodles" />
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/rv_dish_type_iv"
android:layout_width="21dp"
android:layout_height="18dp"
android:layout_gravity="end"
android:background="#drawable/ic_veg_dish"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/detail_middle_cl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="2"
android:orientation="horizontal">
<LinearLayout
android:id="#+id/text_ll"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#id/rv_dish_fav_mark_ib"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textview.MaterialTextView
android:id="#+id/rv_dish_description__mtv"
style="#style/TextAppearance.MdcTypographyStyles.Body12"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="2"
android:layout_marginEnd="2dp"
android:layout_marginStart="0dp"
android:textAlignment="textStart"
android:textColor="#color/black"
tools:text="#string/description" />
<com.google.android.material.textview.MaterialTextView
android:id="#+id/rv_dish_price_mtv"
style="#style/TextAppearance.MdcTypographyStyles.Body22"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:textAlignment="textStart"
tools:text="$10.5" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageButton
android:id="#+id/rv_dish_fav_mark_ib"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:clickable="true"
android:elevation="5dp"
android:focusable="true"
android:paddingStart="10dp"
android:paddingTop="0dp"
android:paddingEnd="0dp"
android:paddingBottom="5dp"
android:background="#drawable/ic_unfav"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/buttons_cl"
android:layout_width="match_parent"
android:layout_height="23dp"
android:layout_marginTop="2dp"
android:paddingBottom="1dp"
android:paddingTop="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatButton
android:id="#+id/rv_add_to_cart_btn"
style="#style/TextAppearance.MdcTypographyStyles.Button1"
android:layout_width="109dp"
android:layout_height="0dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="2dp"
android:background="#drawable/bg_button"
android:backgroundTint="#color/primaryColor"
android:drawableStart="#drawable/ic_button_cart"
android:drawablePadding="0dp"
android:focusable="true"
android:padding="2dp"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="#string/add_to_cart"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatButton
android:id="#+id/rv_dish_customize_btn"
style="#style/TextAppearance.MdcTypographyStyles.Button1"
android:layout_width="109dp"
android:layout_height="0dp"
android:layout_marginStart="2dp"
android:layout_marginEnd="0dp"
android:background="#drawable/bg_button"
android:backgroundTint="#color/black"
android:focusable="true"
android:padding="2dp"
android:text="#string/customize"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
<com.google.android.material.textview.MaterialTextView
android:id="#+id/rv_dish_customization_mtv"
style="#style/TextAppearance.MdcTypographyStyles.Body12"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="3dp"
android:ellipsize="end"
android:maxLines="1"
android:text="#string/your_customisations_are"
android:textAlignment="textStart"
android:textColor="#color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="#id/dish_details_ll"
app:layout_constraintStart_toStartOf="#id/rv_dish_img_cv"
app:layout_constraintTop_toBottomOf="#id/rv_dish_img_cv"
tools:text="Your customisations are - Onion, Tomato, Mushroom, cucumber, radish" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
Now while testing the add to cart button the test case is as follows:
**Class name: MenuActivityTest
see code commented in testingMenuList() **
#RunWith(AndroidJUnit4::class)
#LargeTest
class MenuActivityTest {
#get:Rule
var rule = ActivityScenarioRule(MenuActivity::class.java)
//test to check the visibility of the menu screen layout on the device
#Test
fun checkScreenDisplay() {
onView(withId(R.id.menu_cl))
.check(matches(isDisplayed()))
}
#Test
fun testingMenuList() {
//testing whether the recycler view is displayed for not
onView(withId(R.id.menu_rv)).check(matches(isDisplayed()))
onView(allOf(withId(R.id.dish_ll), isDisplayed()))
//testing the scroll to position to 3rd position
onView(withId(R.id.menu_rv)).perform(
RecyclerViewActions
.scrollToPosition<RecyclerView.ViewHolder>(3)
)
//testing a particular item of the list
onView(allOf(withId(R.id.dish_catg_type_mtv), withText("Beverages")))
onView(allOf(withId(R.id.rv_dish_name_mtv), withText("Coffee")))
onView(allOf(withId(R.id.rv_dish_price_mtv), withText("0")))
onView(
allOf(
withId(R.id.rv_dish_description__mtv),
withText("Because ground coffee beans, coffee roasts, and brewing methods vary, so do coffee drinks. They come in so many different varieties and flavors, such as black coffee, espresso, latte, cappuccino, or mocha.")
)
)
/*onView(allOf(isDisplayed(), withId(R.id.rv_add_to_cart_btn)))
.perform(RecyclerViewActions.actionOnItemAtPosition<MenuDishAdapter.MenuDishViewHolder>(2, click()));
*/
/*val result = onView(
allOf(
withId(R.id.rv_add_to_cart_btn),
withText("Coffee")
)
).perform(
click()
)
Utils.printErrorLog("Result is: $result")*/
onView(allOf(withId(R.id.rv_add_to_cart_btn), isDescendantOfA(allOf(withId(R.id.buttons_cl))))).check(matches(isFocusable()))
*/
/* onData(allOf(withId(R.id.rv_add_to_cart_btn)))
.inAdapterView(allOf(withId(R.id.rv_dish_item_ll)))
.atPosition(1)
.perform(click())*/
}
}
Each and every time in running the testingMenuList I'm getting the error(screenshot attached).
What is the correct method to check the add to cart button click functionality?
The flow is as: MenuActivity has a recycler view menu_rv and this menu_rv contains another recycler view name dish_ll. Inside dish_ll, rv_add_to_cart_btn is the button that is being tested using the TDD approach.

How to fix a Recyclerview that doesn't scroll smoothly?

I am using a RecyclerView with LinearLayoutManager to fetch Data that I get from my API using Retrofit.
The problem is whenever I try to scroll down it goes to the first position.
Some answers on Github & Here, suggested decreasing the image' resolution and avoid using focusable objects but none of these solutions worked for me.
This is my RecyclerView declaration
<android.support.v7.widget.RecyclerView
app:layout_constraintTop_toBottomOf="#id/btn_rech"
app:layout_constraintStart_toStartOf="parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="50dp"
android:descendantFocusability="beforeDescendants"
android:id="#+id/recyler_view_voiture_occasion">
</android.support.v7.widget.RecyclerView>
This is the CardView item that I use to bind data
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="340dp"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:ignore="MissingConstraints"
app:cardCornerRadius="10sp"
android:elevation="15dp"
android:background="#color/colorGrey"
app:cardBackgroundColor="#color/colorLightGrey"
android:layout_margin="7dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="170dp"
android:background="#color/colorWhite"
android:scaleType="centerCrop"
android:id="#+id/annonce_image"
/>
<android.support.v7.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="2dp"
android:text="#string/general"
android:layout_below="#+id/annonce_image"
android:layout_alignStart="#id/annonce_image"
android:layout_marginStart="10dp"
android:textAppearance="#android:style/TextAppearance.Material.Widget.Toolbar.Title"
android:id="#+id/annonce_info"
/>
<android.support.v7.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="#android:style/TextAppearance.Material.Widget.Toolbar.Subtitle"
android:padding="2dp"
android:layout_marginStart="10dp"
android:id="#+id/annonce_price_info"
android:layout_below="#+id/annonce_info"
android:text="this is a sample text"
/>
<android.support.v7.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#ffffff"
android:outlineProvider="#color/colorPrimaryDark"
android:orientation="horizontal"
android:layout_marginTop="10dp"
android:weightSum="90"
android:background="#drawable/item_edit_versement"
android:layout_below="#id/annonce_price_info"
android:layout_marginHorizontal="10dp"
android:padding="5dp"
android:id="#+id/infos_holder"
>
<android.support.v7.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/annonce_km"
android:layout_weight="30"
android:textAlignment="center"
android:text="#string/prix"
android:textSize="14sp"
android:fontFamily="sans-serif-medium"
/>
<android.support.v7.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/annonce_annee"
android:textAlignment="center"
android:layout_weight="30"
android:text="#string/prix"
android:textSize="14sp"
android:fontFamily="sans-serif-medium"
/>
<android.support.v7.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_weight="30"
android:id="#+id/annonce_fuel"
android:textAlignment="center"
android:layout_height="wrap_content"
android:text="#string/Fuel"
android:textSize="14sp"
android:fontFamily="sans-serif-medium"
/>
</android.support.v7.widget.LinearLayoutCompat>
<android.support.v7.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_marginTop="12dp"
android:weightSum="100"
android:gravity="center"
android:layout_below="#id/infos_holder"
android:layout_height="wrap_content">
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/item_edit_versement"
android:layout_marginHorizontal="10dp"
android:layout_weight="40"
android:textStyle="bold"
android:textColor="#color/colorPrimaryDark"
android:textSize="14sp"
android:text="Faire un offre"
/>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/item_edit_versement"
android:backgroundTint="#424242"
android:drawableStart="#drawable/phone"
android:paddingStart="15dp"
android:text="Call owner"
android:textColor="#color/colorWhite"
android:textStyle="bold"
android:textSize="15sp"
android:layout_marginHorizontal="10dp"
android:layout_weight="35"
/>
</android.support.v7.widget.LinearLayoutCompat>
</RelativeLayout>
</android.support.v7.widget.CardView>
This is my part of Code where I get the data from DB and adapt it into the RV
fun prepareRecyclerView(v : View, id : String){
val layout = LinearLayoutManager(v.context)
layout.orientation = LinearLayoutManager.VERTICAL
val adapter = v.findViewById<RecyclerView>(R.id.recyler_view_voiture_occasion)
adapter.layoutManager = layout
val annonceAdapter = OccasionCarsAdapter(v.context,annonceList )
adapter.adapter = annonceAdapter
//initLineaire(v , R.id.recyler_view_voiture_occasion, LinearLayoutManager.VERTICAL ,annonceAdapter as RecyclerView.Adapter<RecyclerView.ViewHolder>)
}
fun getAnnonceList(id: String, maView: View, filters: VehiculeRechFilters?){
val service = prepareService()
val requestCall = service.GetOccasionAnnouncement(id,
filters!!.minPrix, filters.maxPrix, filters.minAnnee,
filters.minAnnee, filters.maxKm, filters.codeVersion)
requestCall.enqueue(object : Callback<List<VehiculeOccasion>> {
override fun onFailure(call: Call<List<VehiculeOccasion>>, t: Throwable) {
Log.e("Call response" , "Can't get the data" , t.cause)
}
override fun onResponse(call: Call<List<VehiculeOccasion>>, response: Response<List<VehiculeOccasion>>) {
if(response.isSuccessful){
Toast.makeText(this#CustomOccasionFragment.context,response.body().toString(), Toast.LENGTH_LONG).show()
for (e in response.body()!!){
annonceList.add(e)
}
prepareRecyclerView(maView!! ,idUser)
}
else {
Log.i("response assert" , "couldn't get the data correctly")
}
}
})
}

Kotlin : same fragment, children with same tag

In my fragment, I have two linear layout with the same tag "result". Inside theses linear layouts, I have another layout with the tag "toggle" and a button with the tag "toggleButton".
I want that : when I click on my button, it toggle the linear layout "toggle" of its linear layout parent "result"
But when I do this :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val root = rootLayoutResultSearch
root.findViewWithTag<Button>("toToggleButton")
val buttonToggle = view.findViewWithTag<Button>("toToggleButton")
buttonToggle.setOnClickListener{
Log.i(TAG, "click")
val toggle = view.findViewWithTag<LinearLayout>("toToggle")
if(toggle.visibility == View.GONE){
toggle.visibility = View.VISIBLE
}else{
toggle.visibility = View.GONE
}
}
}
it's working only for my first linear layout "result". When I click on my second button, it's not doing anything
Here the xml of the layouts "result" (I only post the first, the second is the exact same one)
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:tag="result"
android:contentDescription="result">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="35dp"
android:background="#drawable/whit_bg_and_shadow"
android:tag="visibleNotChangeable"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
style="#style/hoursSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight=".1"
android:fontFamily="#font/rubik_medium_italic"
android:tag="heureDepart"
android:text="#string/fillHoursRecherche1"
android:textStyle="italic" />
<TextView
style="#style/citySearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight=".9"
android:fontFamily="#font/rubik_medium"
android:tag="villeDepart"
android:text="#string/fillVilleRecherche1"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
style="#style/hoursSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight=".1"
android:fontFamily="#font/rubik_medium_italic"
android:tag="heureDepart"
android:text="#string/fillHoursRecherche2"
android:textFontWeight="500"
android:textStyle="italic" />
<TextView
style="#style/citySearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight=".9"
android:fontFamily="#font/rubik_medium"
android:tag="villeDepart"
android:text="#string/fillVilleRecherche2"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:fontFamily="#font/roboto"
android:tag="villeArrivee"
android:text="#string/jourCircuRecherche" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/roboto"
android:tag="villeArrivee"
android:text="#string/fillJourCircuRecherche" />
</LinearLayout>
<View style="#style/HorizontalLine" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/bus" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="15dp"
android:background="#drawable/dark_blue_rectangle"
android:text="3"
android:textColor="#color/colorWhite" />
</LinearLayout>
<View style="#style/HorizontalLine" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:src="#drawable/horaire" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="15dp"
android:fontFamily="#font/roboto"
android:text="#string/fillTempsRecherche" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="35dp"
android:background="#drawable/gray_bg"
android:visibility="gone"
android:tag="toToggle"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
style="#style/hoursSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight=".1"
android:fontFamily="#font/rubik_medium_italic"
android:tag="heureDepart"
android:text="#string/fillHoursRecherche1"
android:textStyle="italic" />
<TextView
style="#style/citySearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight=".9"
android:fontFamily="#font/rubik_medium"
android:tag="villeDepart"
android:text="#string/fillVilleRecherche1"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
style="#style/hoursSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight=".1"
android:fontFamily="#font/rubik_medium_italic"
android:tag="heureDepart"
android:text="#string/fillHoursRecherche2"
android:textFontWeight="500"
android:textStyle="italic" />
<TextView
style="#style/citySearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight=".9"
android:fontFamily="#font/rubik_medium"
android:tag="villeDepart"
android:text="#string/fillVilleRecherche2"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:fontFamily="#font/roboto"
android:tag="villeArrivee"
android:text="#string/jourCircuRecherche" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/roboto"
android:tag="villeArrivee"
android:text="#string/fillJourCircuRecherche" />
</LinearLayout>
<View style="#style/HorizontalLine" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/bus" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="15dp"
android:background="#drawable/dark_blue_rectangle"
android:text="3"
android:textColor="#color/colorWhite" />
</LinearLayout>
<View style="#style/HorizontalLine" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:src="#drawable/horaire" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="15dp"
android:fontFamily="#font/roboto"
android:text="#string/fillTempsRecherche" />
</LinearLayout>
</LinearLayout>
<Button
android:id="#+id/ToggleSearchResult"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="#drawable/arrow_down_blue_circle"
android:layout_gravity="center"
android:layout_marginTop="-20dp"
android:tag="toToggleButton"
/>
</LinearLayout>
Okay, I've thrown together a quick idea of what I think you want to accomplish. It excludes all the error and consistency checking one would normally want to do.
package com.example.toggler
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import android.widget.LinearLayout
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val list = arrayListOf<View>()
root_View.findViewsWithText(list, "toToggleButton", View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION)
list.forEach { button ->
button.setOnClickListener { v: View ->
val viewParent = v.parent
if (viewParent is LinearLayout) {
val taggedView = viewParent.findViewWithTag<View>("toggle")
taggedView.visibility = when {
taggedView.visibility == View.GONE -> View.VISIBLE
else -> View.GONE
}
}
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/root_View"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:contentDescription="toToggleButton"
android:tag="toToggleButton"
android:text="toggle"
tools:ignore="HardcodedText" />
<View
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#F44336"
android:tag="toggle" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:contentDescription="toToggleButton"
android:tag="toToggleButton"
android:text="toggle"
tools:ignore="HardcodedText" />
<View
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#9C27B0"
android:tag="toggle" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="#+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:contentDescription="toToggleButton"
android:tag="toToggleButton"
android:text="toggle"
tools:ignore="HardcodedText" />
<View
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#FFEB3B"
android:tag="toggle" />
</LinearLayout>
</LinearLayout>
[EDIT]
Or, if you prefer to use tags:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
root_View.findViewsWithTag("toToggleButton").forEach { button ->
button.setOnClickListener { v: View ->
val viewParent = v.parent
if (viewParent is LinearLayout) {
val taggedView = viewParent.findViewWithTag<View>("toggle")
taggedView.visibility = when {
taggedView.visibility == View.GONE -> View.VISIBLE
else -> View.GONE
}
}
}
}
}
}
private fun ViewGroup.findViewsWithTag(tag: String): Sequence<View> {
return sequence {
for (index in 0 until childCount) {
val child = getChildAt(index)
when (child) {
is ViewGroup -> yieldAll(child.findViewsWithTag(tag))
is View -> if (child.tag == tag) yield(child)
}
}
}
}

Categories

Resources