Search code examples
androidkotlintextviewscrollview

'TextView' inside 'ScrollView' stops scrolling when the parent 'ScrollView' is scrolled


Question:

I'm working on an Android app where I dynamically add custom views containing TextView elements inside a ScrollView. Each TextView is designed to be scrollable independently, but I'm encountering an issue where, if I put too much content in the main layout, the TextView stops being scrollable when the parent ScrollView is scrolled.

Layout Structure:

  • I have a ScrollView with a LinearLayout inside it.
  • Each child of the LinearLayout is a custom layout (inflated from an XML template) that contains multiple TextView elements, some of which need to be scrollable.

Flashcard Template (view_list_template.xml):

<RelativeLayout
    android:id="@+id/layoutStructure"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    
    <TextView
        android:id="@+id/textViewQ"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="vertical"
        android:lines="6"
        android:nestedScrollingEnabled="true"/>
        
    <!-- Other views -->
    
</RelativeLayout>

Main Layout (view_list.xml):

<RelativeLayout
    android:layout_height="match_parent"
    android:layout_width="match_parent">

    <ScrollView
        android:id="@+id/mainScrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
        <LinearLayout
            android:id="@+id/container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            
            <!-- Dynamically added views go here -->
            
        </LinearLayout>
    </ScrollView>
    
    <!-- Other views -->
    
</RelativeLayout>

Kotlin Code:

val container = findViewById<LinearLayout>(R.id.container)
val mainScrollView = findViewById<ScrollView>(R.id.mainScrollView)

for (card in flashCardStorage) {
    val cardLayout = LayoutInflater.from(this).inflate(R.layout.view_list_template, container, false) as RelativeLayout
    val questionTextView = cardLayout.findViewById<TextView>(R.id.textViewQ)
    
    // Set text and other properties
    questionTextView.text = card.question
    
    // Add card layout to container
    container.addView(cardLayout)
}

Problem:

When I try to scroll the TextView (with id=textViewQ) independently, it stops responding if there’s enough content in the main ScrollView. The main ScrollView seems to take over the scrolling, preventing the TextView from being scrollable.

What I've Tried:

  • Setting android:nestedScrollingEnabled="true" for the TextView.
  • Using requestDisallowInterceptTouchEvent(true) in OnTouchListener.
  • Ensuring the TextView has vertical scrollbars and enough lines for content overflow.

None of these attempts have resolved the issue. The TextView still stops scrolling when the parent ScrollView is in control.

Question:

How can I make sure that each TextView scrolls independently inside the ScrollView, even when there's a lot of content on the main page?


Solution

  • I found a solution for making the TextView scrollable within another scrollable view. Here's how you can do it by creating a separate Kotlin file to add an extension function for TextView:

    import android.text.method.ScrollingMovementMethod
    import android.view.MotionEvent
    import android.widget.TextView
    
    // This is an extension function for TextView to make it scrollable inside a ScrollView.
    fun TextView.makeScrollableInsideScrollView() {
        movementMethod = ScrollingMovementMethod()
        setOnTouchListener { v, event ->
            v.parent.requestDisallowInterceptTouchEvent(true)
            when (event.action and MotionEvent.ACTION_MASK) {
                MotionEvent.ACTION_UP -> {
                    v.parent.requestDisallowInterceptTouchEvent(false)
                    performClick() // To handle the warning about performClick
                }
            }
            false
        }
    }
    

    After adding this function, you can make any TextView scrollable within a ScrollView by simply calling the function like this:

    myTextView.makeScrollableInsideScrollView()