可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
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.
Please provide some suggestions.
回答1:
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)
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.
focused - The view that is a descendant of child that actually has focus
回答2:
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);
}
回答3:
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()
回答4:
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?
回答5:
Since you can know the child LinearLayout
that you need to scroll to, how about trying this.
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 scrollTo as well as smoothScrollTo
回答6:
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);
}
});
}
回答7:
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();
}
});
回答8:
I got the desired result using requestChildFocus() as suggested by Swas_99's answer above.
However since it doesn't do smooth scrolling, I looked into the source code for requestChildFocus which calls scrollToChild which 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:
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).
回答9:
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());
}
回答10:
You can use method smoothScrollTo to scroll to specific view in scroll view.
- Example:
my_scroll_View.smoothScrollTo(0, editText.getBottom());
Good luck!
回答11:
Try to call view.requestFocus()
on the view you want to scroll to.