2011-01-18 6 views
44

LinearLayout이 포함 된 HorizontalScrollView가 있습니다. 화면에는 런타임시 LinearLayout에 새 뷰를 추가하는 Button이 있으며 새로운 뷰가 추가되면 스크롤 뷰가 목록의 끝으로 스크롤되도록하고 싶습니다.HorizontalScrollView : 새로운보기가 추가되면 자동 스크롤을 끝내시겠습니까?

저는 거의 모든 것이 작동합니다. 단, 항상 마지막 뷰의 짧은 뷰를 스크롤합니다. 새로운 시각의 포함을 먼저 계산하지 않고 스크롤하는 것처럼 보입니다.

내 응용 프로그램에서 사용자 지정보기 개체를 사용하고 있지만 ImageView를 사용하고 동일한 증상이있는 작은 테스트 응용 프로그램을 만들었습니다. requestLayout() 같은 레이아웃 및 ScrollView, 시도한 scrollTo (Integer.MAX_VALUE) 및 netherverse 스크롤 한 같은 여러 가지 시도 : UI 스레드 문제 또는 뭔가 위반 있습니까?

======

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> 

답변

113

내가 타이밍 문제가 있다고 생각. 보기가 추가되면 레이아웃이 완료되지 않습니다. 잠시 후 요청되고 완료됩니다. 뷰를 추가 한 직후 fullScroll을 호출하면 선형 레이아웃의 너비가 확장 될 기회가 없습니다. 교체

시도 :와

s.fullScroll(HorizontalScrollView.FOCUS_RIGHT); 

:

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

짧은 지연이 시스템을 정착 할 수있는 충분한 시간을 제공해야합니다.

P. UI 루프의 현재 반복 이후까지 스크롤링을 지연시키는 것으로 충분할 수 있습니다. 나는이 이론을 테스트하지 않은,하지만 맞다 경우, 다음을 수행 할 수있는 충분한 것 :

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

내가 좋아하는이 더 나은 (내 제안에도 불구하고) 임의의 지연을 도입하는 것은 나에게 해키 보인다 때문이다.

+5

는, 덕분에 아주 많이, 그 일을 위해 나를 귀찮게되었습니다! 그때 그것을 보여주는 오류가 방법 'postDelayed (긴 인 java.lang.Runnable을)'해결할 수 위의 코드를 사용하려고 할 때 : –

+0

감사 테드 hopp – praveenb

+1

일이 .... 나 : –

12

그냥 다른 sugestion,이 질문은 나를 도왔습니다 :).

뷰가 레이아웃 단계를 완료하면 리스너를 넣을 수 있습니다. 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

당신은 당신이 새로운보기의 위치를 ​​배치 프로세스 시간을 줄 수 있도록 실행 가능한에 둘 필요가보기 방법 smoothScrollTo

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

를 사용

+0

안녕 .. 고마워. 이 코드는 나를 위해 매우 유용합니다 .. 많이 고마워요. – RVG

1

나는 가장 좋은 방법은 당신이 레이아웃이 완료 될 때까지 그 정도의 시간이 소요되는지 알 수 없기 때문에 monxalo에 의해 게시 하나라고 생각합니다. 나는 그것을 시도하고 완벽하게 작동합니다.

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

나는 시간의 양이 적절하다고 생각하지 않는다. 문제는 UI 스레드 루프의 현재 반복에서 스크롤이 발생하지 않아야한다는 것입니다. 현재 반복이 완료되면 뷰 계층 구조가 최신 상태로 유지되어야합니다. –

2

사용 : 유일한 차이점은 내가 내 사용자 지정 가로 스크롤 뷰에 하나 개의 행을 추가 한이다 .

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

이 내가 무슨 짓을 수평있는 ScrollView {바로에 스크롤}에 대한 코드 아래

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

나는 @monxalo하고 @ granko87 더 나은 접근 방식 대신에 우리는 시간의 통과의 어떤 임의의 양을 할 경우 레이아웃이 완료 될 것이라고 가정을 만드는 리스너 것을 동의합니다. View 즉시 ViewGroup에 추가 할 수 없습니다

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

아이 :

경우, 나처럼, 당신은 그냥 간단하게하기 위해 OnLayoutChangeListener을 추가 할 수 있습니다 사용자 정의 HorizontalScrollView 서브 클래스를 사용할 필요가 없습니다 . 그래서이 보류중인 다른 작업을 완료 한 후에 실행하는 Runnable 게시해야합니다. 그래서 View를 추가 한 후

는 사용 정확히 테드을했다

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