1

Currently I'm developing a screen which will generate views dynamically based on a response and it involves a lot of cases where I should change the focus/position of scroll view to the selected view. So far I have managed to solve most of issues by using this method when view is not visible on screen:

fun View.requestViewOnScreen() {
   val rect = Rect(0, 0, width, height)
   requestRectangleOnScreen(rect, false)
}

The problem is that I have a hierarchy of nested views, and when the view is visible, it stays where it is when I call the above code, even if i try it with the code below (also with delay):

scrollView.smoothScrollTo(0, view.top)

Hierarchy is like:

  1. NestedScrollView
  2. ConstraintLayout
  3. CustomView
  4. LinearLayout
  5. The view which I want to position it on the top/center of screen

ScrollView widget:

  <androidx.core.widget.NestedScrollView
   android:id="@+id/scrollView"
   android:layout_width="0dp"
   android:layout_height="0dp"
   android:fillViewport="true"
   android:visibility="gone"
   app:layout_constraintBottom_toTopOf="@+id/stickyCtaView"
   app:layout_constraintEnd_toEndOf="parent"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintTop_toTopOf="parent"
   tools:visibility="visible">

Any idea how can I adapt my code to make the NestedScrollView to scroll and position the requested view in center? Also I want to note that I have a reference to the view object itself. Thanks in advance!

Astrit Veliu
  • 1,252
  • 1
  • 12
  • 22
  • I don't really get how your layout ist constructed, is the `ConstraintLayout` the direct child for the `NestedScrollView`, are 3,4,5 siblings in the ConstraintLayout? – Muhannad Fakhouri Dec 13 '21 at 08:20
  • @MuhannadFakhouri ConstraintLayout is the direct child for NestedScrollView, 3 is child of 2, 4 is child of 3, and 5 is child of 4 (the hierarchy goes like cascade). The issue is when I want to scroll to a view which will show error, the requestRectangleOnScreen and smoothScrollTo aren't focusing at all the view – Astrit Veliu Dec 13 '21 at 08:49

1 Answers1

1

view.top returns the top position of a view relative to its direct parent, in your case it's the top position in relation to a greater parent is required for that you can use a method like the following to aggregate the top position of a view in relation to the scrollView and scroll to it

private fun ScrollView.scrollTo(target: View) {
        var topPosition = 0
        var view = target
        while (view !== this) {
            topPosition += view.top
            view = view.parent as View
        }
        smoothScrollTo(0, topPosition)
    }

so to scroll to any view you just call scrollView.scrollTo(view)

Muhannad Fakhouri
  • 1,468
  • 11
  • 14
  • Thank you for your answer, this works at some point but I have one more question, how should I change the condition to scroll the top of target view a little higher, because right now its scrolling it somewhere down the center of screen. Thank you in advance! – Astrit Veliu Dec 15 '21 at 07:46
  • actually it should assure that the scrollview is scrolled as much as it can to place the target view on top, is it really possible for your view to scroll even more? if not maybe adding a big `paddingBottom` to your scrollView can help you achieve that – Muhannad Fakhouri Dec 15 '21 at 11:26
  • Yes, the view can scroll like 2x more than the target view height itself on this case, I'll try with paddingBottom and see if it will achieve a better result. Thank you for your reply! – Astrit Veliu Dec 15 '21 at 12:05
  • You're welcome, if this doesn't work let me have a look at your layout file – Muhannad Fakhouri Dec 15 '21 at 12:18
  • With padding is achieving almost what I need, so I'll mark this as the correct Answer! Thank you for your awesome solution :) – Astrit Veliu Dec 15 '21 at 12:47
  • You're welcome ✌ – Muhannad Fakhouri Dec 15 '21 at 21:26