1

I have several TextViews inside ConstraintLayout. The visibility of those TextViews are set at runtime based upon the data availability.

I need to bold the text of the first visible TextView.

I have tried many things but couldn't resolve the issue.

I have tried:

  1. Looping through the child inside the parent layout and finding the first child and making it bold. This approach always finds the first child inside the parent layout regardless of it's visiblility.
  2. I put a check before retrieving the first element if view.visibility == View.VISIBLE and also I checked view.isShown, both way again returns the first child in the view hierarchy irrespective of the visibility. So, view.visibility always returns View.VISIBLE.

What am I missing and how can I make it work?

Providing sample codes:

XML

<?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">

    <data>

        <variable
            name="viewModel"
            type="MyViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/rootLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="24dp">

        <TextView
            android:id="@+id/textView1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="First textview"
            android:textColor="@color/black"
            android:visibility="@{viewModel.textView1Visibility}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />


        <TextView
            android:id="@+id/textView2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Second textview"
            android:textColor="@color/black"
            android:visibility="@{viewModel.textView2Visibility}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/textView1" />

        <TextView
            android:id="@+id/textView3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Third textview"
            android:textColor="@color/black"
            android:visibility="@{viewModel.textView3Visibility}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/textView2" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

CODE

    binding.apply {

        /** We have three textviews.
         * textView1 doesn't have data so we are hiding it.
         * textView2 has data so, we need to show it.
         * and textView2 will be the first item, we need to bold it as well. */

        textView1.visibility = View.GONE

        /** looping through the children of root layout and bolding the first visible */
        rootLayout.forEach exit@ { view ->
            if(view.isVisible || view.isShown) {
                (view as TextView).typeface = Typeface.DEFAULT_BOLD
                return@exit
            }
        }

    }
2
  • 2
    You'll need to show some code.
    – Cheticamp
    Commented Sep 2, 2022 at 21:01
  • @Cheticamp provided the code. Thanks.
    – skafle
    Commented Sep 6, 2022 at 18:10

1 Answer 1

0

Your code is looping through all the children of the ConstraintLayout because return@exit acts like a continue and not a true break.

Try the following:

run exit@{
    rootLayout.forEach { view ->
        if (view.isVisible || view.isShown) {
            (view as TextView).typeface = Typeface.DEFAULT_BOLD
            return@forEach
        }
    }
}

There may be a more elegant way to go about this, but the above should work.

Update to code:

rootLayout.children.firstOrNull { view ->
    view.isVisible || view.isShown
}?.also { view ->
    (view as TextView).typeface = Typeface.DEFAULT_BOLD
}

I will also mention that your code will find the first visible child of the ConstraintLayout child order, but that view may not be the view that one would pick as the first looking at the screen. That is because the view order within the children of ConstraintLayout may differ from the on-screen order due to layout constraints. This may not be a problem for you, but it is something to think about.

4
  • Thanks a lot for your response @Cheticamp. But the main issue remains unchanged. The visibility update from viewmodel is later than we check visibility with above code. Hence, all child views get it's visibility VISIBLE when we check with above code. So the bold is applied to the first child, then viewmodel updates it's visibility to GONE.
    – skafle
    Commented Sep 6, 2022 at 22:22
  • Then you had two problems. The code I posted fixed one. You have posted no code for the ViewModel or interactions with it, so it will be difficult to address the second problem. Post that code so someone can help.
    – Cheticamp
    Commented Sep 6, 2022 at 23:07
  • There is not much complicated code in viewmodel. Just if API response has data to display in the textView, visibility returns View.VISIBLE and which goes to XML -- android:visibility="@{viewModel.textView1Visibility}". Any way... thank you so much.
    – skafle
    Commented Sep 7, 2022 at 1:37
  • If you need to check the views after the API returns, you will need to establish a callback or some other means to make the changes.
    – Cheticamp
    Commented Sep 7, 2022 at 1:51

Not the answer you're looking for? Browse other questions tagged or ask your own question.