Scroll to a specific view in scroll view

前端 未结 15 1403
醉梦人生
醉梦人生 2020-12-04 14:08

I have added a scrollview and the subchilds inside the scrollview. At some point i need to scroll to a specific view.



1. 

        
相关标签:
15条回答
  • 2020-12-04 14:44

    I think I have found more elegant and error prone solution using

    ScrollView.requestChildRectangleOnScreen

    No math involved, and contrary to other proposed solutions, it will handle correctly scrolling both ways up and down.

    void scrollToRow(ScrollView scrollView, LinearLayout linearLayout, TextView textViewToShow) {
        Rect textRect = new Rect(); //coordinates to scroll to
        textViewToShow.getHitRect(textRect); //fills textRect with coordinates of TextView relative to its parent (LinearLayout) 
        scrollView.requestChildRectangleOnScreen(linearLayout, textRect, false); //ScrollView will make sure, the given textRect is visible
    }
    

    It is a good idea to wrap it into postDelayed to make it more reliable, in case the ScrollView is being changed at the moment

    private void scrollToRow(final ScrollView scrollView, final LinearLayout linearLayout, final TextView textViewToShow) {
        long delay = 100; //delay to let finish with possible modifications to ScrollView
        scrollView.postDelayed(new Runnable() {
            public void run() {
                Rect textRect = new Rect(); //coordinates to scroll to
                textViewToShow.getHitRect(textRect); //fills textRect with coordinates of TextView relative to its parent (LinearLayout) 
                scrollView.requestChildRectangleOnScreen(linearLayout, textRect, false); //ScrollView will make sure, the given textRect is visible
            }
        }, delay);
    }
    

    Just nice isn`t?

    0 讨论(0)
  • 2020-12-04 14:46

    If child that we need to scroll to is not a direct child then above solutions don't work

    I have used below solution in my project, sharing it may be helpful to others

    /**
     * Used to scroll to the given view.
     *
     * @param scrollViewParent Parent ScrollView
     * @param view View to which we need to scroll.
     */
    private void scrollToView(final ScrollView scrollViewParent, final View view) {
        // Get deepChild Offset
        Point childOffset = new Point();
        getDeepChildOffset(scrollViewParent, view.getParent(), view, childOffset);
        // Scroll to child.
        scrollViewParent.smoothScrollTo(0, childOffset.y);
    }
    
    /**
     * Used to get deep child offset.
     * <p/>
     * 1. We need to scroll to child in scrollview, but the child may not the direct child to scrollview.
     * 2. So to get correct child position to scroll, we need to iterate through all of its parent views till the main parent.
     *
     * @param mainParent        Main Top parent.
     * @param parent            Parent.
     * @param child             Child.
     * @param accumulatedOffset Accumulated Offset.
     */
    private void getDeepChildOffset(final ViewGroup mainParent, final ViewParent parent, final View child, final Point accumulatedOffset) {
        ViewGroup parentGroup = (ViewGroup) parent;
        accumulatedOffset.x += child.getLeft();
        accumulatedOffset.y += child.getTop();
        if (parentGroup.equals(mainParent)) {
            return;
        }
        getDeepChildOffset(mainParent, parentGroup.getParent(), parentGroup, accumulatedOffset);
    }
    
    0 讨论(0)
  • 2020-12-04 14:46

    try this:

    ScrollView sv = // your scrollview
    View insideView = // find the View that you need to scroll to which is inside this ScrollView
    sv.scrollTo(0, (int)insideView.getY());
    

    insideView.getY() will not work below API Level 11, for API Level below 11 you can replace insideView.getY() with insideView.getTop()

    0 讨论(0)
  • 2020-12-04 14:48

    Here rootView is your parent view and childView is a view where you want to scroll your view

    public static int getRelativeTop(View rootView, View childView) {
        if(childView.getParent() == rootView) return childView.getTop();
        else return childView.getTop() + getRelativeTop(rootView, (View) childView.getParent());
    }
    
    0 讨论(0)
  • 2020-12-04 14:49

    I use this like a extension

    fun ScrollView.focusOnView(toView: View){
    
        Handler().post(Runnable {
            this.smoothScrollTo(0, toView.top)
        })
    
    }
    

    Usage:

    myScrollView.focusOnView(myView)
    
    0 讨论(0)
  • 2020-12-04 14:52

    Here's a solution that works if the target view is not a direct child of your ScrollView:

    public int findYPositionInView (View rootView, View targetView)
    {
      return findYPositionInView (rootView, targetView, 0);
    }
    
    
    // returns -1 if targetView not found
    private int findYPositionInView (View rootView, View targetView, int yCumulative)
    {
      if (rootView == targetView)
        return yCumulative;
    
      if (rootView instanceof ViewGroup)
      {
        ViewGroup parentView = (ViewGroup)rootView;
        for (int i = 0;  i < parentView.getChildCount ();  i++)
        {
          View child = parentView.getChildAt (i);
          int yChild = yCumulative + (int)child.getY ();
    
          int yNested = findYPositionInView (child, targetView, yChild);
          if (yNested != -1)
            return yNested;
        }
      }
    
      return -1; // not found
    }
    

    Use it like this:

    int yScroll = findYPositionInView (scrollView, targetView);
    scrollView.scrollTo (0, yScroll);
    

    Further, if you wish to set focus, do this:

    targetView.requestFocus ();
    

    And, if you want the keyboard to show, do this:

    if (targetView instanceof EditText)
    {
      targetView.post (new Runnable ()
      {
        @Override public void run ()
        {
          InputMethodManager imm = (InputMethodManager)context.getSystemService (Context.INPUT_METHOD_SERVICE);
          imm.showSoftInput (targetView, InputMethodManager.SHOW_FORCED);
        }
      });
    }
    
    0 讨论(0)
提交回复
热议问题