Как сделать круговую прокрутку на ViewPager?

Вышеприведенный код фактически ничего не видит - он просто вычисляет, а затем выдает расчет. Это код, который вы использовали, или просто пример для этого вопроса?

попытаться выполнить textAreaDoc.insertString (int, String, AttributeSet) в конце?

23
задан portfoliobuilder 26 January 2014 в 20:20
поделиться

10 ответов

Хорошо, у меня есть ответ. Это было на самом деле проще, чем я ожидал, но это требует некоторой хитрости. Во-первых, позвольте мне начать с настройки. Допустим, например, у вас есть три страницы (A-B-C), которые вы просматриваете в ViewPager. И вы хотите настроить его так, чтобы, если вы продолжаете прокручивать на C (стр. 3), он переходит к A (стр. 1), а если вы прокручиваете назад на A (стр. 1), он переходит к C (стр. 3). ).

Я не говорю, что мое решение является лучшим, но оно работает, и я не вижу никаких проблем. Во-первых, вы должны создать две «поддельные» страницы. Поддельные страницы представляют первую и последнюю страницы вашего ViewPager. Следующее, что вам нужно, это настроить onPageChangeListener () и использовать метод onPageSelected (). Причина, по которой вам нужны поддельные страницы, заключается в том, что onPageSelected () регистрируется только после того, как вы переместились (сильно ударили). Другими словами, без этого метода конечный пользователь должен был бы перейти к странице 2 и вернуться к странице 1, чтобы получить попадание на страницу 1, что также означает, что страница 1 будет пропущена в зависимости от логики вашего кода.

Установка действительно весь ответ. После того, как у вас есть поддельные страницы, нужно просто использовать setCurrentItem () внутри необходимого метода.

Вот как выглядит мой код. Обязательно поместите это внутри вашего публичного метода Object instantiateItem (конечный контейнер ViewGroup, конечная позиция int), непосредственно перед возвратом своего представления внутри вашего контейнера.

((ViewPager) container).setOnPageChangeListener(new OnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                Log.d(TAG, "onPageSelected() :: " + "position: " + position);

                // skip fake page (first), go to last page
                if (position == 0) {
                    ((ViewPager) container).setCurrentItem(118, false);
                }

                // skip fake page (last), go to first page
                if (position == 119) {
                    ((ViewPager) container).setCurrentItem(1, false); //notice how this jumps to position 1, and not position 0. Position 0 is the fake page!
                }

            }

Вот и все, он делает свое дело! Единственное, что нужно сделать - запустить ViewPager с позиции 1 (это вторая страница: поддельная страница = pg 1, моя настоящая стартовая страница = pg 2). Теперь, каждый раз, когда я прокручиваю на поддельную страницу, я перенаправляю ее назад на последнюю реальную страницу. И каждый раз, когда я прокручиваю вперед до последней фальшивой страницы, я перенаправляю ее на настоящую стартовую страницу (стр. 2).

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

14
ответ дан portfoliobuilder 26 January 2014 в 20:20
поделиться

Это решение без поддельных страниц и работает как шарм:

public class CircularViewPagerHandler implements ViewPager.OnPageChangeListener {
    private ViewPager   mViewPager;
    private int         mCurrentPosition;
    private int         mScrollState;

    public CircularViewPagerHandler(final ViewPager viewPager) {
        mViewPager = viewPager;
    }

    @Override
    public void onPageSelected(final int position) {
        mCurrentPosition = position;
    }

    @Override
    public void onPageScrollStateChanged(final int state) {
        handleScrollState(state);
        mScrollState = state;
    }

    private void handleScrollState(final int state) {
        if (state == ViewPager.SCROLL_STATE_IDLE) {
            setNextItemIfNeeded();
        }
    }

    private void setNextItemIfNeeded() {
        if (!isScrollStateSettling()) {
            handleSetNextItem();
        }
    }

    private boolean isScrollStateSettling() {
        return mScrollState == ViewPager.SCROLL_STATE_SETTLING;
    }

    private void handleSetNextItem() {
        final int lastPosition = mViewPager.getAdapter().getCount() - 1;
        if(mCurrentPosition == 0) {
            mViewPager.setCurrentItem(lastPosition, false);
        } else if(mCurrentPosition == lastPosition) {
            mViewPager.setCurrentItem(0, false);
        }
    }

    @Override
    public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
    }
}

Вы просто должны установить его на свой ViewPager как onPageChangeListener и все:

viewPager.setOnPageChangeListener(new CircularViewPagerHandler(viewPager));

Чтобы избежать этого синего блеска в «конце» вашего ViewPager, вы должны применить эту строку к вашему XML, где находится ViewPager:

android:overScrollMode="never"
38
ответ дан tobi_b 26 January 2014 в 20:20
поделиться

Попробуйте это

((ViewPager) container)
                .setOnPageChangeListener(new OnPageChangeListener() {
                    @Override
                    public void onPageSelected(int position) {
                        Log.i("TAG", "pos::" + position);

                    }
                    @Override
                    public void onPageScrollStateChanged(int state) {
                        // TODO Auto-generated method stub                            
                           int currentPage = pager.getCurrentItem();
                           Log.i("TAG", "currentPage::" + currentPage);
                           Log.i("TAG", "currentState::" + currentState);
                           Log.i("TAG", "previousState::" + previousState);
                           if (currentPage == 4 || currentPage == 0) {
                            previousState = currentState;
                            currentState = state;
                            if (previousState == 1 && currentState == 0) {
                             pager.setCurrentItem(currentPage == 0 ? 4 : 0);
                            }
                           }

                    }

                    @Override
                    public void onPageScrolled(int arg0, float arg1,
                            int arg2) {
                        // TODO Auto-generated method stub

                    }
                });

        return

Это должно быть размещено внутри

 @Override
    public Object instantiateItem(final View container, int position) {}
2
ответ дан D-D 26 January 2014 в 20:20
поделиться

Я немного изменил ответ от @portfoliobuilder. Это очень просто Установка текущего элемента без плавной прокрутки до PageChangeState в «0», поэтому он будет очень плавным.

((ViewPager)container).setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {
        currentPage = position;
    }

    @Override
    public void onPageScrollStateChanged(int state) {

        // state equals to 0 means the scroll action is stop
        if(state == 0) {

            if(currentPage == 0)
                ((ViewPager)container).setCurrentItem(imageResourceList.size()-2,false);

            if(currentPage == imageResourceList.size()-1)
                ((ViewPager)container).setCurrentItem(1,false);
        }
    }
});
2
ответ дан Kurt Van den Branden 26 January 2014 в 20:20
поделиться

Я попробовал решение @ портфеля, это здорово. Но есть небольшая проблема: когда текущим элементом является голова или хвост, если я просто щелкаю ViewPager, а не перетаскиваю, элемент изменится на хвост или голову. И я добавил сенсорный слушатель в ViewPager, чтобы решить эту проблему.

skinPager.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            //Record the x when press down and touch up, 
            //to judge whether to scroll between head and tail
            int x = (int) event.getX();
            int y = (int) event.getY();
            if(event.getAction() == MotionEvent.ACTION_DOWN)
                skinPagerPressX = x;
            else if(event.getAction() == MotionEvent.ACTION_UP)
                skinPagerUpX = x;
            return false;
        }
    });

Следующее является модифицированной функцией портфеля:

private void handleSetNextItem() {
    final int lastPosition = skinPager.getAdapter().getCount() - 1;
    //Only scroll when dragged
    if(mCurrentPosition == 0 && skinPagerUpX > skinPagerPressX) {
        skinPager.setCurrentItem(lastPosition, false);
    } else if(mCurrentPosition == lastPosition && skinPagerUpX < skinPagerPressX) {
        skinPager.setCurrentItem(0, false);
    }
}
1
ответ дан nile.wangyq 26 January 2014 в 20:20
поделиться

Это простой пример, важной частью слушателя является обнаружение STATE_IDLE конечной точки цикла. поэтому сначала реализуйте класс OnPageChangeListener, затем в свой класс обработчика добавьте эту часть:

@Override
    public void onPageScrollStateChanged(int state) {

        if (state == ViewPager.SCROLL_STATE_IDLE) {

            if (mPreviousPosition == mCurrentPosition && !mIsEndOfCycle) {

                if (mCurrentPosition == 0) {
                    mViewPager.setCurrentItem(getAdapterItemsCount() - 1);
                } else {
                    mViewPager.setCurrentItem(0);
                }

                mIsEndOfCycle = true;
            } else {
                mIsEndOfCycle = false;
            }

            mPreviousPosition = mCurrentPosition;
        }

    }
1
ответ дан Mr.Hosseini 26 January 2014 в 20:20
поделиться

Решено отсутствие анимации при перемещении справа налево при перелистывании первой страницы к последней и наоборот

Небольшое изменение в ответе @tobi_b решило мою проблему. для этого добавьте копию последней страницы в начальной и первой страницы в последнюю. Затем просто удалите оператор NOT из метода ниже в PagerAdapter. И замените setCurrentItem (lastposition, false) на setCurrentItem (lastposition-1, false) и setCurrentItem (0, false) для setCurrentItem (1, false).

private void setNextItemIfNeeded() {
    if (isScrollStateSettling()) {
        handleSetNextItem();
    }
}

private boolean isScrollStateSettling() {
    return mScrollState == ViewPager.SCROLL_STATE_SETTLING;
}
private void handleSetNextItem() {
    final int lastPosition = pager.getAdapter().getCount() - 1;
    if(mCurrentPosition == 0) {
        pager.setCurrentItem(lastPosition-1, false);
    } else if(mCurrentPosition == lastPosition) {
       pager.setCurrentItem(1, false);
    }
}

И в вашем MainActivity.java не забудьте установить текущий элемент равным 1. Надеясь, это поможет некоторым.

0
ответ дан TheHound.developer 26 January 2014 в 20:20
поделиться

Я создал круговую панель просмотра с плавной прокруткой от последнего к первому при пролистывании влево и от первого до последнего при пролистывании вправо.

для этого добавьте последнюю страницу в начальной и первую страницу к последней: внутри addOnPageChangeListener: мы должны сделать некоторые вычисления, когда мы на 0 месте, то на onPageScrollStateChanged установить текущий элемент как последний пункт и наоборот.

Посмотрите код

public class ViewPagerCircular_new extends AppCompatActivity {
ViewPager viewPager;
ArrayList<String> str = new ArrayList<String>();
boolean chageImage = false;
int setPos;

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.view_pager_normal);
    viewPager = (ViewPager) findViewById(R.id.vf_home_top_pager);
    str.add("6");         // added the last page to the frist
    str.add("1");        // First item to display in view pager
    str.add("2");
    str.add("3");
    str.add("4");
    str.add("5");
    str.add("6");     // last item to display in view pager
    str.add("1");      // added the first page to the last
    ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
    viewPager.setAdapter(adapter);
    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener()
    {

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
        {
            if (position == str.size() - 1)
            {
                chageImage = true;
                setPos = 1;
            } else if (position == 0)
            {
                chageImage = true;
                setPos = str.size() - 2;
            } else
            {
                chageImage = false;
            }
        }

        @Override
        public void onPageSelected(int position)
        {
        }

        @Override
        public void onPageScrollStateChanged(int state)
        {
            if (state == ViewPager.SCROLL_STATE_IDLE && chageImage)
            {
                viewPager.setCurrentItem(setPos, false);
            }
        }
    });
// display the 1st item as current item 
    viewPager.setCurrentItem(1);
}

// адаптер пейджера

public class ViewPagerAdapter extends FragmentStatePagerAdapter
{

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

    @Override
    public Fragment getItem(int position)
    {
        PagerFragment fragment = new PagerFragment();
        Bundle bundle = new Bundle();
        bundle.putString("pos", str.get(position));
        fragment.setArguments(bundle);
        return fragment;
    }

    @Override
    public int getCount()
    {
        return str.size();
    }

}

// фрагмент для отображения в адаптере

public class PagerFragment extends Fragment
{

    Bundle bundle;
    String pos;

    public PagerFragment()
    {
    }

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        bundle = getArguments();
        pos = bundle.getString("pos");
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        TextView textView = new TextView(ViewPagerCircular_new.this);
        textView.setGravity(Gravity.CENTER);
        textView.setTextSize(25);
        textView.setText(pos);
        return textView;
    }

}

}

3
ответ дан Mani Agarwal 26 January 2014 в 20:20
поделиться

Это мое решение:

myViewPager.java

public class myViewPager extends PagerAdapter {

    public myViewPager (Context context) {
        this.context = context;
    }

    @Override
    public int getCount() {
        return rank.length+2;
    }

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

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        // Declare Variables

        TextView textViewRank;



        //Log.i(TAG, "get position = "+position);

        inflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View itemView = inflater.inflate(R.layout.viewpager_item, container,
            false);

        textViewRank= (TextView) itemView.findViewById(R.id.textView1);

        if (position == getCount() - 1) {
            textViewRank.setText(rank[0]);
        } else if (position == 0) {
            textViewRank.setText(rank[rank.length-1]);
        } else {
            textViewRank.setText(rank[position-1]);
        }


        ((ViewPager) container).addView(itemView);

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

viewpager_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:id="@+id/textView1"/>
</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getName();
    public static String[] rank;
    myViewPager adapter;
    private ViewPager viewPager;
    private static int currentPage;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        rank = new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };
        viewPager = (ViewPager) findViewById(R.id.view_pager);
        adapter = new myViewPager(this);

        viewPager.setAdapter(adapter);

        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                Log.i(TAG, "onPageSelected = "+position);
                currentPage = position;
            }
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                // not needed
            }
            @Override
            public void onPageScrollStateChanged(int state) {
                if (state == ViewPager.SCROLL_STATE_IDLE) {
                    int pageCount = rank.length+2;

                    if (currentPage == pageCount-1){
                        viewPager.setCurrentItem(1,false);
                    } else if (currentPage == 0){
                        viewPager.setCurrentItem(pageCount-2,false);
                    }
                }
            }
        });
    }


}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />

</LinearLayout>

Предполагается, что массив состоит из 10 элементов. Затем «добавить» 2 фиктивных элемента, но не добавить. Когда вызывается функция get_count, просто вернуть size = 10 + 2 элемента.

манекен e [0] e [1] e [2] e [3] e [4] e [5] e [6] e [7] e [8] e [9] dummy

В viewPager.addOnPageChangeListener:

при переходе к последнему элементу viewPager должен установить первый элемент следующим.

if (currentPage == pageCount-1){
    viewPager.setCurrentItem(1,false);
}

при переходе к первому элементу viewPager должен установить последний элемент следующим.

else if (currentPage == 0){
    viewPager.setCurrentItem(pageCount-2,false);
}

InIntiateItem:

 if (position == getCount() - 1) {
    textViewRank.setText(rank[0]);
 } else if (position == 0) {
    textViewRank.setText(rank[rank.length-1]);    
 } else {
    textViewRank.setText(rank[position-1]);
 }
2
ответ дан Richie Shih 26 January 2014 в 20:20
поделиться

Ответ @tobi_b не совсем успешен, так как он не плавно скользит от последнего к первому (по крайней мере, в моем испытании). Но я был действительно вдохновлен его ответом. Мое решение заключается в том, что пора переходить от поддельного последнего к реальному первому, подождать, пока не закончится последняя прокрутка. Вот мой код, это очень просто,

private final class MyPageChangeListener implements OnPageChangeListener {

    private int currentPosition;

    @Override
    public void onPageScrollStateChanged(int state) {
        if (state == ViewPager.SCROLL_STATE_IDLE) {
            if (currentPosition == viewPager.getAdapter().getCount() - 1) {
                viewPager.setCurrentItem(1, false);
            }
            else if (currentPosition == 0) {
                viewPager.setCurrentItem(viewPager.getAdapter().getCount() - 2, false);
            }
        }
    }

    @Override
    public void onPageScrolled(int scrolledPosition, float percent, int pixels) {
        //empty
    }

    @Override
    public void onPageSelected(int position) {
        currentPosition = position;
    }

}

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

1
ответ дан jinge 26 January 2014 в 20:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: