Android 在滚动视图中滚动到特定视图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21483188/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 04:39:07  来源:igfitidea点击:

Scroll to a specific view in scroll view

androidscrollview

提问by Rajagopal

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

我在滚动视图中添加了一个滚动视图和子子项。在某些时候,我需要滚动到特定视图。

<scrollview>

1. <linearlayout>

    <textview></textview>
    <textview></textview>

   </linearlayout>

2. <linearlayout>

    <textview></textview>
    <textview></textview>

   </linearlayout>

3. <linearlayout>

    <textview></textview>
    <textview></textview>

   </linearlayout>

4. <linearlayout>

    <textview></textview>
    <textview></textview>

   </linearlayout>

5. <linearlayout>

    <textview></textview>
    <textview></textview>

   </linearlayout>

6. <linearlayout>

    <textview></textview>
    <textview></textview>

   </linearlayout>

7. <linearlayout>

    <textview></textview>
    <textview></textview>

   </linearlayout>

   <button>
   </button>

 </scrollview>

The above layout was created dynamically. so i can't have the xml file posted here. Layout creation is completely dynamic. Even the number of child view inside the linearlayout may also vary.

上面的布局是动态创建的。所以我不能在这里发布 xml 文件。布局创建是完全动态的。甚至线性布局内的子视图数量也可能会有所不同。

So when i click on the button i need to get scrolled to a particular view say here when i click on button i need to scroll to the linear layout 4. I tried with the scrollTo method but it scrolls to the top of the scrollview.

所以当我点击按钮时,我需要滚动到一个特定的视图,当我点击按钮时,我需要滚动到线性布局 4。我尝试使用 scrollTo 方法,但它滚动到滚动视图的顶部。

Please provide some suggestions.

请提供一些建议。

回答by Vasanth

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);
}

回答by Swas_99

This should do the trick:

这应该可以解决问题:

View targetView = findViewById(R.id.DESIRED_VIEW_ID);  
targetView.getParent().requestChildFocus(targetView,targetView);

public void RequestChildFocus (View child, View focused)

public void RequestChildFocus(查看子项,查看焦点)

child- The child of this ViewParent that wants focus. This view will contain the focused view. It is not necessarily the view that actually has focus.

child- 想要获得焦点的这个 ViewParent 的孩子。该视图将包含聚焦视图。实际具有焦点的不一定是视图。

focused- The view that is a descendant of child that actually has focus

focused- 视图是实际上具有焦点的 child 的后代

回答by Dev

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()

insideView.getY()将无法在 API 级别 11 以下工作,对于低于 11 的 API 级别,您可以替换insideView.getY()insideView.getTop()

回答by ?tarke

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

我想我找到了更优雅且容易出错的解决方案

ScrollView.requestChildRectangleOnScreen

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 postDelayedto make it more reliable, in case the ScrollViewis being changed at the moment

最好将其包装起来postDelayed以使其更可靠,以防当前ScrollView正在更改

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?

很好不是吗?

回答by midhunhk

Since you can know the child LinearLayoutthat you need to scroll to, how about trying this.

既然你可以知道LinearLayout你需要滚动到的孩子,那么试试这个怎么样。

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

More information on scrollToas well as smoothScrollTo

有关scrollTosmoothScrollTo 的更多信息

回答by Peri Hartman

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

如果目标视图不是 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);
    }
  });
}

回答by Mohammad Javad

Use :

用 :

final  ScrollView scrollView= (ScrollView) 
int speed=1000;
findViewById(R.id.main_scrollView);
final View view = findViewById(R.id.your_view); 
ViewTreeObserver vto = view.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() { view.getViewTreeObserver().removeOnGlobalLayoutListener(this);   
                ObjectAnimator.ofInt(scrollView, "scrollY",  (int) view.getY()).setDuration(speed).start();
            }
        }); 

回答by Eric Mutta

I got the desired result using requestChildFocus() as suggested by Swas_99's answer above.

我使用 requestChildFocus() 得到了想要的结果,正如上面Swas_99 的回答所建议的那样。

However since it doesn't do smooth scrolling, I looked into the source code for requestChildFocuswhich calls scrollToChildwhich calls offsetDescendantRectToMyCoords. From there I got the idea to use the following C#/Xamarin code which gives a similar effect to using requestChildFocus() but with smooth scrolling:

但是,由于它不能平滑滚动,我查看了requestChildFocus的源代码,它调用了scrollToChild,它调用了offsetDescendantRectToMyCoords。从那里我得到了使用以下 C#/Xamarin 代码的想法,该代码与使用 requestChildFocus() 具有类似的效果,但具有平滑滚动:

private static void ScrollToView(View ArgTarget) {
    var CurParent = ArgTarget.Parent;

    while (CurParent != null) {
      var ScrollArea = CurParent as ScrollView;

      if (ScrollArea != null) {
        var ViewRect = new Rect();
        ArgTarget.GetDrawingRect(ViewRect);

        ScrollArea.OffsetDescendantRectToMyCoords(ArgTarget, ViewRect);
        ScrollArea.SmoothScrollTo(ViewRect.Left, ViewRect.Top);

        break;
      }

      CurParent = CurParent.Parent;
   }
}

The basic idea is to find the target view's containing ScrollView. Then get the target view's drawing rectangle, adjust its coordinates so they are understood by the ScrollView then ask the ScrollView to scroll to smooth-scroll to that position. The end effect is that the view you want to scroll to always ends up being fully visible near the top of the screen (you can play around with ViewRect.Top if you want to center the view on the screen instead).

基本思想是找到包含 ScrollView 的目标视图。然后获取目标视图的绘图矩形,调整其坐标以便 ScrollView 理解它们,然后要求 ScrollView 滚动以平滑滚动到该位置。最终效果是您想要滚动到的视图始终在屏幕顶部附近完全可见(如果您想将视图置于屏幕中心,则可以使用 ViewRect.Top)。

回答by ad joy

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

这里 rootView 是您的父视图,而 childView 是您想​​要滚动视图的视图

public static int getRelativeTop(View rootView, View childView) {
    if(childView.getParent() == rootView) return childView.getTop();
    else return childView.getTop() + getRelativeTop(rootView, (View) childView.getParent());
}

回答by Phuong Pham

You can use method smoothScrollTo to scroll to specific view in scroll view. - Example:

您可以使用方法 smoothScrollTo 在滚动视图中滚动到特定视图。- 例子:

my_scroll_View.smoothScrollTo(0, editText.getBottom());

Good luck!

祝你好运!