ViewPager 实现 Galler 效果, 中间大图显示,两边小图展示(优化篇)
上一张效果图:
之前的项目有一个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); } } }; }LoopPagerAdapterWrapperpublic 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)); } } }
ViewPager 实现 Galler 效果, 中间大图显示,两边小图展示(优化篇)的更多相关文章
- ViewPager 实现 Galler 效果, 中间大图显示,两边小图展示
正常情况下, ViewPager 一页只能显示一项数据, 但是我们常常看到网上,特别是电视机顶盒的首页经常出现中间大图显示两端也都露出一点来,这种效果怎么实现呢?先上一张效果图: 大家第一眼肯定想到了 ...
- 【笔记】WPF实现ViewPager引导界面效果及问题汇总
最近在开发项目的首次使用引导界面时,遇到了问题,引导界面类似于安卓手机ViewPager那样的效果,希望通过左右滑动手指来实现切换不同页面,其间伴随动画. 实现思路: 1.界面布局:新建一个UserC ...
- 基于jQuery左侧小图滚动右侧大图显示代码
今天给大家分享一款 jQuery左侧小图滚动右侧大图显示代码是一款基于jQuery实现的左侧滚动图片点击大图查看效果代码.该实例适用浏览器:IE8.360.FireFox.Chrome.Safari. ...
- jQuery 效果 —— 隐藏和显示
jQuery 效果 -- 隐藏和显示 1.隐藏和显示 (1)在jQuery中我们可以使用hide()和show()分别隐藏和显示HTML元素: //隐藏元素 $("button") ...
- windows7文件夹怎样默认图片大图显示?
先打开一个含有图片的文件夹,在文件夹空白处右键选择属性,打开自定义选项卡. 确定自定义选项卡 显示的是:“优化此文件夹:图片”. 然后,选择:组织--文件夹和搜索选项--查看--文件夹视图,应用到文件 ...
- 精致3D图片切换效果,最适合企业产品展示
这是一个精致的立体图片切换效果,特别适合企业产品展示,可立即用于实际项目中.支持导航和自动播放功能, 基于 CSS3 实现,推荐使用最新的 Chrome,Firefox 和 Safari 浏览器浏览效 ...
- TexturePacker大图还原成小图工具带源码
TexturePacker是一个把好多小图打成大图的软件,生成的是大图以及小图在大图位置的.plist描述文件,但是不支持把大图还原成小图.网上偷的图一般都是大图和plist,想得到小图比较麻烦,于是 ...
- Python - 工具:将大图切片成小图,将小图组合成大图
训练keras时遇到了一个问题,就是内存不足,将 .fit 改成 .fit_generator以后还是放不下一张图(我的图片是8192×8192的大图==64M).于是解决方法是将大图切成小图,把小图 ...
- Android照片墙加强版,使用ViewPager实现画廊效果
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/12646775 记得关于照片墙的文章我已经写过好几篇了,有最基本的照片墙,有瀑布流模 ...
随机推荐
- dubbo服务的发布和调用
Dubbo是分布式服务架构,是一个优秀的开源服务型框架,使得应用可以通过高性能的rpc实现服务的输入和输出功能.其实dubbo就是资源调度和治理中心的管理工具. 发布dubbo服务:在提供服务的应用中 ...
- 高效update方案
--方案1:如果有索引,先把索引删除后,再update,最后把索引重新创建一下因为索引对update影响很大. --方案2:1.create table newA as select id,name, ...
- 剑指架构师系列-Redis安装与使用
1.安装Redis 我们在VMware中安装CentOS 64位系统后,在用户目录下下载安装Redis. 下载redis目前最稳定版本也是功能最完善,集群支持最好并加入了sentinel(哨兵-高可用 ...
- vue以及js的一些坑或常用技巧
判断空object Object.getOwnPropertyNames(obj).length === 0 模拟range Array.apply(null, Array(5)).map(funct ...
- Hibernate与JPA的区别是什么
翻译来源:https://www.quora.com/What-is-the-difference-between-Hibernate-and-JPA 本文作者:苏生米沿 本文地址:http://bl ...
- JVM:类的生命周期
类的生命周期 综述 1. 只有当一个类被切实使用到的时候才会被加载到虚拟机中(例如:new, 方法调用, A a = null;不算) 2. 若在加载一个类的过程中,有其他类被切实使用到, ...
- Swift3中dispatch_once废弃的解决办法
在Swift中如果想搞类的单例模式,那么在初始化的时候一般会使用just one time执行的方式,我们使用dispatch_once_t配合调用dispatch_once方法,一般的代码如下: s ...
- 如何找出Xcode中不同版本Swift的路径
我们知道Xcode中可能包含不知一个Swift的版本,那么我们如何找到它们对应的路径呢? 熟悉unix shell命令的童鞋都知道有一个find指令,在我们已知Xcode路径时,我们可以在其中找到Sw ...
- JAVA进阶之旅(二)——认识Class类,反射的概念,Constructor,Field,Method,反射Main方法,数组的反射和实践
JAVA进阶之旅(二)--认识Class类,反射的概念,Constructor,Field,Method,反射Main方法,数组的反射和实践 我们继续聊JAVA,这次比较有意思,那就是反射了 一.认识 ...
- ListView之侧滑删除
SwipeMenuListView 是一个为listview添加item侧滑菜单的开源库,项目地址:https://github.com/baoyongzhang/SwipeMenuListView ...