我有一个很长的带有滚动视图的活动。它是一个包含用户必须填写的各种字段的表单。我在表单的中间有一个复选框,当用户选中它时,我想滚动到视图的特定部分。是否有办法以编程方式滚动到EditText对象(或任何其他视图对象)?

此外,我知道这是可能的使用X和Y坐标,但我想避免这样做,因为形式可能会从用户到用户的变化。


当前回答

在我看来,滚动到给定矩形的最好方法是通过视图。requestRectangleOnScreen(矩形、布尔值)。你应该在你想要滚动到的视图上调用它,并传递一个你想要在屏幕上可见的局部矩形。第二个参数在平滑滚动时为假,在即时滚动时为真。

final Rect rect = new Rect(0, 0, view.getWidth(), view.getHeight());
view.requestRectangleOnScreen(rect, false);

其他回答

private final void focusOnView(){
    yourScrollView.post(new Runnable() {
        @Override
        public void run() {
            yourScrollView.scrollTo(0, yourEditText.getBottom());
        }
    });
}
scrollView.post(new Runnable() {
    @Override
    public void run() {
        scrollView.smoothScrollTo(0, myTextView.getTop());
    }
});

回答来自我的实际项目。

如果sclmain是你的NestedScrollView,那么使用以下方法:

scrlMain.post(new Runnable() {
    @Override
    public void run() {
        scrlMain.fullScroll(View.FOCUS_UP);
    }
});

检查Android源代码,你会发现ScrollView已经有一个成员函数scrollToChild(View),它做的正是所请求的。不幸的是,这个函数由于某种模糊的原因被标记为private。在这个函数的基础上,我写了下面的函数,它可以找到指定为参数的视图上方的第一个ScrollView,并滚动它,使它在ScrollView中可见:

 private void make_visible(View view)
 {
  int vt = view.getTop();
  int vb = view.getBottom();

  View v = view;

  for(;;)
     {
      ViewParent vp = v.getParent();

      if(vp == null || !(vp instanceof ViewGroup))
         break;

      ViewGroup parent = (ViewGroup)vp;

      if(parent instanceof ScrollView)
        {
         ScrollView sv = (ScrollView)parent;

         // Code based on ScrollView.computeScrollDeltaToGetChildRectOnScreen(Rect rect) (Android v5.1.1):

         int height = sv.getHeight();
         int screenTop = sv.getScrollY();
         int screenBottom = screenTop + height;

         int fadingEdge = sv.getVerticalFadingEdgeLength();

         // leave room for top fading edge as long as rect isn't at very top
         if(vt > 0)
            screenTop += fadingEdge;

         // leave room for bottom fading edge as long as rect isn't at very bottom
         if(vb < sv.getChildAt(0).getHeight())
            screenBottom -= fadingEdge;

         int scrollYDelta = 0;

         if(vb > screenBottom && vt > screenTop) 
           {
            // need to move down to get it in view: move down just enough so
            // that the entire rectangle is in view (or at least the first
            // screen size chunk).

            if(vb-vt > height) // just enough to get screen size chunk on
               scrollYDelta += (vt - screenTop);
            else              // get entire rect at bottom of screen
               scrollYDelta += (vb - screenBottom);

             // make sure we aren't scrolling beyond the end of our content
            int bottom = sv.getChildAt(0).getBottom();
            int distanceToBottom = bottom - screenBottom;
            scrollYDelta = Math.min(scrollYDelta, distanceToBottom);
           }
         else if(vt < screenTop && vb < screenBottom) 
           {
            // need to move up to get it in view: move up just enough so that
            // entire rectangle is in view (or at least the first screen
            // size chunk of it).

            if(vb-vt > height)    // screen size chunk
               scrollYDelta -= (screenBottom - vb);
            else                  // entire rect at top
               scrollYDelta -= (screenTop - vt);

            // make sure we aren't scrolling any further than the top our content
            scrollYDelta = Math.max(scrollYDelta, -sv.getScrollY());
           }

         sv.smoothScrollBy(0, scrollYDelta);
         break;
        }

      // Transform coordinates to parent:
      int dy = parent.getTop()-parent.getScrollY();
      vt += dy;
      vb += dy;

      v = parent;
     }
 }

你应该使你的TextView请求焦点:

    mTextView.requestFocus();