Я могу использовать только ViewPager для просмотра страниц назад и не могу переходить вперед

Я могу использовать только ViewPager для просмотра страниц назад и не могу переходить вперед.

бегущее изображение

Я пишу баннер, но я могу использовать ViewPager только для перехода назад и не могу переходить вперед.

Это адаптер, который я написал.

class MyPagerAdapter extends PagerAdapter {

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        int p = position % mImgRes.length;
        container.addView(mListView.get(p));
        return mListView.get(p);
    } 

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

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

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

}

Это сообщение об ошибке.

   07-29 20: 45: 02.098 20791-20791 / com.example.myfirstpro E / AndroidRuntime: 
   ФАТАЛЬНОЕ ИСКЛЮЧЕНИЕ: главная
   Процесс: com.example.myfirstpro, PID: 20791
   java.lang.IllegalStateException: указанный дочерний элемент уже имеет родителя. Сначала вы должны вызвать removeView () у родителя ребенка.
       на android.view.ViewGroup.addViewInner(ViewGroup.java:4465)
       на android.view.ViewGroup.addView(ViewGroup.java:4301)
       на android.support.v4.view.ViewPager.addView(ViewPager.java:1505)
       на android.view.ViewGroup.addView(ViewGroup.java:4242)
       на android.view.ViewGroup.addView(ViewGroup.java:4215)
       в com.example.myfirstpro.MainFragment$MyPagerAdapter.instantiateItem(MainFragment.java:62)
       на android.support.v4.view.ViewPager.addNewItem(ViewPager.java:1034)
       на android.support.v4.view.ViewPager.populate(ViewPager.java:1216)
       на android.support.v4.view.ViewPager.populate(ViewPager.java:1116)
       на android.support.v4.view.ViewPager$3.run(ViewPager.java:273)
       на android.view.Choreographer$CallbackRecord.run(Хореограф.java:892)
       на android.view.Choreographer.doCallbacks(Хореограф.java:704)
       на android.view.Choreographer.doFrame(Хореограф.java:637)
       на android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:878)
       на android.os.Handler.handleCallback(Handler.java:739)
       на android.os.Handler.dispatchMessage(Handler.java:95)
       на android.os.Looper.loop(Looper.java:148)
       на android.app.ActivityThread.main(ActivityThread.java:5628)
       в java.lang.reflect.Method.invoke(родной метод)
       на com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:853)
       на com.android.internal.os.ZygoteInit.main(ZygoteInit.java:737)

Программа вылетит, когда я перейду вперед.

Это в дополнение к коду, отличному от адаптера.@Hong Duan

    private ViewPager mVpScroll;
private int mImgRes[] = new int[] {
        R.drawable.banner01,
        R.drawable.banner02,
        R.drawable.banner03
};
private List<View> mListView = new ArrayList<>();
private LayoutInflater mInfalte;

public MainFragment() {
    // Required empty public constructor
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    for (int i = 0; i < mImgRes.length; i++) {
        View inflate = inflater.inflate(R.layout.fragment_main_scroll_item, null);
        ImageView ivBanner = (ImageView) inflate.findViewById(R.id.iv_scroll);
        ivBanner.setImageResource(mImgRes[i]);
        mListView.add(inflate);
    }
    mInfalte = inflater;
    return inflater.inflate(R.layout.fragment_main, container, false);
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    mVpScroll = (ViewPager) view.findViewById(R.id.vp_scroll);
    mVpScroll.setAdapter(new MyPagerAdapter());
}

1 ответ

Решение

Как показывает сообщение об ошибке, основной причиной является дочерний View добавляется дважды. Но почему это происходит только тогда, когда вы проводите назад? Я сделал тестовый проект, и я думаю, что я нашел причину:)

когда ViewPager свитки, он будет перерабатывать предметы, используя его PagerAdapter методы: instantiateItem а также destroyItem, когда ViewPager хочет показать новый предмет, instantiateItem называется, когда ViewPager прокручивает, вид, который с экрана будет уничтожен методом destroyItem,

По умолчанию ViewPager будет держать 1 больше элементов на каждой стороне для плавной прокрутки, а это означает, что есть не более 3 предметы хранятся у ViewPager,

Проблема в том, что вы используете:

int p = position % mImgRes.length;

реализовать "петлю" ViewPager, это означает, что если mImgRes.length == 3, позиция 3 покажет то же самое View в положении 0.

Теперь подумайте о вашем случае:

  • когда ViewPager начатый, предмет 0 а также 1 (справа) добавлены instantiateItem;

  • затем прокрутите страницу вправо, элемент 1 показано, и элемент 2 добавлен, теперь элемент 0 (левый боковой элемент), 1, 2 (справа) сохраняются;

  • прокрутите страницу вправо еще раз, элемент 2 показано, пункт 3 добавлено, пункт 0 уничтожен методом destroyItem Теперь предмет 1 (левый боковой элемент), 2, 3 (правый элемент, тот же элемент для 0) хранятся;

Все работает нормально если instantiateItem а также destroyItem работает, как ожидалось, и работает, когда вы прокручиваете вправо ("вперед"), но не работает, когда вы прокручиваете влево ("назад"), потому что порядок instantiateItem а также destroyItem выполнены разные! Смотрите журнал:

07-30 22:00:04.385 26064-26064/com.example.test D/xxxxx: instantiateItem: 0
07-30 22:00:04.388 26064-26064/com.example.test D/xxxxx: instantiateItem: 1
07-30 22:00:17.693 26064-26064/com.example.test D/xxxxx: instantiateItem: 2
07-30 22:00:18.743 26064-26064/com.example.test D/xxxxx: destroyItem: 0
07-30 22:00:18.744 26064-26064/com.example.test D/xxxxx: instantiateItem: 3
07-30 22:00:26.477 26064-26064/com.example.test D/xxxxx: instantiateItem: 0  < -- crash!!!
07-30 22:00:18.743 26064-26064/com.example.test D/xxxxx: destroyItem: 3

когда вы прокрутите вправо, destroyItem выполняется сначала, затем instantiateItem, так что работает нормально, но когда вы прокручиваете влево, instantiateItem выполняется первым, поэтому, когда печатается последняя строка журнала, элемент 0 добавляется второй раз, потому что элемент 3 (которые разделяют одно и то же View с предметом 0) еще не был уничтожен, то вылетает:)

Интересно то, что если mImgRes.length > 3, он будет работать нормально, потому что когда есть 4 пункта, это не слишком поздно, когда destroyItem выполнить.

Итак, если вы хотите реализовать ViewPager с функцией "петли", вы должны думать о том, как обойти эту проблему.

Другие вопросы по тегам