ViewPager 实现 Galler 效果, 中间大图显示,两边小图展示(优化篇)

简介: 上一张效果图:之前的项目有一个Galley的项目,但是代码结构特别乱,别问我为什么,我也是刚接手这个项目,为了方便以后阅读和维护我对一些模块进行了重构。ViewPager实现Galler效果,但是当时时间比较急,写的比较仓促,上一篇实现了简单的效果,但是对于初始的时候左边滑动是有问题的,这是因为我们在自己的Adapter的时候对于getCount,我们想通过Integer.MAX_VAL

上一张效果图:

之前的项目有一个Galley的项目,但是代码结构特别乱,别问我为什么,我也是刚接手这个项目,为了方便以后阅读和维护我对一些模块进行了重构。ViewPager实现Galler效果但是当时时间比较急,写的比较仓促,上一篇实现了简单的效果,但是对于初始的时候左边滑动是有问题的,这是因为我们在自己的Adapter的时候对于getCount,我们想通过Integer.MAX_VALUE来实现无限循环,简单的说这个是向右(无限大)吧,所以也就只是实现了向右的循环,对于像左的还是不行的。

那么怎么解决呢?

首先我们对Adapter还是需要按以前的写法,其实Adapter适配器就是帮我们做界面的,其他的逻辑最好不要加,我之前的想法是用过

viewPager.addOnPageChangeListener来实现,通过判断是否滑到最左边或者最右边来实现循环滑到。
 
 int realPosition = mAdapter.toRealPosition(position);
            if (mPreviousPosition != realPosition) {
                mPreviousPosition = realPosition;
                if (mOuterPageChangeListener != null) {
                    mOuterPageChangeListener.onPageSelected(realPosition);
                }
            }

这里我封装了一个类,只要将你的ViewPager改为我封装好的ViewPager就行
LoopViewPager 
 
public class LoopViewPager extends ViewPager {

    private static final boolean DEFAULT_BOUNDARY_CASHING = false;

    private OnPageChangeListener mOuterPageChangeListener;
    private LoopPagerAdapterWrapper mAdapter;
    private boolean mBoundaryCaching = DEFAULT_BOUNDARY_CASHING;

    public static int toRealPosition( int position, int count ){
        position = position-1;
        if( position < 0 ){
            position += count;
        }else{
            position = position%count;
        }
        return position;
    }
    
    public void setBoundaryCaching(boolean flag) {
        mBoundaryCaching = flag;
        if (mAdapter != null) {
            mAdapter.setBoundaryCaching(flag);
        }
    }

    @Override
    public void setAdapter(PagerAdapter adapter) {
        mAdapter = new LoopPagerAdapterWrapper(adapter);
        mAdapter.setBoundaryCaching(mBoundaryCaching);
        super.setAdapter(mAdapter);
        setCurrentItem(0, false);
    }

    @Override
    public PagerAdapter getAdapter() {
        return mAdapter != null ? mAdapter.getRealAdapter() : mAdapter;
    }

    @Override
    public int getCurrentItem() {
        return mAdapter != null ? mAdapter.toRealPosition(super.getCurrentItem()) : 0;
    }

    public void setCurrentItem(int item, boolean smoothScroll) {
        int realItem = mAdapter.toInnerPosition(item);
        super.setCurrentItem(realItem, smoothScroll);
    }

    @Override
    public void setCurrentItem(int item) {
        if (getCurrentItem() != item) {
            setCurrentItem(item, true);
        }
    }

    @Override
    public void setOnPageChangeListener(OnPageChangeListener listener) {
        mOuterPageChangeListener = listener;
    };

    public LoopViewPager(Context context) {
        super(context);
        init();
    }

    public LoopViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        super.setOnPageChangeListener(onPageChangeListener);
    }

    private OnPageChangeListener onPageChangeListener = new OnPageChangeListener() {
        private float mPreviousOffset = -1;
        private float mPreviousPosition = -1;

        @Override
        public void onPageSelected(int position) {

            int realPosition = mAdapter.toRealPosition(position);
            if (mPreviousPosition != realPosition) {
                mPreviousPosition = realPosition;
                if (mOuterPageChangeListener != null) {
                    mOuterPageChangeListener.onPageSelected(realPosition);
                }
            }
        }

        @Override
        public void onPageScrolled(int position, float positionOffset,
                int positionOffsetPixels) {
            int realPosition = position;
            if (mAdapter != null) {
                realPosition = mAdapter.toRealPosition(position);

                if (positionOffset == 0
                        && mPreviousOffset == 0
                        && (position == 0 || position == mAdapter.getCount() - 1)) {
                    setCurrentItem(realPosition, false);
                }
            }

            mPreviousOffset = positionOffset;
            if (mOuterPageChangeListener != null) {
                if (realPosition != mAdapter.getRealCount() - 1) {
                    mOuterPageChangeListener.onPageScrolled(realPosition,
                            positionOffset, positionOffsetPixels);
                } else {
                    if (positionOffset > .5) {
                        mOuterPageChangeListener.onPageScrolled(0, 0, 0);
                    } else {
                        mOuterPageChangeListener.onPageScrolled(realPosition,
                                0, 0);
                    }
                }
            }
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            if (mAdapter != null) {
                int position = LoopViewPager.super.getCurrentItem();
                int realPosition = mAdapter.toRealPosition(position);
                if (state == ViewPager.SCROLL_STATE_IDLE
                        && (position == 0 || position == mAdapter.getCount() - 1)) {
                    setCurrentItem(realPosition, false);
                }
            }
            if (mOuterPageChangeListener != null) {
                mOuterPageChangeListener.onPageScrollStateChanged(state);
            }
        }
    };

}

LoopPagerAdapterWrapper
 
 
public class LoopPagerAdapterWrapper extends PagerAdapter {

    private PagerAdapter mAdapter;

    private SparseArray<ToDestroy> mToDestroy = new SparseArray<ToDestroy>();

    private boolean mBoundaryCaching;

    void setBoundaryCaching(boolean flag) {
        mBoundaryCaching = flag;
    }

    LoopPagerAdapterWrapper(PagerAdapter adapter) {
        this.mAdapter = adapter;
    }

    @Override
    public void notifyDataSetChanged() {
        mToDestroy = new SparseArray<ToDestroy>();
        super.notifyDataSetChanged();
    }

    int toRealPosition(int position) {
        int realCount = getRealCount();
        if (realCount == 0)
            return 0;
        int realPosition = (position-1) % realCount;
        if (realPosition < 0)
            realPosition += realCount;

        return realPosition;
    }

    public int toInnerPosition(int realPosition) {
        int position = (realPosition + 1);
        return position;
    }

    private int getRealFirstPosition() {
        return 1;
    }

    private int getRealLastPosition() {
        return getRealFirstPosition() + getRealCount() - 1;
    }

    @Override
    public int getCount() {
        return mAdapter.getCount() + 2;
    }

    public int getRealCount() {
        return mAdapter.getCount();
    }

    public PagerAdapter getRealAdapter() {
        return mAdapter;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        int realPosition = (mAdapter instanceof FragmentPagerAdapter || mAdapter instanceof FragmentStatePagerAdapter)
                ? position
                : toRealPosition(position);

        if (mBoundaryCaching) {
            ToDestroy toDestroy = mToDestroy.get(position);
            if (toDestroy != null) {
                mToDestroy.remove(position);
                return toDestroy.object;
            }
        }
        return mAdapter.instantiateItem(container, realPosition);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        int realFirst = getRealFirstPosition();
        int realLast = getRealLastPosition();
        int realPosition = (mAdapter instanceof FragmentPagerAdapter || mAdapter instanceof FragmentStatePagerAdapter)
                ? position
                : toRealPosition(position);

        if (mBoundaryCaching && (position == realFirst || position == realLast)) {
            mToDestroy.put(position, new ToDestroy(container, realPosition,
                    object));
        } else {
            mAdapter.destroyItem(container, realPosition, object);
        }
    }

    @Override
    public void finishUpdate(ViewGroup container) {
        mAdapter.finishUpdate(container);
    }

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

    @Override
    public void restoreState(Parcelable bundle, ClassLoader classLoader) {
        mAdapter.restoreState(bundle, classLoader);
    }

    @Override
    public Parcelable saveState() {
        return mAdapter.saveState();
    }

    @Override
    public void startUpdate(ViewGroup container) {
        mAdapter.startUpdate(container);
    }

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        mAdapter.setPrimaryItem(container, position, object);
    }

    static class ToDestroy {
        ViewGroup container;
        int position;
        Object object;

        public ToDestroy(ViewGroup container, int position, Object object) {
            this.container = container;
            this.position = position;
            this.object = object;
        }
    }

}

这里需要注意对于上一篇的 WelfareAdapter ,我们就按常规写法就行。
public class WelfareAdapter extends PagerAdapter {

    private Context mContext;
    private List<PanicBean> dataList = new ArrayList<>();

    public WelfareAdapter(Context mContext) {
        this.mContext = mContext;
    }

    public void setDatas(List<PanicBean> list) {
        if (list.size() <= 0) {
            dataList.clear();
            notifyDataSetChanged();
            return;
        }
        dataList.clear();
        dataList.addAll(list);
        notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return /*Integer.MAX_VALUE*/dataList.size();
    }

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

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

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
//        position %= dataList.size();
//        if (position<0){
//            position = dataList.size()+position;
//        }

            PanicBean data = dataList.get(position);

            ViewHolder viewHolder = null;
            View view = LayoutInflater.from(mContext).inflate(
                    R.layout.item_finefare_layout, null);
            if (viewHolder == null) {
                viewHolder = new ViewHolder(view);
            }
            bindView(viewHolder, data);

            container.addView(view, LayoutParams.MATCH_PARENT,
                    LayoutParams.MATCH_PARENT);

            return view;
    }

    private void bindView(ViewHolder viewholder, final PanicBean data) {
        Glide.with(mContext).load(data.pic).into(viewholder.welfareImage);

        viewholder.welfareImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ToastUtils.showToast("你点击了"+data.href);
            }
        });
    }

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

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

    class ViewHolder {
        @BindView(R.id.welfare_image)
        RoundedImageView welfareImage;

        ViewHolder(View view) {
            ButterKnife.bind(this, view);
            view.setTag(this);
        }

        public void reset() {
            welfareImage.setBackground(mContext.getResources().getDrawable(R.drawable.welfare_default_icon));
        }
    }

}

部分源码: https://github.com/xiangzhihong/jingdongApp



目录
相关文章
|
11天前
|
小程序 容器
小程序图片水平垂直居中显示在view中
小程序图片水平垂直居中显示在view中
|
9月前
不用涉及到各种冲突常规打造酷炫下拉视差效果SmartRefreshLayout+ViewPager+RecyclerView
不用涉及到各种冲突常规打造酷炫下拉视差效果SmartRefreshLayout+ViewPager+RecyclerView
124 0
向上滑动导航固定头部demo效果图示例(整理)
向上滑动导航固定头部demo效果图示例(整理)
鼠标可控的表格滑动(左右)demo效果示例(整理)
鼠标可控的表格滑动(左右)demo效果示例(整理)
|
前端开发 容器
BottomNavigationView使用,配合ViewPager、修改图标大小、去掉文字等
BottomNavigationView使用,配合ViewPager、修改图标大小、去掉文字等
573 0
BottomNavigationView使用,配合ViewPager、修改图标大小、去掉文字等
减小TabLayout高度而不影响每个tab展示的几种方法
在Support Design库中有一个新的组件TabLayout,配合TabItem实现tab页面的形式。 但是图标和文字组合的tab的默认情况下,TabLayout中的tab太高,占据太多布局。 但是如果直接将TabLayout高度改小,很容易出现图标显示不全的情况,因为图标和字体及两者的间距没有跟着改变。 这时可以从几个方面处理:
234 0
|
Android开发
【Android 应用开发】Paint 渲染 之 BitmapShader 位图渲染 ( 渲染流程 | CLAMP 拉伸最后像素 | REPEAT 重复绘制图片 | MIRROR 绘制反向图片 )(二)
【Android 应用开发】Paint 渲染 之 BitmapShader 位图渲染 ( 渲染流程 | CLAMP 拉伸最后像素 | REPEAT 重复绘制图片 | MIRROR 绘制反向图片 )(二)
247 0
【Android 应用开发】Paint 渲染 之 BitmapShader 位图渲染 ( 渲染流程 | CLAMP 拉伸最后像素 | REPEAT 重复绘制图片 | MIRROR 绘制反向图片 )(二)
|
前端开发 Android开发
【Android 应用开发】Paint 渲染 之 BitmapShader 位图渲染 ( 渲染流程 | CLAMP 拉伸最后像素 | REPEAT 重复绘制图片 | MIRROR 绘制反向图片 )(一)
【Android 应用开发】Paint 渲染 之 BitmapShader 位图渲染 ( 渲染流程 | CLAMP 拉伸最后像素 | REPEAT 重复绘制图片 | MIRROR 绘制反向图片 )(一)
362 0
|
开发框架 容器
Flutter NestedScrollView实现的一个经典滑动折叠头部图片的效果
Flutter是谷歌推出的最新的移动开发框架。 Flutter NestedScrollView 滑动组件是用来处理复杂情况下的滑动应用场景,如向上滑动视图时,要折叠隐藏一部分内容,这时候就需要使用到 NestedScrollView 与 SliverAppBar 的结合使用。
Flutter NestedScrollView实现的一个经典滑动折叠头部图片的效果