使用ViewPager.PageTransformer自定义ViewPager

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

源码

地址

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值