图片轮播控件Android版开发文档-version0.1
2016-01-09 13:22
393 查看
图片轮播控件Android版version0.1已在简书中发布,请先前往查看。本文详细介绍该控件的实现原理。
+ 基本的图片轮播展示功能,可左右翻页
+ 自动循环播放,由定时器控制每3秒向右翻动一页,最后一页继续翻页到第一页。可在程序中禁用自动播放。
+ 横竖屏自动适配,以该控件的高度宽度比为判断标准。当高度大于宽度时,作为竖屏模式处理,每次只显示一个图片;当宽度大于高度时,作为横屏模式处理,每次显示多个图片,每个图片具有相同的高度和宽度,都等于控件的高度。
这段代码即大家公认的
至此,控件已经实现了基本的图片展示功能,可以手动滑动翻页。接下来需要实现循环翻页和定时翻页功能。
使用
在
定时翻页功能的实现非常简单,只要使用一个定时器就能完成,此处不再赘述。
最后一个非常关键的技术手段就是横竖屏适配。需要在控件初始化的时候确定当前应该选择哪种模式,如果是竖屏模式,那么代码不需做任何改动,使用
为了在控件加载完成后获取它的大小,使用了控件的
至此,整个控件的核心原理已经叙述完毕。
如有疑问,请直接回复或发送邮件到wjg172184@163.com。
需求分析
为了实现一个功能丰富、适配各种设备的通用型图片轮播控件,0.1版本暂提出如下需求:+ 基本的图片轮播展示功能,可左右翻页
+ 自动循环播放,由定时器控制每3秒向右翻动一页,最后一页继续翻页到第一页。可在程序中禁用自动播放。
+ 横竖屏自动适配,以该控件的高度宽度比为判断标准。当高度大于宽度时,作为竖屏模式处理,每次只显示一个图片;当宽度大于高度时,作为横屏模式处理,每次显示多个图片,每个图片具有相同的高度和宽度,都等于控件的高度。
实现原理
本控件使用一个ViewPager作为图片轮播的主体,在底部添加一个
LinearLayout作为若干个圆点的容器,当前选中的图片对应的圆点为亮色,其它为暗色。控件的xml布局如下:
[code]<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rtv_container" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="false" > <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginLeft="0dp" android:layout_marginRight="0dp" android:clipChildren="false" /> <LinearLayout android:id="@+id/dot_container" android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:layout_alignParentBottom="true" android:layout_centerInParent="true" android:gravity="center" /> </RelativeLayout>
ViewPager需要自定义一个适配器
ViewPagerAdapter,继承自
PagerAdapter:
[code]class ViewPagerAdapter extends PagerAdapter { private List<View> views; public ViewPagerAdapter (List<View> views) { this.views = views; } //销毁position位置的界面 @Override public void destroyItem(ViewGroup container, int position, Object object) { ((ViewPager)container).removeView(views.get(position)); } //获得当前界面数 @Override public int getCount() { return views.size(); } //初始化position位置的界面 @Override public Object instantiateItem(ViewGroup container, final int position) { View view = views.get(position); container.addView(view); return view; } //判断是否由对象生成界面 @Override public boolean isViewFromObject(View view, Object object) { return (view == object); } }
这段代码即大家公认的
ViewPager的适配器代码,未做任何改动,因此不必赘述。
至此,控件已经实现了基本的图片展示功能,可以手动滑动翻页。接下来需要实现循环翻页和定时翻页功能。
使用
ViewPager实现循环翻页并不是件容易的事情,网络上公认的两种解决方法都有或多或少的缺陷。我提出了一种新的解决方法,详细内容可以参考我的另一篇博文《真无限循环的ViewPager——解决两端滑动的平滑问题》,不过在这里我还是要简单介绍一下。在网络上流行的真无限循环的
ViewPager解决方案中,使用CABCA的图片序列代替实际的图片序列ABC。在向右从第2个C翻页到第2个A后,自动跳转到第1个A(不带过渡效果);在向左从第1个A翻页到第1个C后,自动跳转到第2个C(不带过渡效果)。以此方式实现循环翻页。但问题是如果在
onPageSelected中做如上所述的跳转,将得到不连续的翻页体验。因此我的实现方法是在
onPageScrollStateChanged中跳转。先看
ViewPager的监听器实现类
MyPageChangeListener的代码,实现了
OnPageChangeListener接口:
[code]private final class MyPageChangeListener implements OnPageChangeListener { @Override public void onPageScrollStateChanged(int state) { if (state == ViewPager.SCROLL_STATE_IDLE) { if (currentPosition == views.size() - 1) { viewPager.setCurrentItem(1, false); } else if (currentPosition == 0) { viewPager.setCurrentItem(views.size() - 2, false); } } } @Override public void onPageScrolled(int scrolledPosition, float percent, int pixels) { //empty } @Override public void onPageSelected(int position) { currentPosition = position; } }
在
onPageSelected方法中只需要记录新到达的页面的下标,由于该方法调用的时候,翻页的过渡过程还没有结束,所以在
onPageScrollStateChanged方法中,等待到达
SCROLL_STATE_IDLE状态。一旦到达
IDLE状态,说明翻页的过渡过程完全结束,这时候再去判断当前页是哪一页,是否需要立即跳转。经过测试,这种方式达到了很好的效果。另外,上面的代码为了突出重点,略去了一些设置控件底部小圆点的程序段。
定时翻页功能的实现非常简单,只要使用一个定时器就能完成,此处不再赘述。
最后一个非常关键的技术手段就是横竖屏适配。需要在控件初始化的时候确定当前应该选择哪种模式,如果是竖屏模式,那么代码不需做任何改动,使用
ViewPager的默认设置就可以了;如果是横屏模式,就需要对
ViewPager做一些个性化的设置。根据我们的需求分析,横屏时每个图片占据一个正方形大小的空间,正方形的边长等于控件的高度。
ViewPager有个特殊的用法,当我们把它的
clipChildren属性设为
false,并将它的左右
margin扩大,
margin占据的空间就会显示出相邻的图片,而且
margin越大,显示出的图片就越多。请看如下代码:
[code]ViewTreeObserver vto = viewPager.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @SuppressWarnings("deprecation") @Override public void onGlobalLayout() { viewPager.getViewTreeObserver().removeGlobalOnLayoutListener(this); int height = viewPager.getHeight(); int width = viewPager.getWidth(); RelativeLayout.LayoutParams viewPagerLayoutParams = (RelativeLayout.LayoutParams) viewPager.getLayoutParams(); if(height < width) { viewPagerLayoutParams.leftMargin = (width - height) / 2; viewPagerLayoutParams.rightMargin = (width - height) / 2; viewPager.setLayoutParams(viewPagerLayoutParams); } } });
为了在控件加载完成后获取它的大小,使用了控件的
ViewTreeObserver对象。我们判断高度和宽度的关系,如果高度小于宽度,则调整
ViewPager的左右
margin,调整的结果是整个控件的宽度除去左右
margin之后正好等于控件的高度。
至此,整个控件的核心原理已经叙述完毕。
如有疑问,请直接回复或发送邮件到wjg172184@163.com。
相关文章推荐
- Android简单计时器详解(Timer)
- Android朋友圈评论功能知识点记录
- 理解Android虚拟机体系结构(转)
- Android SurfaceView实战 打造抽奖转盘
- android 禁止scrollview 因控件变化自动滚动到底的方法
- Android 之自定义弹出提示框
- 优雅(简单粗暴)的使用AndroidStudio
- android SQLite getWritableDatabase VS getReadableDatabase
- Android ViewGroup使用小结
- Android自动化测试课程大纲
- (转)美团Android自动化之旅—适配渠道包
- (转)美团Android资源混淆保护实践
- android热更新
- (转)美团Android DEX自动拆包及动态加载简介
- Android 5.0新特性
- Maxwin-z/XListView-Android(下拉刷新上拉加载)源码解析(一)
- Android6.0系统权限那些事
- Eclips 开发 apk 使用android内部(com.android.internal) API
- Android5.0新特性 -- Material Design材料设计(1)
- Android如何缩放应用中的字体大小