7

フラグメントを使用し、ページ(A <-> B <-> C <-> A)などの曲線の動きでスワイプできるViewPagerを実装したいと思います。これがどのように行われるかについてのいくつかの投稿を読みました。たとえば、要素の数の偽のカウントを返したり、中央の開始位置を設定したりします。 円形のビューページャーを作成する方法は?

これらはすべてPagerAdapterに基づいているようです。FragmentPagerAdapterを拡張しているときに同様のことを行おうとすると、fakeCountのページを返すとすぐに、フラグメントをスワイプすると例外が発生します。フラグメントは2つしかありません。例外:java.lang.IllegalStateException:フラグメントのタグを変更できません。

これは、FragmentManagerが私が位置2にいると思っているが、位置2が位置0のフラグメントを指しているために発生したと思います。これを回避する方法を知っている人はいますか?Fragmentmanagerを拡張して実験する必要があると考えています。これに関する例や助けをいただければ幸いです。

4

3 に答える 3

3

少し遅れていることはわかっていますが、これが私にとってどのように機能したかです:

3 つのフラグメント間で円形のスワイプが必要だったので、ページのループを実装しやすくするために、それらの 3 つとさらに 2 つを仮想化しました。

public static class FirstViewFragment extends Fragment {
    // Empty Constructor
    public FirstViewFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_landing_1, container, false);
    }
}

public static class SecondViewFragment extends Fragment {
    // Empty Constructor
    public SecondViewFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_landing_2, container, false);
    }
}

public static class ThirdViewFragment extends Fragment {
    // Empty Constructor
    public ThirdViewFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_landing_3, container, false);
    }
}

そして、最初から左にスワイプし、最後から右にスワイプできるようにする、さらに 2 つの仮想フラグメント。最初の仮想は最後の実際と同じレイアウトを膨張させ、最後の仮想は最初の実際と同じレイアウトを膨張させます。

public static class StartVirtualFragment extends Fragment {
    public StartVirtualFragment() {}

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_landing_3, container, false);
    }
}

public static class EndVirtualFragment extends Fragment {
    public EndVirtualFragment() {}

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_landing_1, container, false);
    }
}

私のアダプター:

private class ViewPagerAdapter extends FragmentPagerAdapter {

    public ViewPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int i) {
        switch (i) {
            case 0:
                return new StartVirtualFragment();
            case 1:
                if (firstViewFragment == null) {
                    firstViewFragment = new FirstViewFragment();
                }
                return firstViewFragment;
            case 2:
                if (secondViewFragment == null) {
                    secondViewFragment = new SecondViewFragment();
                }
                return secondViewFragment;
            case 3:
                if (thirdViewFragment == null) {
                    thirdViewFragment = new ThirdViewFragment();
                }
                return thirdViewFragment;
            case 4:
                return new EndVirtualFragment();
        }
        return null;
    }

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

そして、私のページリスナーは onPageScrollStateChanged を使用して正しいページを設定し、ループを実装しました:

viewPager.setOnPageChangeListener(new 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_DRAGGING) {
                int pageCount = viewPager.getChildCount();
                int currentItem = viewPager.getCurrentItem();
                if (currentItem == 0) {
                    viewPager.setCurrentItem(pageCount - 2, false);
                } else if (currentItem == pageCount - 1) {
                    viewPager.setCurrentItem(1, false);
                }
            }
        }
    });

そして最後に:

viewPager.setCurrentItem(1);

私が助けてくれることを願っています

于 2014-05-12T10:55:56.513 に答える
1

GitHub に、作成したウィジェットを含むプロジェクトがあります。ここにあります:

https://github.com/Cyber​​Eagle/AndroidWidgets

次のパッケージには、CircularViewPager で使用するアダプターがあります: https://github.com/Cyber ​​Eagle/AndroidWidgets/tree/master/src/main/java/br/com/cybereagle/androidwidgets/adapter

まず、レイアウトで ViewPager の代わりに CircularViewPager を使用します。CircularViewPager はこちら: https://github.com/Cyber​​Eagle /AndroidWidgets/blob/master/src/main/java/br/com/cybereagle/androidwidgets/view/CircularViewPager.java

この ViewPager は、PagerAdapter ではなく、WrapperCircularPagerAdapter を想定しています。このラッパーは、ViewPager を騙して、ViewPager に多くのアイテムがあると思わせるために使用されますが、実際にはアイテムを繰り返して循環効果を生み出します。したがって、PagerAdapter、FragmentPagerAdapter、または FragmentStatePagerAdapter のいずれかを実装する代わりに、CircularFragmentPagerAdapter、CircularFragmentStatePagerAdapter、または CircularPagerAdapter のいずれかを実装します。次に、アダプターを WrapperCircularPagerAdapter でラップし、アダプターの代わりに CircularViewPager にラッパーを設定します。また、データセットの変更を通知するときは、ラッパーで notifyDatasetChanged() を呼び出します。

循環アダプターの 1 つを実装する場合、instantiateItem を実装する代わりに、instantiateVirtualItem を実装する必要があることに気付くでしょう。フラグメントのページャー アダプターには、getItem の代わりに getVirtualItem を実装します。それは、仮想アイテムの概念を作成したからです。

わかりやすくするために、4 つのアイテムを持つビュー ページャーを想像してください。各アイテムは音楽を表します。一番左に行くと、一番左に4番目の商品が見えます。実は全くの新作ですが、4曲目を代表するバーチャルアイテムと連動しています。

別の例: 現在、音楽が 1 つしかないとします。左右に同じ音楽が表示されます。一度に 3 つのアイテムがありますが、仮想アイテムは 1 つだけです。

説明したように、Wrapper は ViewPager を騙して、アイテムがたくさんあると思わせています。ユーザーが ViewPager の端の 1 つに到達するのをより困難にするために (とにかく長い時間がかかります)、データセットに変更が発生するたびに、ViewPager は同じ仮想アイテムに移動しますが、真ん中あたりが実物。

もう 1 つ重要なことは、CircularViewPager にはメソッド setCurrentVirtualItem があることです。このメソッドは、目的の仮想アイテムに最も近い実際のアイテムを計算し、setCurrentItem を使用してそれを設定します。現在の仮想アイテムのインデックスを返す getCurrentVirtualItem を使用するオプションもあります。getCurrentItem を使用すると、大きなインデックスが取得されることに注意してください。

さて、これです。プロジェクトのドキュメントが不足していて申し訳ありません。私はすぐにそれを文書化する予定です。また、ラッパーの必要性を取り除くことも計画しています。(Apache 2.0 ライセンスを尊重して) コードを自由にコピーして、フォークしたり、コードに貢献したりしてください。

于 2013-10-17T23:34:22.067 に答える
-3
**If you want to make 3 views visible at same time and make it circular** 

    public abstract class CircularPagerAdapter extends PagerAdapter{
        private int count;
        int[] pagePositionArray;
        public static final int EXTRA_ITEM_EACH_SIDE = 2;
        private ViewPager.OnPageChangeListener pageChangeListener;
        private ViewPager viewPager;

        public CircularPagerAdapter(final ViewPager pager, int originalCount ) {
            super();
            this.viewPager = pager;
            count = originalCount + 2*EXTRA_ITEM_EACH_SIDE;
            pager.setOffscreenPageLimit(count-2);
            pagePositionArray = new int[count];
            for (int i = 0; i < originalCount; i++) {
                pagePositionArray[i + EXTRA_ITEM_EACH_SIDE] = i;
            }
            pagePositionArray[0] = originalCount - 2;
            pagePositionArray[1] = originalCount -1;
            pagePositionArray[count - 2] = 0;
            pagePositionArray[count - 1] = 1;

            pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

                public void onPageSelected(final int position) {
                    if(pageChangeListener != null)
                    {
                        pageChangeListener.onPageSelected(pagePositionArray[position]);
                    }

                    pager.post(new Runnable() {
                        @Override
                        public void run() {
                            if (position == 1){
                                pager.setCurrentItem(count-3,false);
                            } else if (position == count-2){
                                pager.setCurrentItem(2,false);
                            }
                        }
                    });
                }

                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                    if(pageChangeListener != null)
                    {
                        pageChangeListener.onPageScrolled(pagePositionArray[position],positionOffset,positionOffsetPixels);
                    }
                }

                public void onPageScrollStateChanged(int state) {
                    if(pageChangeListener != null)
                    {
                        pageChangeListener.onPageScrollStateChanged(state);
                    }
                }
            });
        }


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

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return false;
        }

        public abstract Object customInstantiateItem(ViewGroup container, int position);

        public void setPageChangeListener(ViewPager.OnPageChangeListener pageChangeListener)
        {
            this.pageChangeListener = pageChangeListener;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            int pageId = pagePositionArray[position];
            return customInstantiateItem(container,pageId);
        }

        @Override
        public void destroyItem(View container, int position, Object object) {
            ((ViewPager) container).removeView((View) object);
        }

        public void setFirstItem()
        {
            viewPager.setCurrentItem(EXTRA_ITEM_EACH_SIDE - 1);
        }
    }
于 2016-09-07T05:52:53.403 に答える