您好,欢迎来到源码搜藏!分享精神,快乐你我!提示:担心找不到本站?在百度搜索“源码搜藏”,网址永远不丢失!
  • 首 页
  • 在线工具
  • 当前位置:首页 > 安卓源码 > 技术博客 >

    Android 图片轮播器的实现及源码解析

    时间:2016-12-06 22:26 来源:互联网 作者:源码搜藏 浏览:收藏 挑错 推荐 打印

    在很多产品,尤其是电商类社区内的网页或者app中,我们经常会看到一个图片轮播墙,一页一页的广告/活动/商品介绍每隔一段时间就切换到下一张。那在安卓中我们该如何实现图片轮播器呢?面对自定义样式、自定义图片加载框架等等复杂的自定义需求,如何设计接口 在很多产品,尤其是电商类社区内的网页或者app中,我们经常会看到一个图片轮播墙,一页一页的广告/活动/商品介绍每隔一段时间就切换到下一张。那在安卓中我们该如何实现图片轮播器呢?面对自定义样式、自定义图片加载框架等等复杂的自定义需求,如何设计接口使得使用者可以很方便的自定义属性呢?接下来我从wangyeming/ImageBanner源码出发,探讨下我对这个小小功能框架的设计和实现。

    图片轮播,一页两页,一页两页
    Android 图片轮播器的实现及源码解析

    首先明确需求:

    1. 图片轮播器由若干张不定的页面构成,每个页面上的元素包括:图片(必选) + 指示器(可选,可能是点点点,可能是数字等)
    2. 可以手势滑动图片的切换
    3. 闭环展示,第一张的左边是最后一张,最后一张的右边是第一张,无限循环播放。

    看一下我画的设计结构图(很丑,轻拍)

    Android 图片轮播器的实现及源码解析

    可以看到有这么几个对象:

    ImageBanner:自定义控件,包含定时任务管理器TimerController、增强ViewPager、指示器BannerIndicator。内部包含了诸如开启,关闭轮播等逻辑。设计为抽象类,通过钩子方法实现UI样式的自定义。

    TimerController: 定时任务管理器, 无论是Timer也好,手动设计的定时Handler也好,它的职责就是执行定时任务,具体到图片轮播器里,职责就通知CirclePageAdapter和BannerIndicator切换到下一张。

    CustomSwipeViewPager: 增强ViewPager, 方便随时禁止和开启手势滑动。

    CirclePageAdapter: ViewPager的adapter, 通过在左右两边各增加一个伪Pager,滑动到0,和最后一个时,无动画切换到最后一个和0,从而实现循环滑动。同样设计为抽象类,ImageView的样式,图片加载的方式等同样通过钩子方法留出来供使用者自定义。

    BannerIndicator: 指示器,设计成接口形式,实现该接口的自定义View都可以作为轮播器当中的指示器。最大程度自定义UI。

    如何使用?

    派生CirclePageAdapter,实现单个图片加载的样式和点击事件

    [代码]java代码:

    ?
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    public class CustomCirclePageAdapter extends CirclePageAdapter<bannerimage> {
        public CustomCirclePageAdapter(Context context) {
            super(context);
        }
        @Override
        protected void showImage(ImageView vImage, BannerImage bannerImage) {
            //自定义采用何种图片加载方式
            Glide.with(mContext)
                .load(bannerImage.getImagePath())
                .placeholder(R.drawable.default_loading)
                .error(R.drawable.topic_pic)
                .dontAnimate()
                .into(vImage);
        }
        @Override
        protected void onClickImage(final BannerImage bannerImage) {
            //自定义每张图片的点击事件
            Uri uri = Uri.parse(bannerImage.getLink());
            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
            try {
                mContext.startActivity(intent);
            } catch (Exception e) {
               e.printStackTrace();
            }
        }
        @Override
        protected ImageView createImageView() {
            //自定义图片的样式
            ImageView vImage = new ImageView(mContext);
            vImage.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, DemoUtil.dp2px(mContext, 100)));
            vImage.setScaleType(ImageView.ScaleType.FIT_XY);
            return vImage;
        }
    }</bannerimage>

    自定义指示器(可选),实现BannerIndicator接口即可

    [代码]java代码:

    ?
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    public class CustomBannerIndicator extends LinearLayout implements BannerIndicator {
        private List<imageview> vimg = new ArrayList<>();
        public CustomBannerIndicator(Context context) {
            this(context, null);
        }
        public CustomBannerIndicator(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
        public CustomBannerIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
        private void init() {
            setOrientation(HORIZONTAL);
        }
        @Override
        public void showInitState(int imageCount) {
            for (int i = 0; i < imageCount; i++) {
                ImageView vImage = new ImageView(getContext());
                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
                int margin = DemoUtil.dp2px(getContext(), 10);
                layoutParams.setMargins(margin, 0, margin, 0);
                vImage.setLayoutParams(layoutParams);
                vimg.add(vImage);
                vImage.setBackgroundResource(i == 0 ? R.drawable.dot_choosen_ic : R.drawable.dot_unchoosen_ic);
                addView(vImage);
            }
        }
        @Override
        public void notifyIndexChanged(int indexOfImage) {
            for (int i = 0; i < vimg.size(); i++) {
                vimg.get(i).setBackgroundResource(i == indexOfImage ? R.drawable.dot_choosen_ic : R.drawable.dot_unchoosen_ic);
            }
        }
    }</imageview>

    配置ImageBanner

    [代码]java代码:

    ?
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class CustomImageBanner extends ImageBanner<bannerimage> {
        public CustomImageBanner(Context context) {
            super(context);
        }
        public CustomImageBanner(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
        public CustomImageBanner(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
        @Override
        protected int getLayoutRes() {
            return R.layout.custom_banner;
        }
        @Override
        protected int getImagePagerViewId() {
            return R.id.image_parer;
        }
        @Override
        protected CirclePageAdapter<bannerimage> initCirclePageAdapter() {
            return new CustomCirclePageAdapter(getContext());
        }
        @Override
        protected int getBannerIndicatorViewId() {
            return R.id.image_indicator;
        }
    }</bannerimage></bannerimage>

    在xml中使用:

    [代码]xml代码:

    ?
    1
    2
    3
    4
    5
    <com.tianyeguang.imagebanner.banner.CustomImageBanner
            android:id="@+id/custom_image_banner"
            android:layout_width="match_parent"
            android:layout_height="136dp"
            android:layout_margin="16dp"/>

    传入数据,正确的开启和关闭轮播的定时器:

    [代码]java代码:

    ?
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    @Override
    protected void onResume() {
        super.onResume();
        vBanner.start();
    }
    @Override
    protected void onPause() {
        vBanner.finish();
        super.onPause();
    }

    具体的代码大家可以查看demo, demo的样式就是博文上的示意图,谢谢大家的阅读~


    Android 图片轮播器的实现及源码解析转载http://www.codesocang.com/anzhuoyuanma/boke/33972.html
    标签:网站源码