0

my listview has a relative layout parent, it is set to wrap hight and match width, the problem is in the listview height, when i set it to 100dp it works fine, the items show, but when i set it to wrap or match parent it clips and only show one or non of the items, i can see that there is a scroll bar at the side as well, how can i make it wrap?

        <RelativeLayout
            android:id="@+id/expandable_rl"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="@dimen/xlarge">

            <ListView
                android:id="@+id/lisview"
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:layout_alignParentEnd="true"

                app:layout_constraintVertical_bias="1.0"
                android:layout_alignParentBottom="true"
                app:layout_constraintHorizontal_bias="0.0" />


        </RelativeLayout>

and this is how i am setting it, its just to test it, its located in a recycler view

        holder.list.adapter = ArrayAdapter(holder.itemView.context, R.layout.simple_item, arrayListOf("hello","hi","testing"))

this is how i expand the expandable layout

 holder.itemView.setOnClickListener {
            if (unitsList[position].isExpandable) {
                holder.expandableRL.visibility = if (holder.expandableRL.visibility == View.GONE) View.VISIBLE else View.GONE
            }
        }

i tried using notifyItemChanged(position) but it made it expand then immediately collapse for some reason
i am new here and don't know how to fix this at the moment

1 Answers1

0

A fully wrapped list means it doesn't scroll, as all of items are visible. If that is the case, why using a ListView in the first place. Here is a suggestion to make use of LinearLayout instead.

XML for RecyclerView item:

<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="wrap_content"
    >

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:text="Click Me" />

    <LinearLayout
        android:id="@+id/expandable_rl"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@id/button"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:visibility="gone"
        android:orientation="vertical">
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

And Here's the adapter:

class RecyclerAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return ViewHolder(
            LayoutInflater.from(parent.context).inflate(
                R.layout.recycler_item,
                parent,
                false
            )
        )
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        (holder as? ViewHolder)?.itemView?.let { itemView ->
            val expandable = itemView.findViewById<LinearLayout>(R.id.expandable_rl)
            createItems(expandable)
            itemView.findViewById<Button>(R.id.button).setOnClickListener {
                expandable.visibility = View.VISIBLE
            }
        }
    }

    private fun createItems(expandable: LinearLayout) {
        listOf("Hi", "Hello", "Goodbye").forEach { word ->
            val item = createItem(expandable.context, word)
            expandable.addView(item)
        }
    }
    
    private fun createItem(context: Context, word: String): View {
        return LinearLayout(context).apply {
            layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
            orientation = LinearLayout.VERTICAL
            gravity = Gravity.CENTER
            addView(
                TextView(context).apply {
                    layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
                    text = word
                }
            )
        }
    }

    override fun getItemCount(): Int {
        return 30
    }

    class ViewHolder(view: View): RecyclerView.ViewHolder(view)
}

This is a basic design, but you can take it from here and design what you need.

gioravered
  • 1,758
  • 3
  • 19
  • 30
  • thanks @gioravered, i love the solution, it makes more sense, i didn't know you could do stuff like this, i have a question tho, i have a custom view inside instead of that TextView, is there a way to summon it and then i would edit the texts and so on....? or maybe a video that you would recommend that goes into details on how to do it this way, cause my item has different types of views, and i want to learn how to do stuff this way – Yakin Wissem Aug 30 '21 at 13:16
  • When you say custom view you mean XML or you mean you created a new class that extends the View class? – gioravered Aug 30 '21 at 15:09
  • @Yakin Wissem, Also, please accept the answer if you think it answers your question. Thanks. – gioravered Aug 31 '21 at 06:14
  • yes, i mean xml, sorry i didn't know about accepting answers. – Yakin Wissem Aug 31 '21 at 11:00
  • No worries. For xml, you need to inflate the view using a layout inflater. Check this answer https://stackoverflow.com/questions/2335813/how-to-inflate-one-view-with-a-layout – gioravered Aug 31 '21 at 18:12
  • yup that is what i wanted, thank you so much, you're a saint – Yakin Wissem Aug 31 '21 at 21:39