Est-il un moyen de faire défiler un défilement de vue spécifique de modifier le texte?

j'ai une très longue activité avec scrollview. C'est un formulaire avec différents champs que l'utilisateur doit remplir. J'ai une case à cocher à mi-chemin dans mon formulaire, et quand l'utilisateur le vérifie, je veux faire défiler vers une partie spécifique de la vue. Y a-t-il un moyen de faire défiler vers un objet EditText (ou tout autre objet view) par programmation?

aussi, je sais que c'est possible en utilisant X et y coords mais je veux éviter de le faire car le formulaire peut changer d'Utilisateur En utilisateur.

149
demandé sur GingerHead 2011-07-26 18:31:54

17 réponses

private final void focusOnView(){
        your_scrollview.post(new Runnable() {
            @Override
            public void run() {
                your_scrollview.scrollTo(0, your_EditBox.getBottom());
            }
        });
    }
359
répondu Sherif elKhatib 2016-08-09 09:05:34

la réponse de Sherif elKhatib peut être grandement améliorée, si vous voulez faites défiler la vue vers le centre de la vue . Cette méthode réutilisable défile la vue vers le centre visible d'une vue horizontale.

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 une verticale ScrollView , remplacer x et y par smoothScroll . Et utilisez view.getTop() au lieu de view.getLeft() et view.getBottom() au lieu de v.getRight() .

:)

48
répondu ahmadalibaloch 2016-12-09 22:17:44

cela fonctionne bien pour moi:

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

public void RequestChildFocus (Vue de l'enfant, Vue axé)

enfant - l'enfant de ce parent qui veut se concentrer. Cette vue contient la vue. Ce n'est pas nécessairement le point de vue qui fait l'objet du débat.

focalisé - le point de vue qui est un descendant de l'enfant qui a effectivement focus

38
répondu Swas_99 2015-08-01 17:37:01

à mon avis, la meilleure façon de faire défiler vers un rectangle donné est via View.requestRectangleOnScreen(Rect, Boolean) . Vous devez appeler un View vous voulez faire défiler et passer un local rectangle vous souhaitez être visible sur l'écran. Le second paramètre doit être false pour le défilement en douceur et true pour le défilement immédiat.

final Rect rect = new Rect(0, 0, view.getWidth(), view.getHeight());
view.requestRectangleOnScreen(rect, false);
18
répondu Michael 2016-04-21 11:54:53

Vous devriez faire de votre TextView demande:

    mTextView.requestFocus();
10
répondu Ovidiu Latcu 2011-07-26 14:49:12

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 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());
            }
        });
    } 
}
9
répondu Tobrun 2017-10-11 14:52:33

mon texte D'édition a été imbriqué plusieurs couches dans mon ScrollView, qui n'est pas en lui-même la vue racine du layout. Parce que getTop() et getBottom () semblaient rapporter les coordonnées dans sa vue contenant, je lui ai demandé de calculer la distance du haut du ScrollView au haut de L'EditText en itérant à travers les parents de L'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();
7
répondu Injured Platypus 2014-08-26 22:18:30

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
répondu Goran Horia Mihail 2014-04-13 07:22:50

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

a suivi a fonctionné beaucoup mieux.

mObservableScrollView.post(new Runnable() {
            public void run() { 
                mObservableScrollView.fullScroll([View_FOCUS][1]); 
            }
        });
1
répondu CoDe 2017-05-23 12:18:25

je pense que j'ai trouvé une solution plus élégante et sujette aux erreurs en utilisant

ScrollView.requestChildRectangleOnScreen

pas de mathématiques impliquées, et contrairement à d'autres solutions proposées, il gérera correctement le défilement des deux côtés, de haut en bas.

/**
 * 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'écharpe en postDelayed pour la rendre plus fiable, dans le cas où le ScrollView est être changé à l'instant

/**
 * 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);
}
1
répondu Štarke 2016-06-27 08:18:16

en examinant le code source Android, vous pouvez trouver 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é comme paramètre et l'effile pour qu'il devienne 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
répondu Jaromír Adamec 2015-08-13 17:10:33

Dans mon cas, ce n'est pas EditText , c'est googleMap . Et ça marche 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
répondu Zin Win Htet 2016-03-15 05:00:54

Que: y a-t-il un moyen de faire défiler programmatiquement une vue de défilement vers un texte d'édition spécifique?

Ans:vue de rouleau emboîté dans recyclerview dernière position ajoutée données d'enregistrement.

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

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

0
répondu Ravi Bhalala 2017-05-23 12:10:41

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
répondu w4kskl 2016-07-26 09:39:23

ce qui suit est 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 le nombre de rouleaux nécessaire pour afficher le bas de la vue, y compris toute marge au bas de cette vue.

0
répondu LukeWaggoner 2016-09-15 06:34:48

rouleau vertical, bon pour les formulaires. La réponse est basée sur le rouleau 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
répondu Qamar 2018-02-07 10:21:59

les réponses ci-dessus fonctionneront très bien si ScrollView est le parent direct de ChildView. Si votre ChildView est enveloppé dans un autre groupe de vue dans le ScrollView, il causera un comportement inattendu parce que la vue.getTop () obtient la position relative à son parent. Dans ce cas, vous devez mettre en œuvre 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));
}
0
répondu Sam Fisher 2018-08-29 04:45:25