web-dev-qa-db-ja.com

スクロールビューで特定のビューにスクロールする

スクロールビューとスクロールビュー内のサブチャイルドを追加しました。ある時点で、特定のビューにスクロールする必要があります。

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

上記のレイアウトは動的に作成されました。 xmlファイルをここに投稿することはできません。レイアウトの作成は完全に動的です。 linearlayout内の子ビューの数も異なる場合があります。

したがって、ボタンをクリックすると、特定のビューにスクロールする必要があります。ボタンをクリックすると、リニアレイアウト4にスクロールする必要があります。

いくつかの提案を提供してください。

46
Rajagopal

スクロールする必要がある子が直接の子でない場合、上記の解決策は機能しません

私は私のプロジェクトで以下のソリューションを使用しましたが、それを共有すると他の人に役立つ可能性があります

/**
 * 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);
}
89
Vasanth

これでうまくいくはずです:

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

public void RequestChildFocus(子の表示、フォーカスの表示)

child-フォーカスを必要とするこのViewParentの子。このビューには、フォーカスされたビューが含まれます。実際にフォーカスがあるのは、必ずしもビューではありません。

focused-実際にフォーカスを持つ子の子孫であるビュー

88
Swas_99

これを試して:

_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()はAPIレベル11より下では機能しません。APIレベル11より下では、insideView.getY()insideView.getTop()に置き換えることができます

23
Dev

私はよりエレガントでエラーを起こしやすい解決策を見つけたと思う

ScrollView.requestChildRectangleOnScreen

数学は含まれておらず、他の提案された解決策とは異なり、上下に正しくスクロールを処理します。

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
}

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

ちょうどいいですね?

9
Štarke

スクロールする必要がある子_​​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());

scrollTo および smoothScrollTo の詳細

7
midhunhk

ターゲットビューが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
}

次のように使用します。

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

さらに、フォーカスを設定する場合は、次を実行します。

targetView.requestFocus ();

また、キーボードを表示する場合は、次の操作を行います。

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);
    }
  });
}
1
Peri Hartman

ここで、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());
}
0
ad joy

つかいます :

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();
            }
        }); 
0
Mohammad Javad

メソッドscrollScrollToを使用して、スクロールビューの特定のビューにスクロールできます。 -例:

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

がんばろう!

0
Phuong Pham

Swas_99の 上記の回答 で提案されているように、requestChildFocus()を使用して目的の結果を得ました。

ただし、スムーズなスクロールは行われないため、 requestChildFocus を呼び出すソースコードを調べました。これは scrollToChild を呼び出し、 offsetDescendantRectToMyCoords を呼び出します。そこから、requestChildFocus()を使用した場合と同様の効果をもたらすが、スムーズなスクロールを行う次のC#/ Xamarinコードを使用するというアイデアを得ました。

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

基本的な考え方は、ScrollViewを含むターゲットビューを見つけることです。次に、ターゲットビューの描画四角形を取得し、ScrollViewが認識できるように座標を調整してから、ScrollViewにその位置までスムーズにスクロールするように依頼します。最終的な効果は、スクロールするビューが常に画面の上部近くに完全に表示されることです(代わりに、ビューを画面の中央に配置したい場合はViewRect.Topをいじることができます)。

0
Eric Mutta