3

I wanna achieve the following be behavior for one screen of my app. I have a fragment's layout with ConstraintLayout as it's parent. Inside ConstraintLayout I have a ScrollView with nested ConstraintLayout (nested ConstraintLayout contains ImageView and TextView) and simple Button below the ScrollView.

I wanna enable button as soon as user reaches to the bottom of ScrollView and disable when user scrolls up.

Layout is below.

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    >

  <ScrollView
      android:id="@+id/scrollableView"
      android:layout_width="match_parent"
      android:layout_height="0dp"
      android:fillViewport="true"
      app:layout_constraintBottom_toTopOf="@id/elevationShadow"
      app:layout_constraintTop_toBottomOf="@id/appbar">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_marginStart="@dimen/spacing_large"
        android:layout_marginEnd="@dimen/spacing_large"
        android:layout_height="wrap_content">

      <ImageView
          android:id="@+id/user_image"
          android:layout_width="144dp"
          android:layout_height="144dp"
          android:layout_gravity="center"
          android:layout_marginTop="@dimen/spacing_large"
          android:src="@drawable/user_image"
          android:visibility="visible"
          app:layout_constraintEnd_toEndOf="parent"
          app:layout_constraintStart_toStartOf="parent"
          app:layout_constraintTop_toTopOf="parent"
          />

      <TextView
          android:id="@+id/heading"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:textSize="@dimen/text_size_xxlarge"
          android:textStyle="bold"
          android:textAlignment="center"
          android:textColor="@color/black_color"
          android:layout_marginTop="@dimen/spacing_large"
          tools:text="Tools text"
          android:textAppearance="?tvptTextAppearanceBody"
          app:layout_constraintEnd_toEndOf="parent"
          app:layout_constraintStart_toStartOf="parent"
          app:layout_constraintTop_toBottomOf="@+id/user_image"
          />

      <TextView
          android:id="@+id/content"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_marginTop="@dimen/spacing_large"
          android:textAlignment="center"
          android:textSize="@dimen/user_info_content_text_size"
          android:textAppearance="?tvptTextAppearanceBody"
          android:textColor="@color/black"
          app:layout_constraintEnd_toEndOf="parent"
          app:layout_constraintHorizontal_bias="0.0"
          app:layout_constraintStart_toStartOf="parent"
          app:layout_constraintTop_toBottomOf="@+id/heading"
          tools:text="Tools test content"
          />

    </androidx.constraintlayout.widget.ConstraintLayout>

  </ScrollView>

  <View
      android:id="@+id/elevationShadow"
      android:layout_width="match_parent"
      android:layout_height="3dp"
      android:background="@drawable/shadow_elevation"
      app:layout_constraintEnd_toEndOf="parent"
      android:layout_marginBottom="@dimen/user_info_activity_confirm_button_margin"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintBottom_toTopOf="@id/button_confirm"/>

  <com.travelportdigital.android.compasswidget.button.PercentageBasedStateButton
      android:id="@+id/button_confirm"
      style="@style/PrimaryButton"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:background="@android:color/transparent"
      android:layout_marginBottom="@dimen/user_info_activity_confirm_button_margin"
      android:text="@string/user_info_continueButton_title"
      android:textAllCaps="true"
      app:layout_constraintBottom_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

The problem is that content for TextView which is inside ScrollView can both long and short. That's why I had to add ScrollView if the content is long.

By the small piece of code I was able to achieve the behavior I needed with one small remark.

fun addScrollChangeListener() {
    scrollView.viewTreeObserver
        .addOnScrollChangedListener {
          enableContinueButton(scrollView.getChildAt(0).bottom <= scrollView.height + scrollView.scrollY)
        }
  }

And the code above works fine for the scenario when content is long (when user arrives to this screen Continue button is disabled and when user scrolls to the bottom of the scroll view it become enabled if user scrolls up it becomes disabled again.

I wanna update this logic to enable button when user arrives to this screen and content of TextView inside ScrollView is short (no need scrolling for this scenario).

I made some researches in Google and could not find the solution which would work for me.

In onViewCreated() method I added logic to disable or enable button when user arrives to this screen.

enableContinueButton(!isScrollingRequired())

I tried this implementation

  private fun isScrollingRequired(): Boolean {
    val view = scrollView.getChildAt(scrollView.childCount - 1) as View
    val diff = view.bottom - (scrollView.height + scrollView.scrollY)
   return diff != 0
  }

and this

    return if (child != null) {
      val childHeight = child.height
      scrollView.height <= childHeight + scrollView.paddingTop + scrollView.paddingBottom;
    } else {
      false
    }

but it did not work, because ScrollView height and it's child height is always 0

Looking forward your advices.

Regards, Alex

  • Issue is resolved. The answer in this post helped me a lot. https://stackoverflow.com/a/57876872/7276497 I had to use GlobalLayoutListener in onActivityCreatedMethod as comment's author suggested. – Alexandru Iachimov Oct 17 '20 at 14:09
  • Careful: `onGlobalLayout` is not guaranteed to be called at a point when views have a dimension: https://cheesecakelabs.com/blog/understanding-android-views-dimensions-set/ – user2891462 Sep 02 '21 at 17:16

1 Answers1

0

I dont know is this what you want to do but it should be one of the solution.

I think you can just simply add the button in the "ScrollView" so when user scrolls at the bottom, user will see the button and when user scrolls up, user cannot press the button as well.

Below layout .XML works for me, Using ScrollView with ConstraintLayout:
(you may need extra dependencies)

<ScrollView
        android:id="@+id/msg_scroll"
        android:layout_width="0dp"
        android:layout_height="200dp"
        android:fillViewport="true"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/infoSumm">
        <!--Display the <ScrollView> under <TextView>"@+id/infoSumm" -->

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/inside_scroll"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toTopOf="parent">

            <TextView
                android:id="@+id/infoDetail"
                android:text=""
                android:layout_marginTop="12dp"
                android:scrollbars="vertical"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:maxHeight="240dp"
                app:layout_constraintTop_toTopOf="@id/inside_scroll"
                app:layout_constraintStart_toStartOf="parent"
                tools:text="Info Detail"/>


            <com.google.android.material.button.MaterialButton
                android:id="@+id/btn_infoClose"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/default_field_spacing"
                android:backgroundTint="@color/colorPrimary"
                android:textAppearance="@style/TextAppearance.MaterialComponents.Button"
                android:textAlignment="center"
                android:textStyle="bold"
                android:textAllCaps="false"
                android:textSize="20sp"
                android:textColor="@color/colorWhite"
                android:text="@string/btn_Close"
                android:paddingTop="10dp"
                android:paddingBottom="10dp"
                app:cornerRadius="25dp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/infoDetail"/>

        </androidx.constraintlayout.widget.ConstraintLayout>
    </ScrollView>
kiu
  • 111
  • 1
  • 6