42

私はこの奇妙な問題を抱えています. は完全に正常に動作し、次に別ViewPagersetCurrentItem(position, false)アクティビティに切り替えます.最初のアクティビティに戻った後、ViewPager常に最初のアイテムになります. メソッドに追加setCurrentItemしましたがonResume、それでも無視されます。アイテムを範囲外のインデックスに設定しようとしても、例外はスローされません。後でこのメソッドを呼び出すと、「次へ」ボタンがタップされると、期待どおりに機能します。または何かの呼び出しの可能性についてコードを10回チェックしましsetCurrentItem(0)たが、まったくありません。

4

18 に答える 18

89

なぜこれが起こるのか正確には答えられませんが、 setCurrentItem 呼び出しを数ミリ秒遅らせるとうまくいくはずです。私の推測ではonResume、レンダリング パスがまだ存在しておらず、ViewPager が 1 つまたはそのようなものを必要としているためです。

private ViewPager viewPager;

@Override
public void onResume() {
    final int pos = 3;
    viewPager.postDelayed(new Runnable() {

        @Override
        public void run() {
            viewPager.setCurrentItem(pos);
        }
    }, 100);
}

更新: ストーリータイム

今日、viewpagerがsetCurrentItemアクションを無視するという問題があり、stackoverflowで解決策を検索しました。同じ問題と修正を持っている人を見つけました。私は修正を実装しましたが、うまくいきませんでした。うわあ!stackoverflow に戻って、その偽修正プロバイダーに反対票を投じ、そして ...

それは私。私は自分自身の不完全な非修正を実装しました。これは、最初に問題に遭遇したときに思いついたものです (後で忘れられました)。悪い情報を提供したことで、自分自身に反対票を投じなければなりません。


私の最初の「修正」が機能した理由は、「レンダリングパス」のためではありませんでした。問題は、ページャーのコンテンツがスピナーによって制御されていたことです。スピナーとページャーの両方の状態が onResume で復元されました。このため、スピナーの onItemSelected リスナーが次のイベント伝播サイクル中に呼び出され、ビューページャーが再設定されました。今回は別のデフォルト値を使用しています。
初期状態の復元中にリスナーを削除してリセットすると、問題が修正されました。

上記の修正は、onItemSelected イベントが発生したにページャの現在の位置を設定したため、初めて機能しました。後で、何らかの理由で動作しなくなりました (おそらくアプリが遅くなりすぎました - 私の実装では 100ms を使用しませんでしたが、10ms を使用しました)。その後、クリーンアップ サイクルで postDelayed を削除しました。これは、既に問題のある動作を変更しなかったためです。

更新 2:自分の投稿に反対票を投じることができません。私は、立派な切腹が残された唯一の選択肢だと思います。

于 2013-11-08T12:14:00.580 に答える
15

これに対する非常に簡単な回避策を見つけました:

    if (mViewPager.getAdapter() != null)
        mViewPager.setAdapter(null);
    mViewPager.setAdapter(mPagerAdapter);
    mViewPager.setCurrentItem(desiredPos);

それでもうまくいかない場合は、ハンドラーに入れることができますが、遅延時間は必要ありません。

        new Handler().post(new Runnable() {
            @Override
            public void run() {
                mViewPager.setCurrentItem(desiredPos);
            }
        });
于 2014-04-29T11:11:43.220 に答える
5

ViewTreeObserver を使用して、静的な遅延を回避できます。

コトリン:

簡潔なオプションとして、Kotlin 拡張機能を自由に使用してください。

view_pager.doOnPreDraw {
    view_pager.currentItem = 1
}

gradle 依存関係があることを確認してください: 実装 'androidx.core:core-ktx:1.3.2' 以上

ジャワ

OneShotPreDrawListener.add(view_pager, () -> view_pager.currentItem = 1);
于 2020-11-04T03:00:56.383 に答える
3

私は同じ問題を抱えており、編集しています

@Override
public int getCount() { return NUM_PAGES; }

私はNUM_PAGES間違いを1だけに設定しました。

于 2015-03-19T15:10:53.547 に答える
3

ここで説明されている post() メソッドを使用しましたが、いくつかのシナリオでは十分に機能していましたが、私のデータはサーバーから取得されるため、それは聖杯ではありませんでした.

私の問題は、私がしたいということでした

notifyDataSetChanged

任意の時間に呼び出されてから、viewPager のタブを切り替えます。だから、通知呼び出しの直後に私はこれを持っています

ViewUtilities.waitForLayout(myViewPager, new Runnable() {
    @Override
    public void run() {
        myViewPager.setCurrentItem(tabIndex , false);
    }
});

public final class ViewUtilities {
    public static void waitForLayout(final View view, final Runnable runnable) {
        view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            //noinspection deprecation
                view.getViewTreeObserver().removeGlobalOnLayoutListener(this);

                runnable.run();
            }
        });
    }
}

豆知識://noinspection deprecation最後の は、API 16 以降に修正された API にスペルミスがあるためです。

removeOnGlobalLayoutListener
       ^^
      ON Global

それ以外の

removeGlobalOnLayoutListener
            ^^
            ON Layout

これは私にとってすべてのケースをカバーしているようです。

于 2016-11-21T17:09:55.713 に答える
2

私はこの問題に 1 週​​間取り組んでいましたが、この問題が発生するのは、ビュー ページャー フラグメントでホーム アクティビティ コンテキストを使用していたためであり、アクティビティにアタッチされた後でしかフラグメント内のコンテキストを使用できないことが原因であることに気付きました.
ビュー ページャーが作成されると、アクティビティは、最初 (0) と 2 番目 (1) のページにのみ添付されます。2ページ目を開くと3ページ目がくっつきます!メソッドを使用setCurrentItem()し、引数が 1 より大きい場合、アタッチされる前にそのページを開こうとするため、そのページのフラグメントのコンテキストが null になり、アプリケーションがクラッシュします! そのため、 を遅らせるsetCurrentItem()とうまくいきます! 最初は添付され、次にページが開きます...

于 2019-08-28T13:39:26.137 に答える
0

私が呼び出すまでにsetCurrentItem()、ビューは再作成されようとしています。したがって、実際にsetCurrentItem()はビューページャーを呼び出し、その後システムが呼び出しonCreateView()て新しいビューページャーを作成します。

これが、変化が見られない理由です。postDelayed()そして、これが aが役立つ理由です。

理論上の解決策:setCurrentItem()ビューが再作成されるまで呼び出しを延期します。

実用的な解決策:安定した単純な解決策の手がかりがありません。クラスがそのビューを再作成しようとしているかどうかを確認できるはずです。その場合は、の呼び出しをsetCurrentItem()最後まで延期しますonCreateView()

于 2016-10-08T20:04:00.547 に答える
0

私はこの方法で現在のアイテムを復元しました:

@Override
protected void onSaveInstanceState(Bundle outState) {

    if (mViewPager != null) {
        outState.putInt(STATE_PAGE_NO, mViewPager.getCurrentItem());
    }

    super.onSaveInstanceState(outState);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {

    if (savedInstanceState != null) {
        mCurrentPage = savedInstanceState.getInt(STATE_PAGE_NO, 0);
    }

    super.onRestoreInstanceState(savedInstanceState);
}

@Override
protected void onRestart() {
    mViewPager.setCurrentItem(mCurrentPage);
         super.onRestart();
}
于 2013-10-11T11:20:24.997 に答える