I want to make sure that in a recycler view (horizontal orientation and LinearLayoutManager set) that if I have 2 items to display they both get 50% of the parent layout. So both fit in the screen.
I have tried 2 approaches but neither works properly.
Approach 1:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val itemView = inflater.inflate(R.layout.horizontal_list_item_view, parent, false)
itemView.post(
object : Runnable {
override fun run() {
itemView.layoutParams.width = (parent.width * 0.5).toInt()
}
}
)
return ViewHolder(itemView)
}
This does not work unless I first scroll and then only the first item has its width adapted.
Approach 2:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val itemView = inflater.inflate(R.layout.horizontal_list_item_view, parent, false)
itemView.layoutParams.width = getScreenWidthFromUtils(context).x_width - MAGIC_NUMBER_WHICH_TAKES_PADDING_INTO_ACCOUNT)* 0.5).toInt()
return ViewHolder(itemView)
}
Approach 2 kind of works but obviously it can't be the solution as I doubt it has to be this complicated to achieve this.
What is the proper way to do this?
The GridLayoutManager will take care of giving your item the optimal size and space for the number of column you specify. In your case you want to have 2 items per row so your code should look like :
val gridLayoutManager = GridLayoutManager(context, 2, GridLayoutManager.HORIZONTAL, false)
Related
I'm sharing a RecycledViewPool between different RecyclerViews with same view type. Although the view type has different view bounds. For eg: In RecyclerView1 the width of a single item is 100dp where as in RecyclerView2 the width of a single items is 80dp.
Now whenever i scroll through the elements of either of the RecyclerView the RecycledViewPool returns me ViewHolder of a different RecyclerView. So while scrolling in one RecyclerView i get items with width as 100dp as well as 80dp since the view type for both the RecyclerView are same.
Adapter for RecyclerView1:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<HomeData> {
val viewHolder = super.onCreateViewHolder(parent, viewType)
val view = viewHolder.itemView
view.setWidth(100)
return viewHolder
}
Adapter for RecyclerView2:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<HomeData> {
val viewHolder = super.onCreateViewHolder(parent, viewType)
val view = viewHolder.itemView
view.setWidth(80)
return viewHolder
}
Both the RecyclerView have the same view type and share the same viewpool here.
Am i missing some configuration while setting the viewpool?
This is how the current implementation when I scroll fast.
With in second the whole items in the recycler view are showed till the end.. What I am trying to achieve is something like the one shown below (live demo: recycler views in play store),
even if we scroll fast it shows 1 or 2 items so it feels natural. How can I make the recycler view behave this way?
The code:
Adapter
class CustomAdapter(private val mList: List<ItemsViewModel>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.card_view_design, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
}
override fun getItemCount(): Int {
return mList.size
}
class ViewHolder(ItemView: View) : RecyclerView.ViewHolder(ItemView) {
val imageView: ImageView = itemView.findViewById(R.id.imageview)
val textView: TextView = itemView.findViewById(R.id.textView)
}
}
Implementation
val recyclerview = findViewById<RecyclerView>(R.id.recyclerview)
recyclerview.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.HORIZONTAL, false)
val data = ArrayList<ItemsViewModel>()
val adapter = CustomAdapter(data)
recyclerview.adapter = adapter
When a RecyclerView is scrolled horizontally, the scrollHorizontallyBy() is called several times with dx values that can make the scrolling behave smooth and real according to the fling (push) value of the finger.
The same for vertical RecyclerView, scrollVerticallyBy() gets called with different dy values.
So, you can manipulate this dx value to have the desired behavior; in your case you need to get smaller values of dx.
You'd think of a fixed dx value, but that won't be that natural; instead you can divide it by a fixed amount to scale down the same dx values.
Here I'm using an arbitrary value that you can manipulate it as you need.
So, what you need is to use a custom LinearLayoutManager & override scrollHorizontallyBy() as you use a horizontal recyclerView:
class MyLinearLayoutManager(context: Context?, orientation: Int, reverseLayout: Boolean) :
LinearLayoutManager(context, orientation, reverseLayout) {
override fun scrollHorizontallyBy(
dx: Int,
recycler: RecyclerView.Recycler?,
state: RecyclerView.State?
): Int {
var newDx = (dx / 1.2).toInt() // 1.2 is an arbitrary value
if (newDx == 0 && dx != 0) { // To have no 0 values (Optionally)
newDx = 1
}
return super.scrollHorizontallyBy(newDx, recycler, state)
}
}
Recently I move to Android View Binding from ButterKnife. All my layout are working well, but after migrating to View Binding, there is a weird behavior, all RecyclerView item have the layout_width as wrap_content instead of match_parent.
When I look at layout inspector tool, I see that the card view have wrap_content value for it's width.
But, I didn't change the xml file, so the width is actually still match_parent.
Do I miss something?
In your recycler onCreateViewHolder, instead of this
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemBinding.inflate(LayoutInflater.from(parent.context))
return ViewHolder(binding)
}
Use this 👇
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
The main recyclerview which is vertical recyclerview shows all the deals in the layout
But what I want to achieve is :
after the first 10 deals, I want to display a (horizontal recyclerview) of 5 recommended deal
after the next 10 deals, I want to display a (horizontal recyclerview) of 5 recommended deal
after the next 10 deals, I want to display a (horizontal recyclerview) of 5 recommended deal and so on…
I have attached the image of how i want the design to look like.
I have no clue on how to implement this. But I have both the recyclerview working separately. Just not sure how to combine them. I'm not even sure to code in the adapters or the mainactivity. I have attached the image of the horizontal recyclerview adapter and vertical recyclerview adapter. Please help me by showing me how to implement this feature. Thanks
class MyAdapter(val list: List<String?>): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val TYPE_ITEM = 0
private val TYPE_HORIZONTAL_ITEM = 1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if(viewType == TYPE_ITEM) {
ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false))
}else HorizontalViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.horizontal_layout, parent, false))
}
override fun getItemCount(): Int {
return list.size
}
override fun getItemViewType(position: Int): Int {
return if(list[position]!=null) TYPE_ITEM else TYPE_HORIZONTAL_ITEM
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if(holder is ViewHolder){
holder.bind(list[position]?:"")
// manage your items
}else if(holder is HorizontalViewHolder)
holder.bind()
// manage your horizontal recyclerView
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
fun bind(item: String){
}
}
class HorizontalViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
fun bind(){
}
}
You have to create Adapter which works with different viewTypes. As an example I've made list of Strings and every 10th element is null which is indicate that it's horizontal recyclerView. I believe that in your case instead of null it should be model for handling horizontal recyclerView. E.g list of 20 items should have size of 22 because there are two horizontal recyclerViews.
for (i in 1 until 25){
if (i % 10 == 0)
list.add(null)
else list.add("Hello")
}
recyclerView.adapter = MyAdapter(list)
enter image description here
I've attached final version of my result and that colored fields are for your RecyclerView.
I suggest you to avoid using inner RecyclerView and use NestedScrollView instead and add items through iteration.
I want to create a list of views that align horizontally using recyclerview. I want to be split the width of the recyclerview equally so that all those views can fit inside a single line. view count is dynamic
Here is a simple final result, I created this using HTML and CSS.
Can I achieve the same in android using recyclerview?
Following is my recyclerview adapter, holder.root is the container for every view. I was thinking about getting the recyclerview width and divide that by number of views and setting that value as width for every view.
class ThreadsAdapter(
private val threads: ArrayList<ThreadInfo>
): RecyclerView.Adapter<ThreadsAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.layout_progress_thread, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return threads.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.root.layoutParams.width = 40 // just testing
}
class ViewHolder(v: View): RecyclerView.ViewHolder(v) {
val progressBar: ProgressBar = v.findViewById(R.id.progressBar)
var root: ConstraintLayout = v.findViewById(R.id.root)
}
}
Eventually, I found this library on Github, allow me to use Flexbox layout in android
https://github.com/google/flexbox-layout