您的位置:首页 > 移动开发 > Android开发

图片轮播控件Android版开发文档-version0.1

2016-01-09 13:22 393 查看
图片轮播控件Android版version0.1已在简书中发布,请先前往查看。本文详细介绍该控件的实现原理。

需求分析

为了实现一个功能丰富、适配各种设备的通用型图片轮播控件,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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: