I have set up view model, live data, recycler view, adapters, and view holders to render the folllowing JSON response. The payload has other attributes, but they are not that important as compared to widthUnit
.
{
"canvasUnit": 16,
"specials": [{
"display_name": "Noodle Dish with Roasted Black Bean Sauce",
"heightUnit": 8,
"widthUnit": 16
},
{
"display_name": "Onion Flavored Rings",
"heightUnit": 8,
"widthUnit": 8
},
{
"display_name": "Kikkoman Less Sodium Soy Sauce",
"heightUnit": 8,
"widthUnit": 8
},
{
"display_name": "Organic Romaine Hearts",
"heightUnit": 4,
"widthUnit": 14
},
{
"display_name": "Navel Oranges 4LBS",
"heightUnit": 6,
"widthUnit": 4
},
{
"display_name": "Doritos Ranch",
"heightUnit": 6,
"widthUnit": 4
},
{
"display_name": "Lindt Hello Cookies & Cream 1.4 oz",
"heightUnit": 6,
"widthUnit": 4
}
]
}
I need to have variable number of view on the same row depending on the ratio of widthUnit
to canvasUnit
. In this example, the first row has a ratio of 16 / 16
= 1
. So the 1st row should show the entry associated with the first row
The next two JSON objects have a value of widthUnit
as 8. So their ratio to the maxUnit
is 0.5, which means that I need to display the next two items on the 2nd row.
Similarly, since the next 4 entries have a cumulative width of 16, then 4 items should be shown on the 3rd row.
So the final layout should be something like this
---------------------------------
| |
| ----------------------------- |
| | | |
| | entry # 1 | |
| | | |
| ------------------------------ |
|
| ------------ ------------ |
| | entry # 2 | | entry # 3 | |
| ------------- ----------- |
| ---- ---- ---- ----- |
| | #4 | | #5 | | #6 | | #7 | |
| ---- --- ---- ----- |
---------------------------------
How do I accomplish something like this? I have tried using FlexLayoutManager like this
In my activity's onCreate
function,
I have initialised the adapter, as follows
val recyclerAdapter = RecyclerAdapter(this) // Passing the context to the adapter.
val recyclerView = findViewById(R.id.recycler_view)
with(recyclerView) {
val flexboxLayoutManager = FlexboxLayoutManager(this@MyActivity).apply {
flexDirection = FlexDirection.ROW
justifyContent = JustifyContent.FLEX_START
flexWrap = FlexWrap.WRAP
}
layoutManager = flexboxLayoutManager
adapter = recyclerAdapter
setHasFixedSize(true)
}
Adapter code
class RecyclerAdapter(
private val context: Context
): RecyclerView.Adapter<ViewHolder>() {
var item: Item? = null;
override fun getItemCount(): Int = item?.specials?.size ?: 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val itemBinding: ItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.item, parent, false)
return ViewHolder(context, itemBinding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindViewHolder(item?.specials?.get(position), item?.canvasUnit)
}
}
ViewHolder
class ViewHolder(
private val context: Context,
private val itemBinding: ItemBinding,
): RecyclerView.ViewHolder(
itemBinding.root
) {
fun bindViewHolder(special: Specials?, canvasUnit: Int?) {
special ?: return
canvasUnit ?: return
itemBinding.special = special
itemBinding.executePendingBindings()
}
}
Layout
<?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">
<data>
<import type="android.view.View"/>
<variable
name="special"
type="com.myproject.mobile.model.Specials" />
</data>
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/standardMargin2x"
android:padding="@dimen/standardMargin2x"
style="@style/CardView"
android:visibility="@{special != null ? View.VISIBLE : View.GONE}">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/standardMargin"
android:orientation="horizontal">
<ImageView
android:id="@+id/product_image_url"
android:layout_width="@dimen/product_image_width"
android:layout_height="@dimen/product_image_height"
android:importantForAccessibility="no"
android:layout_alignParentStart="true"
android:scaleType="fitCenter"
android:contentDescription="@null"
android:layout_marginEnd="@dimen/standardMargin2x"
app:imageUrl="@{special.imageUrl}" />
<LinearLayout
android:id="@+id/product_price_container"
android:layout_marginStart="@dimen/standardMargin2x"
android:layout_marginBottom="@dimen/standardMargin2x"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@+id/product_image_url"
android:layout_alignParentEnd="true"
android:layout_alignWithParentIfMissing="true"
android:orientation="vertical"
android:layout_marginEnd="@dimen/standardMargin2x"
android:gravity="end">
<TextView
android:id="@+id/product_original_price"
android:layout_marginBottom="@dimen/standardMargin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/strikethrough"
android:textAppearance="@style/TextAppearance"
app:inUSD="@{special.originalPrice}"
tools:text="$5.00"/>
<TextView
android:id="@+id/product_price"
android:layout_marginBottom="@dimen/standardMargin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Secondary"
app:inUSD="@{special.price}"
tools:text="$5.00"/>
</LinearLayout>
<TextView
android:id="@+id/product_display_name"
android:layout_width="@dimen/text_display_width"
android:layout_height="wrap_content"
android:gravity="center|center_vertical"
android:layout_centerHorizontal="true"
android:layout_below="@id/product_price_container"
android:maxLines="2"
android:ellipsize="end"
android:text="@{special.displayName}"
android:textAppearance="@style/TextAppearance.Bold"
tools:text="Onion flavoured rings"
/>
</RelativeLayout>
</androidx.cardview.widget.CardView>
</layout>
The data is being rendered in a card view as follows
But I would like the entries to be rendered as per my requirements. How can I implement something like this? I have tried going through the following posts