Android: How to place a view so it is constrained and overlaps views inside neighboring customviews

26 Views Asked by At

I am trying to dynamically create and place a View which starts below an icon within a custom 'RecordView', and above the same icon of another 'RecordView' which is just below it using a a ConstraintLayout. The id's of the icons I have confirmed are unique but it seems the constraint doesn't work when connecting to a view inside a custom view.

Any ideas for either fixing this approach or using a different layout to achieve the following expected result and draw the same in between other RecordViews similarly: Desired view

actual result

Here's the code for creating the line dynamically and attempting to constrain against the icons int the first and second RecordViews. It seems that it can only make the constraint against the entire custom view but not against views within them. If ConstraintLayout's don't cater for this, is there any alternatives as I can't seem to find any.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val mainLayout: ConstraintLayout = view.findViewById(R.id.fragmentLayout)

        val record1View: RecordView = view.findViewById(R.id.record1)
        val record2View: RecordView = view.findViewById(R.id.record2)

        val lineView = CanvasLineView(context).apply {
            id = View.generateViewId()
            layoutParams = ConstraintLayout.LayoutParams(20.dpToPx(), ConstraintLayout.LayoutParams.MATCH_CONSTRAINT)
            setBackgroundColor(Color.CYAN)
        }

        mainLayout.addView(lineView)

        val constraintSet = ConstraintSet()
        constraintSet.clone(mainLayout)

        constraintSet.connect(
            lineView.id, ConstraintSet.START,
            record1View.icon.id, ConstraintSet.START,
            0
        )

        constraintSet.connect(
            lineView.id, ConstraintSet.TOP,
            record1View.icon.id, ConstraintSet.BOTTOM,
            0
        )
        constraintSet.connect(
            lineView.id, ConstraintSet.BOTTOM,
            record2View.icon.id, ConstraintSet.BOTTOM,
            0
        )

        constraintSet.applyTo(mainLayout)
    }

Here's the layout for the record_view

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:id="@+id/recordlayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:background="@drawable/border">
    <LinearLayout
        android:id="@+id/recordLinearlayout"
        android:orientation="vertical"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_gravity="center_vertical"
        android:layout_marginStart="8dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <TextView
                android:id="@+id/title"
                android:textStyle="bold"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Title" />
            <View
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_weight="1" />

            <ImageView
                android:id="@+id/icon"
                android:layout_width="24dp"
                android:layout_height="24dp"
                android:layout_gravity="end"
                android:src="@android:drawable/ic_menu_add" />
        </LinearLayout>
        <TextView
            android:id="@+id/content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Content" />
    </LinearLayout>

</LinearLayout>

and the code behind

class RecordView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {

    val icon: ImageView
    private val title: TextView
    private val content: TextView

    init {
        inflate(context, R.layout.record_view, this)

        icon = findViewById(R.id.icon)
        title = findViewById(R.id.title)
        content = findViewById(R.id.content)


        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.Record)
        val recordTitle = typedArray.getString(R.styleable.Record_recordTitle)
        val recordContent = typedArray.getString(R.styleable.Record_recordContent)

        val iconId = typedArray.getResourceId(R.styleable.Record_recordIconId, -1)
        if (iconId != -1) {
            icon.id = iconId
        }

        typedArray.recycle()

        // Set the title and content from attributes
        title.text = recordTitle
        content.text = recordContent
    }
}

and here's the main layout

<?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:id="@+id/fragmentLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.example.constrainviewinsideotherviews.RecordView
            android:id="@+id/record1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:recordTitle="Record 1"
            app:recordIconId="@+id/record1_icon"
            app:recordContent="This is the first record"
            app:layout_constraintStart_toStartOf="parent"
            android:paddingBottom="2dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>

        <com.example.constrainviewinsideotherviews.RecordView
            android:id="@+id/record2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:recordTitle="Record 2"
            app:recordIconId="@+id/record2_icon"
            app:recordContent="This is the second record.\nIt will\ntake up\nquite\a few\nlines"
            android:paddingBottom="2dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/record1"/>

        <com.example.constrainviewinsideotherviews.RecordView
            android:id="@+id/record3"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:recordTitle="Record 3"
            app:recordIconId="@+id/record3_icon"
            android:paddingBottom="2dp"
            app:recordContent="This is the third record"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/record2"/>

        <com.example.constrainviewinsideotherviews.RecordView
            android:id="@+id/record4"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:recordTitle="Record 3"
            app:recordIconId="@+id/record4_icon"
            android:paddingBottom="2dp"
            app:recordContent="This is the fourth record"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/record3"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
0

There are 0 best solutions below