【问题标题】:ViewPager + PagerAdapter w/ Pagination not working properlyViewPager + PagerAdapter w/ Pagination 无法正常工作
【发布时间】:2017-11-29 11:50:23
【问题描述】:

我有一个画廊/幻灯片活动,允许用户在照片之间滑动。每个“页面”只是一个TouchImageView。那里有一个分页逻辑,我可以看到它正在相应地调用 API。但是,即使在调用 notifyDataSetChanged 后,我也无法进一步滑动。代码如下:

Activity {
    ViewPager vp;
    CustomPagerAdapter pagerAdapter;

    onCreate() {
        //api callback
        pagerAdapter = new CustomPagerAdapter();
        vp.setAdapter(pagerAdapter);
    }
}

CustomPagerAdapter() {
    TouchImageView imageView;
    List<Photos> photos;

    int getCount() {
        return photos == null ? 0 : photos.size();
    }

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

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View itemView = mLayoutInflater.inflate(R.layout.pager_image, container, false);
        imageView = (TouchImageView) itemView.findViewById(R.id.photo);
        Glide.with(context)
                .load(photos.get(position).getUrl())
                .into(imageView);

        container.addView(itemView);

        if (position == photos.size()-1) {
            loadMorePhotos();
        }

        return itemView;
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

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

    void loadMorePhotos() {
        //call api and stuff
        void onResponse(Call call, Response<List<Photo>> response) {
            photos.addAll(response.body);
            notifyDataSetChanged();
        }
    }
}

结果如下: http://imgur.com/nA1TzfI

我不知道这两天发生了什么。请帮忙!

【问题讨论】:

    标签: android pagination android-viewpager android-pageradapter


    【解决方案1】:

    这可能并不理想,但在您调用 notifyDatasetChanged() 时,您可以尝试调用 vp.setAdapter(pagerAdapter);

    (即实际重新设置适配器)。这样做的一个缺点是寻呼机可能会回到选择第一页的状态。为避免这种情况,您需要将最新页面保存在某处,然后再恢复。

    正如我所说,并不理想,但它可能会有所帮助。

    【讨论】:

      【解决方案2】:

      您不必从适配器类加载更多照片,在您的活动类中,您可以使用onPageScrolled 并在最后一项滚动时调用 api 并再次设置适配器还保存视图寻呼机的状态,然后再调用 api 以保留它重新设置适配器时。

          private boolean isLastPageSwiped;
          private int counterPageScroll;
      
      private OnPageChangeListener mListener = new OnPageChangeListener() {
      
          @Override
          public void onPageSelected(int arg0) {
              // TODO Auto-generated method stub
      
          }
          @Override
          public void onPageScrolled(int arg0, float arg1, int arg2) {
              // TODO Auto-generated method stub
           if (position == 6 && positionOffset == 0 && !isLastPageSwiped){
              if(counterPageScroll != 0){
                  isLastPageSwiped=true;
                  //call api 
              }
              counterPageScroll++;
          }else{
              counterPageScroll=0;
          }
      
          }
      
          @Override
          public void onPageScrollStateChanged(int arg0) {
              // TODO Auto-generated method stub
      
          }
      };
      

      并使用这个监听器

      vp.setOnPageChangeListener(mListener);
      

      【讨论】:

        【解决方案3】:

        我们可以使用这种方法在 ViewPager 上进行分页(带片段)

        1. 加载新页面数据但不附加到适配器
        2. 确保页面没有滚动,然后将新页面数据附加到适配器 (ViewPager.OnPageChangeListener#onPageScrolled's positionOffsetPixels == 0)。
        3. 使用偏移量 = 新页面数据的大小更新视图寻呼机的当前项目(我们称之为 newPosition
        4. 将数据重新绑定到3个片段:newPosition - 1newPositionnewPosition + 1

        为了获取当前片段,我们可以使用片段管理器

            private fun getFragment(position: Int): PageFragment? =
                supportFragmentManager.fragments.firstOrNull {
                    (it as? PageFragment)?.position == position // always pass possition value into the fragment
                } as? PageFragment
        

        我们需要在不滚动时附加数据(第 2 步),以便为用户提供更好的 UX。如果我们在数据到来时立即追加数据并且如果用户正在滚动,查看寻呼机的setCurrentItem 会做出奇怪的举动。

        我在这里创建了一个简单的版本https://github.com/tuanchauict/DemoPaginationViewPager。请看一下

        【讨论】: