スクロールビューとスクロールビュー内のサブチャイルドを追加しました。ある時点で、特定のビューにスクロールする必要があります。
<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にスクロールする必要があります。
いくつかの提案を提供してください。
スクロールする必要がある子が直接の子でない場合、上記の解決策は機能しません
私は私のプロジェクトで以下のソリューションを使用しましたが、それを共有すると他の人に役立つ可能性があります
/**
* 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);
}
これでうまくいくはずです:
View targetView = findViewById(R.id.DESIRED_VIEW_ID);
targetView.getParent().requestChildFocus(targetView,targetView);
public void RequestChildFocus(子の表示、フォーカスの表示)
child-フォーカスを必要とするこのViewParentの子。このビューには、フォーカスされたビューが含まれます。実際にフォーカスがあるのは、必ずしもビューではありません。
focused-実際にフォーカスを持つ子の子孫であるビュー
これを試して:
_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()
に置き換えることができます
私はよりエレガントでエラーを起こしやすい解決策を見つけたと思う
数学は含まれておらず、他の提案された解決策とは異なり、上下に正しくスクロールを処理します。
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);
}
ちょうどいいですね?
スクロールする必要がある子_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 の詳細
ターゲットビューが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);
}
});
}
ここで、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());
}
つかいます :
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();
}
});
メソッドscrollScrollToを使用して、スクロールビューの特定のビューにスクロールできます。 -例:
my_scroll_View.smoothScrollTo(0, editText.getBottom());
がんばろう!
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をいじることができます)。