web-dev-qa-db-fra.com

Existe-t-il un moyen de faire défiler par programme une vue de défilement vers un texte d'édition spécifique?

J'ai une très longue activité avec un scrollview. Il s'agit d'un formulaire avec différents champs que l'utilisateur doit remplir. J'ai une case à cocher à mi-chemin dans mon formulaire et lorsque l'utilisateur le coche, je souhaite faire défiler une partie spécifique de la vue. Est-il possible de faire défiler un objet EditText (ou tout autre objet vue) par programme?

De plus, 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’un utilisateur à l’autre.

177
NotACleverMan
private final void focusOnView(){
        your_scrollview.post(new Runnable() {
            @Override
            public void run() {
                your_scrollview.scrollTo(0, your_EditBox.getBottom());
            }
        });
    }
411
Sherif elKhatib

La réponse de Sherif elKhatib peut être grandement améliorée si vous voulez faire défiler la vue au centre de la vue de défilement. Cette méthode réutilisable lisse fait défiler la vue jusqu'au 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 les positions 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().

:)

52
ahmadalibaloch

Cela fonctionne bien pour moi:

  targetView.getParent().requestChildFocus(targetView,targetView);

public void RequestChildFocus (Afficher un enfant, Voir ciblé)

enfant - Enfant de ce ViewParent qui veut se concentrer. Cette vue contiendra la vue focalisée. Ce n'est pas nécessairement la vue qui a réellement le focus.

concentré - La vue qui est un descendant d'enfant qui a réellement le focus

46
Swas_99

À mon avis, la meilleure façon de faire défiler un rectangle est de passer par View.requestRectangleOnScreen(Rect, Boolean) . Vous devez l’appeler sur un View pour lequel 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);
24
Michael

J'ai fait une petite méthode utilitaire basée sur Answer de WarrenFaith, ce code prend également en compte si cette vue est déjà visible dans le scrollview, pas besoin de faire défiler.

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());
            }
        });
    } 
}
12
Tobrun

Vous devriez vous concentrer sur la demande TextView:

    mTextView.requestFocus();
10
Ovidiu Latcu

Mon EditText a été imbriqué dans plusieurs couches de mon ScrollView, qui n'est pas la vue racine de la présentation. Parce que getTop () et getBottom () semblaient donner les coordonnées dans la vue qui le contient, je l’ai fait calculer la distance entre le haut de la ScrollView et le haut de EditText en effectuant une itération entre 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();
6
Injured Platypus

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().

4
Goran Horia Mihail

référence: https://stackoverflow.com/a/6438240/2624806

La suite a fonctionné beaucoup mieux.

mObservableScrollView.post(new Runnable() {
            public void run() { 
                mObservableScrollView.fullScroll([View_FOCUS][1]); 
            }
        });
2
CoDe

Les réponses ci-dessus fonctionneront correctement si ScrollView est le parent direct de ChildView. Si votre ChildView est encapsulé dans un autre groupe ViewGroup dans ScrollView, cela provoquera un comportement inattendu, car View.getTop () obtiendra la position relative à 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));
}
2
Sam Fisher

Je pense avoir trouvé une solution plus élégante et moins sujette aux erreurs en utilisant

ScrollView.requestChildRectangleOnScreen

Il n’ya pas de calcul à faire et, contrairement aux autres solutions proposées, le défilement se fera correctement.

/**
 * 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ù la ScrollView serait modifiée 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);
}
2
Štarke

Vous pouvez utiliser ObjectAnimator comme ceci:

ObjectAnimator.ofInt(yourScrollView, "scrollY", yourView.getTop()).setDuration(1500).start();
0
Tazeem Siddiqui

Que: Y a-t-il un moyen de faire défiler par programme une vue de défilement vers un edittext spécifique?

Rép: La vue de défilement imbriquée dans la dernière position de recyclerview a ajouté des données d'enregistrement.

adapter.notifyDataSetChanged();
nested_scroll.setScrollY(more Detail Recycler.getBottom());

Y a-t-il un moyen de faire défiler par programme une vue de défilement vers un texte d'édition spécifique?

0
Ravi Bhalala

Défilement vertical, bon pour les formulaires. La réponse est basée sur le défilement horizontal d’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));
        }
    });
}
0
Qamar

Si scrlMain est votre NestedScrollView, utilisez ce qui suit,

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

                    }
                });
0
Ashwin Balani

En examinant le code source de Android, vous constaterez qu'il existe déjà une fonction membre de ScrollViewscrollToChild(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 du View spécifié en tant que paramètre et le fait défiler pour qu'il soit visible dans le 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;
     }
 }
0
Jaromír Adamec

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 obtient la quantité de défilement nécessaire pour afficher le bas de la vue, y compris les marges situées au bas de cette vue.

0
LukeWaggoner

Ma solution est:

            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]);
0
w4kskl

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);
        }
    });
}
0
Zin Win Htet