2011-01-18 2 views
44

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

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

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

  • Рик

======

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> 

ответ

113

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

Try замена:

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

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

+5

Что это сделал именно Тед, большое спасибо, что это было давало мне покоя в течение нескольких дней! :) –

+0

Спасибо Ted hopp – praveenb

+1

+1 Это помогло мне :) –

12

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

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

Я сделал это только потому, что мне захотелось прокрутиться до раздела сразу после 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); 

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

+0

Hi .. спасибо. этот код очень полезен для меня .. Большое спасибо. – RVG

1

Я думаю, что лучший подход - это тот, который был отправлен 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); 
} 
+0

Я не думаю, что это время. Проблема в том, что прокрутка не должна происходить на текущей итерации цикла потока пользовательского интерфейса. После завершения текущей итерации иерархия представлений должна быть обновлена ​​и выведена. –

2

Использование ниже код для горизонтальной Scrollview {Scroll направо}

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

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

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

Я согласен с @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); 
    } 
}); 
+0

Это решение, которое я тоже придумал. Меньше кода, сделал работу. –

+0

Это, безусловно, правильный ответ на проблему. Ожидание случайного времени - глупость. Ожидание, что механизм компоновки для выполнения своей работы является правильным. – DrAL3X

0

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

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

horizontalScrollView.post(new Runnable() { 
    @Override 
    public void run() { 
     horizontalScrollView.fullScroll(View.FOCUS_RIGHT); 
    } 
}); 
Смежные вопросы