2012-08-03 9 views
52

ViewPagerでアクティビティがあり、たくさんの写真が表示されます。起動時に、ViewPagerの位置は、前のアクティビティでユーザが選択した内容に基づいて設定されます。ギャラリーに似ています。setCurrentItem(0)を呼び出すときにonPageSelectedがトリガされない

新しいページが選択されるたびに、つまりアクティビティが最初に開かれたとき、またはユーザーが新しいページにスライドするときに、onPageSelectedを呼び出す必要があります。

私のような出発点を設定するので:

mPager.setCurrentItem(index); 

すべてがこのように0に設定されたインデックスと呼ばれるsetCurrentItemがonPageSelectedをトリガしないときを除き、動作します。

mPager.setOnPageChangeListener(new OnPageChangeListener() { 
    @Override 
    public void onPageSelected(int index) { 
    Log.d(TAG, "onPageSelected " + index); 
    } 
    ... 
} 

私の質問は次のとおりです。これはバグですか、もしそうなら、私はそれについて何ができますか?

答えて

60

私がこれまでに発見したクリーンな解決策は、私はしませんので、あなたは(ViewPagerに設定onPageChangeListenerへの参照を取ることですあなたはViewPagerのアダプタを設定した後、後に、)ViewPager.getOnPageChangeListener()メソッドがあると思う、呼び出し:

onPageChangeListener.onPageSelected(viewPager.getCurrentItem()); 

しかし、現在のインデックスでのページのフラグメントがで(まだインスタンス化されていません。少なくともFragmentStatePagerAdapterを使用している場合)、ラップする必要があります実行可能な、ALAに:

また
viewPager.post(new Runnable(){ 
@Override 
    public void run() { 
     onPageChangeListener.onPageSelected(viewPager.getCurrentItem()); 
    } 
}); 

、onPageSelectedハンドラ内で使用すると、フラグメントへの参照が必要な場合、あなたはそれを自分で行う必要があるでしょう。私はインスタンス化メソッドと破壊メソッドをオーバーライドし、SparseArrayからフラグメントを追加/削除するFragmentStatePagerAdapterの抽象基本クラスを使用します。

+2

runnableを投稿するだけの秘密のソースです。私は、onPageSelected呼び出しをトリガする前にviewPagerのビューが既にインスタンス化されていることを確認する必要がありました。ニース! – RobP

+0

パーフェクト。最後に私はこの回答を見つけた – flosk8

+0

間違いなく正しい答え – Juvi

1

onPageSelectedは、最初に開いたページに対してはトリガされません。この場合、必要なすべての操作を手動で実行します。また、onPageSelected(0)への呼び出しもうまくいくはずです。

+0

まあ、ページが最初のものでない場合、つまり、最初に開かれたページにトリガされます。私はそれが奇妙に聞こえることを知っていますが、それが私の質問の理由です。 – jpihl

+1

'onPageSelected()'をトリガすると、NullPointerが発生する可能性があります。 – bluewhile

33

これはバグ(または機能)かどうかを確認できませんでした。しかし、私は問題の可能な解決策がどのように見えるかを分かち合いたいと思った。

アクティビティのメソッドで実行したい機能を記述し、onPageSelectedメソッドでこれを呼び出す。

mPager.setOnPageChangeListener(new OnPageChangeListener() { 
    @Override 
    public void onPageSelected(int index) { 
     myOnPageSelectedLogic(index); 
    } 
    ... 
} 

そして右の活動で

setCurrentItem(index); 

を呼び出した後、声明

if(index == 0) { 
    myOnPageSelectedLogic(0); 
} 

場合には、超きれいではありませんが、私はそれが誰か:)

+0

いいです..私はあなたのトリックが好きです...私の側から+1投票:) –

+0

そして、私はfargment自体のページ変更を聞きたいのですが、私は何ができますか? –

+0

実際にはこれは悪いものです。なぜならOnPageChangeListenerは非同期作業の後に呼び出され、この "トリック"を使用すると多くの場合に適切な作業ができなくなるからです。 – Defuera

0
を役に立てば幸い以下を追加します。

ViewPagerを拡張して、positio nは0から0に変更されます

public class BetterViewPager extends ViewPager { 

    public BetterViewPager(Context context, AttributeSet attrs) { 
      super(context, attrs); 
     } 

     // we some the listner 
     protected OnPageChangeListener listener; 

     @Override 
     public void setOnPageChangeListener(OnPageChangeListener listener) { 
      super.setOnPageChangeListener(listener); 
      this.listener = listener; 
     } 

     @Override 
     public void setCurrentItem(int item) { 
      // when you pass set current item to 0, 
      // the listener won't be called so we call it on our own 
      boolean invokeMeLater = false; 

      if(super.getCurrentItem() == 0 && item == 0) 
       invokeMeLater = true; 

      super.setCurrentItem(item); 

      if(invokeMeLater && listener != null) 
       listener.onPageSelected(0); 
     } 

} 
+0

これは本当に答えに近いですが、子フラグメントがまだ添付されていないため、getParentFragmentまたはgetActivityを呼び出そうとすると失敗します。これが他の場所にあるので、フラグメントが添付されていることを保証できますか? – mtmurdock

21

実際これはバグです。

final boolean dispatchSelected = mCurItem != item; 
//item is what you passed to setCurrentItem(item) 

そして、変数mCurItem:変数が、コードによって決定されるdispatchSelected、上記

if (dispatchSelected && mOnPageChangeListener != null) { 
      mOnPageChangeListener.onPageSelected(item); 
     } 

: 私はViewPagerのソースコードをチェックしてきたとの唯一のトリガはをonPageSelectedましたは、次のように定義され、初期化されます。

private int mCurItem; // Index of currently displayed page. 

だからmCurItemは、デフォルトで0です。setCurrentItem(0)を呼び出すと、dispatchSelectedはfalseとなり、onPageSelected()はディスパッチされません。

ここで、setCurrentItem(1または2、3 ...)がそうでないうちにsetCurrentItem(0)を呼び出すことが問題である理由を理解する必要があります。

この問題を解決するための方法

  1. コピーし、独自のプロジェクトにViewPagerのコードとそれを修正:

    from 
    final boolean dispatchSelected = mCurItem != item; //the old line 
    to 
    final boolean dispatchSelected = mCurItem != item || mFirstLayout; //the new line 
    

    その後、独自のViewPagerを使用しています。

  2. 意識的にsetCurrentItem(0)を呼び出し、OnPageChangedListenerを参照しているので、onPageSelected()を自分でディスパッチします。

  3. 听楼下怎么说...

+0

そして、http:// grepcodeというソースコードのリンクです。com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/support/v4/view/ViewPager.java – Nicramus

+0

コードをコピーせずにこれを行う方法はありますか?それをサブクラスで修正する方法はありますか? – mtmurdock

+1

PagerAdapter.DataSetObserverを型に解決できないと言っていますか? – CoDe

-3

あなたは、画面animotionは、以下のソリューションが私のために働くようだ

pager.setCurrentItem(1); 
pager.setCurrentItem(0); 
+1

ページャに1つのアイテムしかない場合は...? – RobP

1

をしようと気にしない場合。すなわち、ビューページャーが最初にロードされたときに、位置0にコールバックを取得し、その後のすべての選択について、ユーザースクロールまたはsetCurrentItem(x)コールからコールバックを取得します。私は望ましくない行動を観察していません。

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 
      @Override 
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 

       if (positionOffsetPixels == 0) { 
       //Do something on selected page at position 
       } 

      } 

      @Override 
      public void onPageSelected(int position) {} 

      @Override 
      public void onPageScrollStateChanged(int state) {} 
     }); 
0
public class PageChangeListener implements ViewPager.OnPageChangeListener { 
    @Override 
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 

    } 

    @Override 
    public void onPageSelected(int position) { 
    } 

    @Override 
    public void onPageScrollStateChanged(int state) { 
     if (state == ViewPager.SCROLL_STATE_IDLE && getCurrentItem() == 0) { 
     //this indicate viewpager finish scroll and page at position 0 is selected. 
     } 
関連する問題