Domanda

Ho una lunga attività con uno ScrollView. Si tratta di un modulo con vari campi che l'utente deve compilare. Ho una casella di controllo a metà strada lungo la mia forma, e quando i controlli utente che voglio per scorrere fino a una parte specifica della vista. Esiste un modo per spostarsi su un oggetto EditText (o qualsiasi altro oggetto vista) di programmazione?

Inoltre, so che questo è possibile utilizzando X e Y coordinate ma voglio evitare di fare questo come la forma può cambiare da utente a utente.

È stato utile?

Soluzione

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

Altri suggerimenti

La risposta di Sherif elKhatib può essere notevolmente migliorata, se si desidera scorrere la vista al centro della vista di scorrimento . Questo metodo riutilizzabile liscia scorre la vista al centro visibile di una 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);
        }
    });
}

Per un cambiamento ScrollView verticale della posizione x e y degli ingressi di smoothScroll. E l'uso view.getTop() invece di view.getLeft() e view.getBottom() invece di v.getRight().

:)

Questo funziona bene per me:

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

RequestChildFocus public void (Bambini, Vista focalizzata)

bambina - Il figlio di questo ViewParent che vuole attenzione. Questo punto di vista conterrà la vista concentrata. Non è necessariamente l'opinione che ha effettivamente messa a fuoco.

focalizzata - Il punto di vista che è un discendente di bambino che ha in realtà messa a fuoco

A mio parere il modo migliore per scorrere fino a un dato rettangolo è tramite View.requestRectangleOnScreen(Rect, Boolean) . Si dovrebbe chiamare su un View si desidera scorrere e superare un rettangolo locale che si desidera essere visibile sullo schermo. Il secondo parametro dovrebbe essere false per scorrimento continuo e true per lo scorrimento immediato.

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

Ho fatto un piccolo metodo di utilità in base alla risposta da WarrenFaith, questo codice prende anche in considerazione se questo punto di vista è già visibile nella ScrollView, senza bisogno di scorrimento.

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

Si dovrebbe fare la vostra attenzione richiesta TextView:

    mTextView.requestFocus();

Il mio EditText stato annidato diversi strati all'interno del mio ScrollView, che di per sé non è vista principale del layout. Perché getTop () e getBottom () sono stati sembrava riferire le coordinate all'interno del suo contenente vista, l'ho avuto calcolare la distanza dalla parte superiore della ScrollView alla parte superiore della EditText scorrendo i genitori del 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();

Un altro varition potrebbe essere:

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

oppure è possibile utilizzare il metodo post().

So che questo potrebbe essere troppo tardi per una risposta migliore, ma una soluzione perfetta desiderata deve essere un sistema come posizionatore. Cioè, quando il sistema effettua una posizionamento per un campo Editor pone il campo solo fino alla tastiera, così come governa UI / UX è perfetta.

Che cosa rende il codice qui sotto è il modo in cui Android posizionamento senza intoppi. Prima di tutto abbiamo mantenere il punto di scorrimento corrente come punto di riferimento. Seconda cosa è di trovare il miglior punto di posizionamento di scorrimento per un editore, per fare questo ci Scorrere verso l'alto, e quindi richiedere i campi dell'editor per rendere la componente ScrollView di fare il miglior posizionamento. Gatcha! Abbiamo imparato la posizione migliore. Ora, quello che faremo è di scorrimento senza intoppi dal punto precedente al punto che abbiamo trovato di recente. Se si vuole si può omettere Smooth scrolling utilizzando scrollTo al posto di smoothScrollTo solo.

. NOTA: Il contenitore principale ScrollView è un campo membro denominato scrollViewSignup, perché il mio esempio è stato uno schermo di iscrizione, come si può capire un sacco

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

Se si desidera utilizzare questo blocco per tutti i EditText le istanze, e rapidamente integrarlo con il codice dello schermo. Si può semplicemente fare un traverser come qui di seguito. Per fare questo, ho fatto l'OnFocusChangeListener principale un campo membro denominato focusChangeListenerToScrollEditor , e lo chiamo durante onCreate come di seguito.

traverseEditTextChildren(scrollViewSignup, focusChangeListenerToScrollEditor);

E l'implementazione del metodo è la seguente.

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

Quindi, quello che abbiamo fatto qui sta facendo tutti i bambini delle istanze EditText per chiamare l'ascoltatore a fuoco.

Per raggiungere questa soluzione, ho controllato fuori tutte le soluzioni qui, e ha generato una nuova soluzione per un risultato migliore UI / UX.

Many thanks to all other answers inspiring me much.

di riferimento: https://stackoverflow.com/a/6438240/2624806

In seguito ha lavorato molto meglio.

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

Le risposte di cui sopra funziona bene se lo ScrollView è il genitore diretto del ChildView. Se il vostro ChildView viene avvolto in un altro ViewGroup nel ScrollView, causerà un comportamento imprevisto perché il View.getTop () ottiene la posizione relativa al suo genitore. In tal caso, è necessario implementare questo:

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

Credo di aver trovato più elegante e meno errori soluzione inclini utilizzando

ScrollView.requestChildRectangleOnScreen

Non c'è matematica coinvolta, e contrariamente alle altre soluzioni proposte, sarà gestire correttamente lo scorrimento sia su e giù.

/**
 * 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
}

E 'una buona idea per avvolgere in postDelayed per renderlo più affidabile, nel caso in cui il ScrollView viene cambiata in questo momento

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

La mia soluzione è:

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

Esaminando il codice sorgente di Android, è possibile trovare che ci sia già una funzione di membro di ScrollView scrollToChild(View)- - che fa esattamente ciò che viene richiesto. Purtroppo, questa funzione è per qualche oscura ragione segnato private. Sulla base di quella funzione che ho scritto seguente funzione che trova il primo ScrollView al di sopra del View specificato come parametro e scorre in modo che esso diventa visibile all'interno del 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;
     }
 }

Nel mio caso, che non è EditText, che è googleMap. E funziona con successo in questo modo.

    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:? C'è un modo per programmazione scorrere una vista di scorrimento per una specifica EditText

Ans:. Guarda nidificati di scorrimento in recyclerview ultima posizione aggiunto registrano i dati

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

c'è un modo per scorrere una vista a livello di codice di scorrimento per un testo specifico di modifica?

Di seguito è quello che sto usando:

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

Questo ottiene la quantità di scorrimento necessari per evidenziare la parte inferiore della vista, tra cui alcun margine sul fondo di questa tesi.

di scorrimento verticale, buona per le forme. Risposta si basa su Ahmadalibaloch di scorrimento orizzontale.

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

È possibile utilizzare ObjectAnimator in questo modo:

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

Se è la vostra scrlMain NestedScrollView, quindi utilizzare il seguente,

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

                    }
                });
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top