Подтвердить что ты не робот

HorizontalScrollView: авто-прокрутка до конца при добавлении новых просмотров?

У меня есть HorizontalScrollView, содержащий LinearLayout. На экране у меня есть кнопка, которая добавит новые представления в LinearLayout во время выполнения, и я бы хотел, чтобы прокрутка просматривала прокрутку до конца списка при добавлении нового представления.

У меня почти все работает - за исключением того, что он всегда прокручивает один вид до последнего представления. Кажется, что он прокручивается без предварительного расчета включения нового представления.

В моем приложении я использую пользовательский объект View, но я сделал небольшое тестовое приложение, которое использует ImageView и имеет тот же самый симптом. Я пробовал различные вещи, такие как requestLayout() как в Layout, так и в ScrollView, я пробовал scrollTo (Integer.MAX_VALUE), и он прокручивался в netherverse:) Я нарушаю проблему с потоком пользовательского интерфейса или что-то в этом роде?

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

Формат 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>
4b9b3361

Ответ 1

Я думаю, что есть проблема времени. Макет не выполняется при добавлении представления. Он запрашивается и выполняется через некоторое время. Когда вы вызываете fullScroll сразу после добавления представления, ширина функции linearlayout не имеет возможности расширяться.

Попробуйте заменить:

s.fullScroll(HorizontalScrollView.FOCUS_RIGHT);

с:

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

Кратковременная задержка должна дать системе достаточно времени для расчета.

P.S. Достаточно просто отложить прокрутку до текущей итерации петли пользовательского интерфейса. Я не тестировал эту теорию, но если это правильно, достаточно было бы сделать следующее:

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

Мне нравится это лучше, потому что введение произвольной задержки кажется мне взломанным (хотя это было мое предложение).

Ответ 2

Я согласен с @monxalo и @granko87 в том, что лучший подход заключается в прослушивании, а не в предположении, что макет будет завершен, если мы допустим некоторое количество времени.

В случае, как и мне, вам не нужно использовать собственный подкласс HorizontalScrollView, вы можете просто добавить OnLayoutChangeListener, чтобы все было просто:

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

Ответ 3

Еще одно предложение, так как этот вопрос мне очень помог:).

Вы можете поместить слушателя, когда представление закончило свою фазу макета, и сразу после выполнения fullScroll, хотя вам нужно расширить класс для этого.

Я сделал это только потому, что мне захотелось перейти к разделу сразу после onCreate(), чтобы избежать мерцания от начальной точки до точки прокрутки.

Что-то вроде:

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

Ответ 4

Используйте метод View smoothScrollTo

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

Вам нужно запустить runnable, чтобы вы выделили время для компоновки, чтобы разместить новый View

Ответ 5

Это то, что я сделал.

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

Ответ 6

Используйте приведенный ниже код для горизонтального прокрутки ( Прокрутить вправо}

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

Ответ 7

Я думаю, что лучший подход - это тот, который был отправлен monxalo, потому что вы не можете знать, сколько времени потребуется, пока макет не будет выполнен. Я попробовал, и он работает отлично. Единственное различие заключается в том, что я добавил только одну строку в свой собственный горизонтальный вид прокрутки:

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

Ответ 8

Ребенок View не может быть немедленно добавлено в ViewGroup. Поэтому необходимо опубликовать Runnable который будет запускаться после выполнения других ожидающих задач.

Итак, после добавления View, используйте:

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

Ответ 9

Это мой способ для 3 ImageViews в 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)