webentwicklung-frage-antwort-db.com.de

HorizontalScrollView: automatischer Bildlauf, um zu beenden, wenn neue Ansichten hinzugefügt werden?

Ich habe eine HorizontalScrollView, die ein LinearLayout enthält. Auf dem Bildschirm habe ich eine Schaltfläche, mit der dem LinearLayout zur Laufzeit neue Ansichten hinzugefügt werden, und ich möchte, dass die Bildlaufansicht bis zum Ende der Liste blättert, wenn eine neue Ansicht hinzugefügt wird.

Ich habe es fast zum Laufen gebracht - außer, dass immer eine Ansicht kurz vor der letzten Ansicht gescrollt wird. Es scheint, als würde es scrollen, ohne vorher die Einbeziehung der neuen Ansicht zu berechnen.

In meiner App verwende ich ein benutzerdefiniertes View-Objekt, aber ich habe eine kleine Testanwendung erstellt, die ImageView verwendet und das gleiche Symptom aufweist. Ich habe verschiedene Dinge wie requestLayout () sowohl für das Layout als auch für ScrollView ausprobiert, ich habe scrollTo (Integer.MAX_VALUE) ausprobiert und in die Nethergegend gescrollt :) Bin ich gegen ein UI-Thread-Problem oder etwas?

  • Rick

======

    public class Main extends Activity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);

             Button b = (Button) findViewById(R.id.addButton);
             b.setOnClickListener(new AddListener());

             add();
        }

        private void add() {
             LinearLayout l = (LinearLayout) findViewById(R.id.list);
             HorizontalScrollView s = 
                 (HorizontalScrollView) findViewById(R.id.scroller);

             ImageView i = new ImageView(getApplicationContext());
             i.setImageResource(Android.R.drawable.btn_star_big_on);
             l.addView(i);

             s.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
        }

        private class AddListener implements View.OnClickListener {
             @Override
             public void onClick(View v) {
                 add();
             }
        }
    }

Layout XML:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
        Android:orientation="vertical"
        Android:layout_width="fill_parent"
        Android:layout_height="fill_parent">

        <HorizontalScrollView
            Android:id="@+id/scroller"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:scrollbarSize="50px">
            <LinearLayout
                Android:id="@+id/list"
                Android:layout_width="wrap_content"
                Android:layout_height="wrap_content"
                Android:padding="4px"/>
        </HorizontalScrollView>

        <LinearLayout
            Android:layout_width="fill_parent"
            Android:layout_height="fill_parent"            
            Android:layout_gravity="center">
            <Button
                Android:id="@+id/addButton"
                Android:layout_width="wrap_content"
                Android:layout_height="wrap_content"
                Android:layout_gravity="center"
                Android:paddingLeft="80px"
                Android:paddingRight="80px"
                Android:paddingTop="40px"
                Android:paddingBottom="40px"
                Android:text="Add"/>
        </LinearLayout>

    </LinearLayout>
49
Rick Barkhouse

Ich denke, es gibt ein Timing-Problem. Das Layout wird nicht erstellt, wenn eine Ansicht hinzugefügt wird. Es wird kurz danach angefordert und ausgeführt. Wenn Sie fullScroll unmittelbar nach dem Hinzufügen der Ansicht aufrufen, konnte die Breite des linearen Layouts nicht erweitert werden.

Versuchen Sie es zu ersetzen:

s.fullScroll(HorizontalScrollView.FOCUS_RIGHT);

mit:

s.postDelayed(new Runnable() {
    public void run() {
        s.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
    }
}, 100L);

Die kurze Verzögerung sollte dem System genügend Zeit geben, sich zu beruhigen.

P.S. Es kann ausreichend sein, den Bildlauf einfach bis nach der aktuellen Iteration der Benutzeroberflächenschleife zu verzögern. Ich habe diese Theorie nicht getestet, aber wenn sie richtig ist, reicht es aus, folgendes zu tun:

s.post(new Runnable() {
    public void run() {
        s.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
    }
});

Ich mag das besser, weil die Einführung einer willkürlichen Verzögerung mir hackig erscheint (obwohl es mein Vorschlag war).

124
Ted Hopp

Ich stimme mit @monxalo und @ granko87 überein, dass der bessere Ansatz bei einem Zuhörer ist, anstatt davon auszugehen, dass das Layout vollständig ist, wenn ein beliebiger Zeitraum vergeht.

Wenn Sie wie ich keine benutzerdefinierte HorizontalScrollView-Unterklasse verwenden müssen, können Sie einfach einen OnLayoutChangeListener hinzufügen, um die Dinge einfach zu halten:

mTagsScroller.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
    @Override
    public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        mTagsScroller.removeOnLayoutChangeListener(this);
        mTagsScroller.fullScroll(View.FOCUS_RIGHT);
    }
});
15
Newtz

Nur ein weiterer Vorschlag, da mir diese Frage sehr geholfen hat :).

Sie können einen Listener setzen, wenn die Ansicht ihre Layoutphase abgeschlossen hat, und direkt nach dem Ausführen von fullScroll müssen Sie die Klasse dafür erweitern.

Ich habe das nur gemacht, weil ich direkt nach onCreate () zu einem Abschnitt scrollen wollte, um das Flimmern vom Startpunkt zum Scrollpunkt zu vermeiden.

So etwas wie:

public class PagerView extends HorizontalScrollView {

    private OnLayoutListener mListener;
    ///...
    private interface OnLayoutListener {
        void onLayout();
    }

    public void fullScrollOnLayout(final int direction) {
        mListener = new OnLayoutListener() {            
            @Override
            public void onLayout() {
                 fullScroll(direction)
                 mListener = null;
            }
        };
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if(mListener != null)
             mListener.onLayout();
    }
}
12
monxalo

Verwenden Sie die View-Methode smoothScrollTo

postDelayed(new Runnable() {
    public void run() {
       scrollView.smoothScrollTo(newView.getLeft(), newView.getTop());
 }
 }, 100L);

Sie müssen eine ausführbare Tabelle einfügen, um dem Layoutprozess Zeit zu geben, um die neue Ansicht zu positionieren

4

Das habe ich getan.

//Observe for a layout change    
ViewTreeObserver viewTreeObserver = yourLayout.getViewTreeObserver();
   if (viewTreeObserver.isAlive()) {
     viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                yourHorizontalScrollView.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
            }
     });
   }
3
Arst

Verwenden Sie den folgenden Code für die horizontale Bildlaufansicht { nach rechts scrollen

view.post(new Runnable() {
                @Override
                public void run() {
                    ((HorizontalScrollView) Iview
                            .findViewById(R.id.hr_scroll))
                            .fullScroll(HorizontalScrollView.FOCUS_RIGHT);
                }
            });
2
sharma_kunal

Ich denke, der beste Ansatz ist der von monxalo, weil man nicht wissen kann, wie lange es dauern wird, bis das Layout fertig ist. Ich habe es ausprobiert und es funktioniert perfekt. Der einzige Unterschied ist, dass ich meiner benutzerdefinierten horizontalen Bildlaufansicht nur eine Zeile hinzugefügt habe:

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    super.onLayout(changed, l, t, r, b);
    this.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
}
1
granko87

Das Kind View kann nicht sofort in eine ViewGroup eingefügt werden. Es ist daher erforderlich, eine Runnable zu posten, die ausgeführt wird, nachdem andere ausstehende Aufgaben abgeschlossen wurden.

Nachdem Sie View hinzugefügt haben, verwenden Sie:

horizontalScrollView.post(new Runnable() {
    @Override
    public void run() {
        horizontalScrollView.fullScroll(View.FOCUS_RIGHT);
    }
});
0
Nabin Bhandari

Dies ist mein Weg für 3 ImageViews in Kotlin:

var p1 = true; var p2 = false; var p3 = false
val x = -55
val handler = Handler()
handler.postDelayed(object : Runnable {
    override fun run() {

        if (p1){
            mainView.picsScrollViewID.smoothScrollTo(mainView.bigPic1ID.x.toInt() + x, 0)
            p1 = false
            p2 = true
            p3 = false
        }
        else if(p2){
            mainView.picsScrollViewID.smoothScrollTo(mainView.bigPic2ID.x.toInt() + x, 0)
            p1 = false
            p2 = false
            p3 = true
        }
        else if(p3){
            mainView.picsScrollViewID.smoothScrollTo(mainView.bigPic3ID.x.toInt() + x, 0)
            p1 = true
            p2 = false
            p3 = false
        }
        handler.postDelayed(this, 2000)
    }
}, 1400)
0
Gabriel