Question

J'ai une activité très longue avec un scrollview. Il est une forme avec les différents champs que l'utilisateur doit remplir. J'ai une demi-case en bas ma forme, et lorsque les contrôles utilisateur Je veux faire défiler à une partie spécifique de la vue. Est-il possible de faire défiler jusqu'à un objet EditText (ou tout autre objet de vue) programme?

Aussi, je sais que cela est possible en utilisant coords X et Y, mais je veux éviter de faire ce que la forme peut changer d'un utilisateur à l'utilisateur.

Était-ce utile?

La solution

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

Autres conseils

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 rouleaux lisse la vue sur 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 changement de ScrollView vertical, la position de x et y des entrées de smoothScroll. Et l'utilisation 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);

RequestChildFocus public void (Voir enfant, Voir concentré)

enfant - L'enfant de ce ViewParent qui veut se concentrer. Ce point de vue contiendra la vue ciblée. Il est pas nécessairement le point de vue qui a effectivement mise au point.

concentré - Le point de vue qui est un descendant de l'enfant qui a fait mise au point

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

final Rect rect = new Rect(0, 0, view.getWidth(), view.getHeight());
view.requestRectangleOnScreen(rect, false);

J'ai fait une petite méthode utilitaire fonction de la réponse de WarrenFaith, ce code prend également en compte si ce point de vue est déjà visible dans le scrollview, 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());
            }
        });
    } 
}

Vous devez faire votre demande de mise au point de TextView:

    mTextView.requestFocus();

Mon EditText a été imbriqué plusieurs couches dans mon ScrollView, qui est lui-même pas la vue racine de la mise en page. Parce que GetTop () et getBottom () ont été Semblant signaler les coordonnées au sein de son contenant vue, je l'avais calculer la distance du haut du ScrollView au sommet de la EditText par Itère les parents du 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 varition serait:

scrollView.postDelayed(new Runnable()
{
    @Override
    public void run()
    {
        scrollView.smoothScrollTo(0, img_transparent.getTop());
    }
}, 2000);

ou vous pouvez utiliser la méthode post().

Je sais que cela peut être trop tard pour une meilleure réponse, mais une solution parfaite souhaitée doit être un système comme positionneur. Je veux dire, lorsque le système fait un positionnement pour un champ éditeur, il place le champ juste en haut du clavier, de façon UI / UX règles, il est parfait.

Qu'est-ce que le code ci-dessous marques de est la façon dont Android positionnement en douceur. Tout d'abord, nous gardons le point de défilement actuel comme point de référence. La deuxième chose est de trouver le meilleur point de défilement de positionnement pour un éditeur, pour ce faire, nous défiler vers le haut, puis demander les champs de l'éditeur pour faire le composant ScrollView pour faire le meilleur positionnement. Gatcha! Nous avons appris la meilleure position. Maintenant, ce que nous allons faire est défiler en douceur du point précédent au point que nous avons trouvé récemment. Si vous voulez, vous pouvez omettre le défilement régulier en utilisant scrollTo au lieu de smoothScrollTo uniquement.

NOTE:. Le conteneur principal ScrollView est un champ nommé membre scrollViewSignup, parce que mon exemple était un écran d'inscription, que vous pouvez trouver beaucoup

view.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(final View view, boolean b) {
            if (b) {
                scrollViewSignup.post(new Runnable() {
                    @Override
                    public void run() {
                        int scrollY = scrollViewSignup.getScrollY();
                        scrollViewSignup.scrollTo(0, 0);
                        final Rect rect = new Rect(0, 0, view.getWidth(), view.getHeight());
                        view.requestRectangleOnScreen(rect, true);

                        int new_scrollY = scrollViewSignup.getScrollY();
                        scrollViewSignup.scrollTo(0, scrollY);
                        scrollViewSignup.smoothScrollTo(0, new_scrollY);
                    }
                });
            }
        }
    });

Si vous voulez utiliser ce bloc pour tous EditText instances et intégrer rapidement avec votre code d'écran. Vous pouvez tout simplement faire un transbordeur comme ci-dessous. Pour ce faire, je l'ai fait la principale OnFocusChangeListener un champ membre nommé focusChangeListenerToScrollEditor , et l'appeler pendant onCreate comme ci-dessous.

traverseEditTextChildren(scrollViewSignup, focusChangeListenerToScrollEditor);

Et la mise en œuvre de la méthode est comme ci-dessous.

private void traverseEditTextChildren(ViewGroup viewGroup, View.OnFocusChangeListener focusChangeListenerToScrollEditor) {
    int childCount = viewGroup.getChildCount();
    for (int i = 0; i < childCount; i++) {
        View view = viewGroup.getChildAt(i);
        if (view instanceof EditText)
        {
            ((EditText) view).setOnFocusChangeListener(focusChangeListenerToScrollEditor);
        }
        else if (view instanceof ViewGroup)
        {
            traverseEditTextChildren((ViewGroup) view, focusChangeListenerToScrollEditor);
        }
    }
}

Alors, ce que nous avons fait ici est fait tous les enfants d'instance de EditText appeler l'auditeur au foyer.

Pour arriver à cette solution, je l'ai vérifié toutes les solutions ici, et a généré une nouvelle solution pour un meilleur résultat UI / UX.

Many thanks to all other answers inspiring me much.

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

Suite à beaucoup mieux travaillé.

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

Les réponses ci-dessus fonctionnera bien si le ScrollView est le parent direct du ChildView. Si votre ChildView est enveloppé dans un autre ViewGroup dans le ScrollView, il provoque un comportement inattendu parce que le View.getTop () obtenir 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));
}

Je pense que je l'ai trouvé plus élégant et moins d'erreurs solution sujette à l'aide

ScrollView.requestChildRectangleOnScreen

Il n'y a pas de mathématiques impliqués, et contrairement à d'autres solutions proposées, il traitera correctement le défilement à la fois vers le haut et vers le 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
}

Il est une bonne idée de l'envelopper dans postDelayed pour le rendre plus fiable, dans le cas où la ScrollView est en cours de modification au 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);
}

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

Examiner le code source Android, vous pouvez trouver qu'il existe déjà une fonction de membre de ScrollView- scrollToChild(View) - qui fait exactement ce qui est demandé. Unfortunatelly, cette fonction est pour une raison obscure private marquée. Sur la base de cette fonction que j'ai écrit la fonction suivante qui trouve la première ScrollView au-dessus du View spécifié en tant que paramètre et défile 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;
     }
 }

Dans mon cas, ce n'est pas EditText, qui est googleMap. Et cela fonctionne comme avec succès cela.

    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: Est-il possible de faire défiler une vue de programmation à un défilement edittext spécifique

Réponse:. Nested point de vue en recyclerview dernière position ajoutée données d'enregistrement

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

Est-il possible de faire défiler une vue de programmation défilement à un texte d'édition spécifique?

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);
}

obtient la quantité de défilement nécessaire pour afficher le fond de la vue, y compris toute marge sur le fond de ce point de vue.

défilement vertical, bon pour les formes. Réponse est basée sur Ahmadalibaloch défilement horizontal.

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));
        }
    });
}

Vous pouvez utiliser ObjectAnimator comme ceci:

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

Si scrlMain est votre NestedScrollView, utilisez ce qui suit,

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

                    }
                });
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top