需求:
- RelativeLayout布局中,顶部放置一个RecyclerView作为category,中间放置ViewPager来显示每个category下的内容,而每一个page页的内容使用RecyclerView显示。
- 可以循环滑动显示内容。
效果图:
实现:
对于需求1,是常规操作,在此就不再赘述。接下来看需求2(ViewPager实现左右循环滑动):
平常我们使用ViewPager,无论是page页放置Fragment还是View,都需要一个Adapter。于是我extends的PagerAdapter如下:
public class MyPagerAdapter extends PagerAdapter {
private List<View> views;
public MyPagerAdapter(List<View> views) {
this.views = views;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(views.get(position));
return views.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
@Override
public int getCount() {
return views.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return (view == object);
}
}
实际上要实现循环滑动,一般可采用两种方式:
其一,新增两个page页,第一个page页作为首页映射“内容页最后page页”,第二个page页作为末尾页,映射“内容页第一page页”,这种实现方式网上可以搜到。但是,这种方式和我的需求1有冲突,category是对应的page页,那么category也要增加两个内容,逻辑上是可以做到,但category映射了position而且使用position访问网络等,简直是牵一发而动全身啊,暂时换个方法试试。。。
其二,看来简单粗暴,但可以解决问题。修改两处:自定义PagerAdapter和ViewPager.OnPageChangeListener的onPageSelected回调。如下:
public class MyPagerAdapter extends PagerAdapter {
private List<View> views;
public MyPagerAdapter(List<View> views) {
this.views = views;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
// container.addView(views.get(position));
// return views.get(position);
//对ViewPager页号求模取出View列表中要显示的项
position %= views.size();
if (position<0){
position = views.size()+position;
}
View view = views.get(position);
//如果View已经在之前添加到了一个父组件,则必须先remove,否则会抛出IllegalStateException。
ViewParent vp =view.getParent();
if (vp!=null){
ViewGroup parent = (ViewGroup)vp;
parent.removeView(view);
}
container.addView(view);
//add listeners here if necessary
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
// container.removeView((View)object);
//Warning:不要在这里调用removeView
}
@Override
public int getCount() {
// return views.size();
// //设置成最大,使用户看不到边界。由于有category对应,值设置为整型最大会导致ANR!!!
// return Integer.MAX_VALUE;
return views.size() * 100;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return (view == object);
}
}
private ViewPager.OnPageChangeListener onPageChangeListener = new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
position = position % pageNumber; // 循环滑动
// ...
}
@Override
public void onPageScrollStateChanged(int state) {
}
};
后记:
看到了一篇文章介绍设置滑动动画(https://www.jianshu.com/p/f70073f7e837 Ps:作者挺厉害的,Android大佬),自己就放到程序中试了下是可以的,代码如下:
mViewPager.setPageTransformer(true, new DepthPageTransformer());
public class DepthPageTransformer implements ViewPager.PageTransformer { // Google官方给出的动画类
private static final float MIN_SCALE = 0.75f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setAlpha(1);
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
} else if (position <= 1) { // (0,1]
// Fade the page out.
view.setAlpha(1 - position);
// Counteract the default slide transition
// view.setTranslationX(pageWidth * -position);
view.setTranslationX(pageWidth * -position + 44); // +44是因为ViewPager设置了android:paddingStart="22dp"
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
但是会出现一个问题,点击category切换page到最后一页,再滑动page准备循环,page内容页第一页的透明度就设置成了0。所以现在就没使用这个滑动动画,如果你程序中没有category只有ViewPager,那应该不会出现这个问题。。。
好啦,明天就是六一儿童节咯,祝愿所有童鞋们都能天真如孩童,少掉头发^&^