J’ai une très longue activité avec une scrollview. C’est un formulaire avec différents champs que l’utilisateur doit remplir. J’ai une case à cocher à mi-chemin de mon formulaire et lorsque l’utilisateur le coche, je veux faire défiler une partie spécifique de la vue. Est-il possible de faire défiler par programme un object EditText (ou tout autre object de vue)?
En outre, je sais que cela est possible en utilisant les coordonnées X et Y, mais je veux éviter de le faire car le formulaire peut changer d’utilisateur à utilisateur.
private final void focusOnView(){ your_scrollview.post(new Runnable() { @Override public void run() { your_scrollview.scrollTo(0, your_EditBox.getBottom()); } }); }
La réponse de Sherif el Khatib peut être grandement améliorée si vous souhaitez faire défiler la vue au centre de la vue de défilement . Cette méthode réutilisable lisse fait défiler la vue vers le centre visible d’un HorizontalScrollView.
private final void focusOnView(final HorizontalScrollView scroll, final View view) { new Handler().post(new Runnable() { @Override public void run() { int vLeft = view.getLeft(); int vRight = view.getRight(); int sWidth = scroll.getWidth(); scroll.smoothScrollTo(((vLeft + vRight - sWidth) / 2), 0); } }); }
Pour un ScrollView
vertical, changez la position x
et y
des entrées de smoothScroll
. Et utilisez view.getTop()
au lieu de view.getLeft()
et view.getBottom()
au lieu de v.getRight()
.
🙂
Cela fonctionne bien pour moi:
targetView.getParent().requestChildFocus(targetView,targetView);
public void RequestChildFocus (Afficher l’enfant, Afficher la vue)
child – L’enfant de ce ViewParent qui veut se concentrer. Cette vue contiendra la vue ciblée. Ce n’est pas nécessairement le sharepoint vue qui a réellement le focus.
focalisé – La vue qui est un descendant de l’enfant qui a réellement le focus
À mon avis, le meilleur moyen de faire défiler un rectangle est d’ View.requestRectangleOnScreen(Rect, Boolean)
. Vous devez l’appeler sur une View
vous souhaitez faire défiler et passer un rectangle local que vous souhaitez voir visible à l’écran. Le deuxième paramètre doit être false
pour un défilement régulier et true
pour un défilement immédiat.
final Rect rect = new Rect(0, 0, view.getWidth(), view.getHeight()); view.requestRectangleOnScreen(rect, false);
Vous devez faire en sorte que votre demande de TextView
axée sur:
mTextView.requestFocus();
J’ai fait une petite méthode utilitaire basée sur la réponse de WarrenFaith, ce code prend également en compte si cette vue est déjà visible dans la vue de défilement, pas besoin de défilement.
public static void scrollToView(final ScrollView scrollView, final View view) { // View needs a focus view.requestFocus(); // Determine if scroll needs to happen final Rect scrollBounds = new Rect(); scrollView.getHitRect(scrollBounds); if (!view.getLocalVisibleRect(scrollBounds)) { new Handler().post(new Runnable() { @Override public void run() { scrollView.smoothScrollTo(0, view.getBottom()); } }); } }
Mon EditText a été nested dans plusieurs couches de mon ScrollView, qui n’est pas la vue racine de la mise en page. Comme getTop () et getBottom () semblaient rapporter les coordonnées dans leur vue contenant, je calculais la distance entre le sumt de ScrollView et le sumt de EditText en parcourant les parents de EditText.
// Scroll the view so that the touched editText is near the top of the scroll view new Thread(new Runnable() { @Override public void run () { // Make it feel like a two step process Utils.sleep(333); // Determine where to set the scroll-to to by measuring the distance from the top of the scroll view // to the control to focus on by summing the "top" position of each view in the hierarchy. int yDistanceToControlsView = 0; View parentView = (View) m_editTextControl.getParent(); while (true) { if (parentView.equals(scrollView)) { break; } yDistanceToControlsView += parentView.getTop(); parentView = (View) parentView.getParent(); } // Compute the final position value for the top and bottom of the control in the scroll view. final int topInScrollView = yDistanceToControlsView + m_editTextControl.getTop(); final int bottomInScrollView = yDistanceToControlsView + m_editTextControl.getBottom(); // Post the scroll action to happen on the scrollView with the UI thread. scrollView.post(new Runnable() { @Override public void run() { int height =m_editTextControl.getHeight(); scrollView.smoothScrollTo(0, ((topInScrollView + bottomInScrollView) / 2) - height); m_editTextControl.requestFocus(); } }); } }).start();
Une autre variante serait:
scrollView.postDelayed(new Runnable() { @Override public void run() { scrollView.smoothScrollTo(0, img_transparent.getTop()); } }, 2000);
ou vous pouvez utiliser la méthode post()
.
référence: https://stackoverflow.com/a/6438240/2624806
La suite a bien mieux fonctionné.
mObservableScrollView.post(new Runnable() { public void run() { mObservableScrollView.fullScroll([View_FOCUS][1]); } });
Je pense que j’ai trouvé une solution plus élégante et sujette à erreur en utilisant
ScrollView.requestChildRectangleOnScreen
Pas de calcul, et contrairement aux autres solutions proposées, il se chargera de faire défiler correctement les deux manières.
/** * Will scroll the {@code scrollView} to make {@code viewToScroll} visible * * @param scrollView parent of {@code scrollableContent} * @param scrollableContent a child of {@code scrollView} whitch holds the scrollable content (fills the viewport). * @param viewToScroll a child of {@code scrollableContent} to whitch will scroll the the {@code scrollView} */ void scrollToView(ScrollView scrollView, ViewGroup scrollableContent, View viewToScroll) { Rect viewToScrollRect = new Rect(); //coordinates to scroll to viewToScroll.getHitRect(viewToScrollRect); //fills viewToScrollRect with coordinates of viewToScroll relative to its parent (LinearLayout) scrollView.requestChildRectangleOnScreen(scrollableContent, viewToScrollRect, false); //ScrollView will make sure, the given viewToScrollRect is visible }
C’est une bonne idée de l’envelopper dans postDelayed
pour le rendre plus fiable, au cas où ScrollView
serait modifié pour le moment.
/** * Will scroll the {@code scrollView} to make {@code viewToScroll} visible * * @param scrollView parent of {@code scrollableContent} * @param scrollableContent a child of {@code scrollView} whitch holds the scrollable content (fills the viewport). * @param viewToScroll a child of {@code scrollableContent} to whitch will scroll the the {@code scrollView} */ private void scrollToView(final ScrollView scrollView, final ViewGroup scrollableContent, final View viewToScroll) { long delay = 100; //delay to let finish with possible modifications to ScrollView scrollView.postDelayed(new Runnable() { public void run() { Rect viewToScrollRect = new Rect(); //coordinates to scroll to viewToScroll.getHitRect(viewToScrollRect); //fills viewToScrollRect with coordinates of viewToScroll relative to its parent (LinearLayout) scrollView.requestChildRectangleOnScreen(scrollableContent, viewToScrollRect, false); //ScrollView will make sure, the given viewToScrollRect is visible } }, delay); }
En examinant le code source Android, vous pouvez constater qu’il existe déjà une fonction membre de ScrollView
– scrollToChild(View)
– qui fait exactement ce qui est demandé. Malheureusement, cette fonction est pour une raison obscure marquée private
. Sur la base de cette fonction, j’ai écrit la fonction suivante qui trouve le premier ScrollView
au-dessus de la View
spécifiée en tant que paramètre et le fait défiler pour qu’il devienne visible dans 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; } }
Dans mon cas, ce n’est pas EditText
, c’est googleMap
. Et cela fonctionne avec succès comme ça.
private final void focusCenterOnView(final ScrollView scroll, final View view) { new Handler().post(new Runnable() { @Override public void run() { int centreX=(int) (view.getX() + view.getWidth() / 2); int centreY= (int) (view.getY() + view.getHeight() / 2); scrollView.smoothScrollBy(centreX, centreY); } }); }
Que: Y a-t-il un moyen de faire défiler par programme une vue déroulante vers un edittext spécifique?
Ans: L’affichage de défilement nested dans la dernière position de la liste de recyclage a ajouté des données d’enregistrement.
adapter.notifyDataSetChanged(); nested_scroll.setScrollY(more Detail Recycler.getBottom());
Existe-t-il un moyen de faire défiler par programme une vue de défilement vers un texte de modification spécifique?
Ma solution est la suivante:
int[] spinnerLocation = {0,0}; spinner.getLocationOnScreen(spinnerLocation); int[] scrollLocation = {0, 0}; scrollView.getLocationInWindow(scrollLocation); int y = scrollView.getScrollY(); scrollView.smoothScrollTo(0, y + spinnerLocation[1] - scrollLocation[1]);
Voici ce que j’utilise:
int amountToScroll = viewToShow.getBottom() - scrollView.getHeight() + ((LinearLayout.LayoutParams) viewToShow.getLayoutParams()).bottomMargin; // Check to see if scrolling is necessary to show the view if (amountToScroll > 0){ scrollView.smoothScrollTo(0, amountToScroll); }
Cela permet d’obtenir la quantité de défilement nécessaire pour afficher le bas de la vue, y compris toute marge au bas de cette vue.
Défilement vertical, bon pour les formulaires. La réponse est basée sur le défilement horizontal Ahmadalibaloch.
private final void focusOnView(final HorizontalScrollView scroll, final View view) { new Handler().post(new Runnable() { @Override public void run() { int top = view.getTop(); int bottom = view.getBottom(); int sHeight = scroll.getHeight(); scroll.smoothScrollTo(0, ((top + bottom - sHeight) / 2)); } }); }
Les réponses ci-dessus fonctionnent correctement si ScrollView est le parent direct de ChildView. Si votre ChildView est encapsulée dans un autre ViewGroup dans ScrollView, cela entraînera un comportement inattendu car View.getTop () obtient la position par rapport à son parent. Dans ce cas, vous devez implémenter ceci:
public static void scrollToInvalidInputView(ScrollView scrollView, View view) { int vTop = view.getTop(); while (!(view.getParent() instanceof ScrollView)) { view = (View) view.getParent(); vTop += view.getTop(); } final int scrollPosition = vTop; new Handler().post(() -> scrollView.smoothScrollTo(0, scrollPosition)); }