Frage

Ich habe eine sehr lange Aktivität mit einer Scrollview. Es ist ein Formular mit verschiedenen Feldern, die der Benutzer ausfüllen muss. Ich habe ein Kontrollkästchen auf halbem Weg in meinem Formular und wenn der Benutzer es überprüft, möchte ich zu einem bestimmten Teil der Ansicht scrollen. Gibt es eine Möglichkeit, programmgesteuert zu einem EditText -Objekt (oder einem anderen Ansichtsobjekt) zu scrollen?

Ich weiß auch, dass dies mit X- und Y -Koordnungen möglich ist, aber ich möchte dies vermeiden, da sich das Formular vom Benutzer zu dem Benutzer geändert hat.

War es hilfreich?

Lösung

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

Andere Tipps

Die Antwort von Sherif Elkhatib kann erheblich verbessert werden, wenn Sie möchten Scrollen Sie die Ansicht in die Mitte der Bildlaufansicht. Diese wiederverwendbare Methode scrollt die Ansicht auf die sichtbare Mitte einer 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);
        }
    });
}

Für eine vertikale ScrollView ändere das x und y Position der Eingänge von smoothScroll. Und verwenden view.getTop() Anstatt von view.getLeft() und view.getBottom() Anstatt von v.getRight().

:)

Das funktioniert gut für mich:

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

public void RequestChildFocus (View Child, View Focused)

Kind - Das Kind dieses Aussichtspaarigen, das sich konzentrieren will. Diese Ansicht enthält die fokussierte Ansicht. Es ist nicht unbedingt die Ansicht, die tatsächlich den Fokus hat.

fokussiert - Die Ansicht, die ein Nachkomme des Kindes ist, der tatsächlich Fokus hat

Meiner Meinung nach ist der beste Weg, zu einem bestimmten Rechteck zu scrollen View.requestRectangleOnScreen(Rect, Boolean). Sie sollten es auf einem anrufen View Sie möchten ein lokales Rechteck scrollen und übergeben, das Sie auf dem Bildschirm sichtbar sein möchten. Der zweite Parameter sollte sein false zum reibungslosen Scrollen und true zum sofortigen Scrollen.

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

Ich habe eine kleine Versorgungsmethode erstellt, die auf der Antwort von Warrenfaith basiert. Dieser Code berücksichtigt auch, wenn diese Ansicht in der ScrollView bereits sichtbar ist und keine Schriftrolle erforderlich ist.

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

Sie sollten Ihre machen TextView Anfrage Focus:

    mTextView.requestFocus();

Mein EditText war mehrere Ebenen in meiner Scrollview verschachtelt, was selbst nicht die Root -Ansicht des Layouts ist. Da Gettop () und GetBottom () die Koordinaten in seiner Ansicht zu melden schienen, ließ ich die Entfernung vom oberen Rand des Scrollviews bis zum oberen Rand des EditText berechnen, indem sie die Eltern des EditText iterierte.

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

Eine andere Variation wäre:

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

oder Sie können die verwenden post() Methode.

Ich weiß, dass dies für eine bessere Antwort zu spät sein kann, aber eine gewünschte perfekte Lösung muss ein System wie Positionierer sein. Ich meine, wenn das System eine Positionierung für ein Editorfeld macht, platziert es das Feld genau auf die Tastatur, so dass UI/UX regiert, ist es perfekt.

Was unter dem Code macht, ist der Android -Weg, der reibungslos positioniert wird. Erstens halten wir den aktuellen Scrollpunkt als Referenzpunkt. Zweitens ist es, den besten Positionierungs -Scroll -Punkt für einen Editor zu finden. Um dies zu tun, scrollen wir nach oben und fordern Sie dann die Editorfelder an, um die Scrollview -Komponente für die beste Positionierung zu erstellen. Gatcha! Wir haben die beste Position gelernt. Jetzt werden wir von dem vorherigen Punkt bis zu dem Punkt, den wir neu gefunden haben, reibungslos scrollen. Wenn Sie möchten, können Sie ein reibungsloses Scrolling unter Verwendung von Verwendung weglassen Scrollto Anstatt von SmoothScrollto nur.

HINWEIS: Das Hauptcontainer -ScrollView ist ein Mitgliedsfeld namens ScrollViewSignup, da mein Beispiel ein Anmeldebildschirm war, da Sie möglicherweise viel herausfinden.

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

Wenn Sie diesen Block für alle verwenden möchten Text bearbeiten Instanzen und integrieren Sie es schnell in Ihren Bildschirmcode. Sie können einfach einen Traverser wie unten machen. Dazu habe ich das wichtigste Onfocuschangelistener zu einem Mitgliedsfeld genannt FocusChangelistenertoscrolleditor, und rufen Sie es während der OnCreate wie unten an.

traverseEditTextChildren(scrollViewSignup, focusChangeListenerToScrollEditor);

Und die Methode -Implementierung ist wie unten.

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

Wir haben hier also alle EditText -Instanz -Kinder dazu gebracht, den Hörer im Fokus anzurufen.

Um diese Lösung zu erreichen, habe ich sie alle Lösungen hier überprüft und eine neue Lösung für ein besseres UI/UX -Ergebnis generiert.

Many thanks to all other answers inspiring me much.

Hinweis : https://stackoverflow.com/a/6438240/2624806

Die folgenden funktionierten weitaus besser.

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

Die obigen Antworten funktionieren gut, wenn die ScrollView der direkte Elternteil der ChildView ist. Wenn Ihr Childview in eine andere ViewGroup in der ScrollView eingewickelt wird, wird dies zu unerwartetem Verhalten führen, da die Ansicht.gettop () die Position relativ zu seinem übergeordneten Punkt erhalten. In diesem Fall müssen Sie dies implementieren:

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

Ich glaube, ich habe eine elegantere und weniger fehleranfälligere Lösung gefunden

Scrollview.requestChildrectangleOncreen

Es gibt keine Mathematik, und im Gegensatz zu anderen vorgeschlagenen Lösungen wird es sowohl nach oben und unten scrollen.

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

Es ist eine gute Idee, es zu wickeln postDelayed Um es zuverlässiger zu machen, falls die ScrollView wird momentan verändert

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

Meine Lösung ist:

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

Wenn Sie den Android -Quellcode untersuchen, können Sie feststellen, dass es bereits eine Mitgliedsfunktion von gibt ScrollViewscrollToChild(View) - Das tut genau das, was angefordert wird. Unglücklich, diese Funktion ist aus irgendeinem dunklen Grund gekennzeichnet private. Basierend auf dieser Funktion habe ich die folgende Funktion geschrieben, die die erste findet ScrollView über View als Parameter spezifiziert und scrollt es so, dass es innerhalb der sichtbar wird 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;
     }
 }

In meinem Fall ist das nicht EditText, das ist googleMap. Und es funktioniert erfolgreich.

    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: Gibt es eine Möglichkeit, eine Scroll -Ansicht programmgesteuert zu einem bestimmten Bearbeitungspflicht zu scrollen?

ANS: verschachtelte Schriftrollenansicht in Recyclerview Letzte Position hat Datensatzdaten hinzugefügt.

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

Gibt es eine Möglichkeit, eine Scroll -Ansicht programmgesteuert zu einem bestimmten Bearbeitungstext zu scrollen?

Das Folgende ist das, was ich benutze:

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

Dadurch wird die Schriftrollenmenge erforderlich, um den Boden der Ansicht anzuzeigen, einschließlich eines beliebigen Randes am Ende dieser Ansicht.

Vertikale Schriftrolle, gut für Formen. Die Antwort basiert auf der horizontalen Schriftrolle von 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));
        }
    });
}

Sie können verwenden ObjectAnimator so was:

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

Wenn Scrlmain Ihre NestedsCrollView ist, verwenden Sie Folgendes.

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

                    }
                });
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top