ViewPager是最常用的作为项目的引导页,不过用久了就感觉没啥意思了,最近网上看到了这样的自定义效果,感觉挺酷的,正好自己的项目也用到了。
就仿照着实现了一把。
接下来就简单介绍下实现的步骤吧
项目结构
可以看见项目有两个Module,第一个app是和自己的应用业务逻辑相关,用来绑定业务数据的,第二个customeviewpager是封装的viewpager相关逻辑,可以复用一般的业务需求。
自定义viewpager
public class CustomViewPager extends ViewPager {
private Context mContext;
private int max_offset;
private boolean mIsLoop = false;
public CustomViewPager(Context context) {
this(context, null);
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
setClipToPadding(false);
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomViewPager);
int padding = (int) typedArray.getDimension(R.styleable.CustomViewPager_vp_padding, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, metrics));
setPadding(getPaddingLeft() + padding, getPaddingTop(), getPaddingRight() + padding, getPaddingBottom());
int margin = (int) typedArray.getDimension(R.styleable.CustomViewPager_vp_margin, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40, metrics));
setPageMargin(margin);
max_offset = (int) typedArray.getDimension(R.styleable.CustomViewPager_vp_max_offset, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 180, metrics));
mIsLoop = typedArray.getBoolean(R.styleable.CustomViewPager_vp_loop, mIsLoop);
typedArray.recycle();
}
/**
* 必须调用 绑定数据
*/
public <T> void bindView(List<T> data, ItemViewHandler<T> handler){
List<ItemView> itemViews = getItemViews(data, handler);
MyPagerAdapter myPagerAdapter = new MyPagerAdapter(itemViews, mIsLoop);
setPageTransformer(false, new CustomPageTransforms(max_offset));
setAdapter(myPagerAdapter);
}
private <T> List<ItemView> getItemViews(List<T> data, ItemViewHandler<T> handler) {
if(data == null){
throw new RuntimeException("data can not null");
}
List<ItemView> itemViews = new ArrayList<>();
for (T t: data) {
ItemView itemView = new ItemView(handler.bind(mContext, t));
itemViews.add(itemView);
}
return itemViews;
}
}
代码量不多,首先在初始化时获取了自定义的相关属性,关键的一个方法bindView是用来给用户绑定数据,有两个参数,第一个数据源,第二个绑定的数据接口,给用户去实现,用户只需要实现其方法,并返回相应的view就可以了。数据封装到view,然后封装到itemView就可以了。
itemView
public class ItemView {
public View view;
public ItemView(View view){
if(view == null){
throw new RuntimeException("View can not be null!!");
}
this.view = view;
}
public View getView() {
return view;
}
public void setView(View view) {
this.view = view;
}
}
itemViewHandler
public interface ItemViewHandler<T> {
View bind(Context context, T data);
}
自定义pageradpater
public class MyPagerAdapter extends PagerAdapter {
private List<ItemView> mItemViews;
private boolean mIsLoop;
public MyPagerAdapter(List<ItemView> itemViews, boolean isLoop){
mItemViews = itemViews;
mIsLoop = isLoop;
}
@Override
public int getCount() {
return mIsLoop? Integer.MAX_VALUE : getItems();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
if(mIsLoop){
position = position % getItems();
}
container.addView(mItemViews.get(position).getView());
return mItemViews.get(position).getView();
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if(mIsLoop){
ViewPager vp = (ViewPager)container;
int i = vp.getCurrentItem() % getItems();
int j = position % getItems();
if(i > j - 2 && i < j + 2){
return;
}
container.removeView(mItemViews.get(j).getView());
}
container.removeView(mItemViews.get(position % getItems()).getView());
}
@Override
public void startUpdate(ViewGroup container) {
super.startUpdate(container);
if(mIsLoop){
ViewPager vp = (ViewPager)container;
int position = vp.getCurrentItem();
if(position == 0){
position = Integer.MAX_VALUE / 2;
}else if(position == getItems() - 1){
position = Integer.MAX_VALUE / 2 - 1;
}
vp.setCurrentItem(position, false);
}
}
public int getItems(){
return mItemViews == null? 0:mItemViews.size();
}
}
可以看见整个pageradapter已经封装模块化了,用户不需要再去重复实现apapter。并且里面有循环和不循环滑动两种模式。
效果
用到了cardView就不多说了。
参考
1.http://mp.weixin.qq.com/s/P8Slyl7i1gyWGZXcvccYTQ
2.http://blog.csdn.net/u012702547/article/details/52334161
3.http://blog.csdn.net/lmj623565791/article/details/38026503