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

图片轮播,一页两页,一页两页

首先明确需求:

1.       图片轮播器由若干张不定的页面构成,每个页面上的元素包括:图片(必选) + 指示器(可选,可能是点点点,可能是数字等)

2.       可以手势滑动图片的切换

3.       闭环展示,第一张的左边是最后一张,最后一张的右边是第一张,无限循环播放。

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

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

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

34public class CustomCirclePageAdapter   extends CirclePageAdapter   {

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;

}

}

自定义指示器(可选),实现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

35public class CustomBannerIndicator   extends LinearLayout   implements BannerIndicator   {

private List 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);

}

}

}

配置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

27public class CustomImageBanner   extends ImageBanner   {

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   initCirclePageAdapter() {

return new CustomCirclePageAdapter(getContext());

}

@Override

protected int getBannerIndicatorViewId() {

return R.id.image_indicator;

}

}

在xml中使用:

[代码]xml代码:1

2

3

4

5

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的样式就是博文上的示意图,谢谢大家的阅读~

JAVA轮播器_Android 图片轮播器的实现及源码解析相关推荐

  1. Java生鲜电商平台-秒杀系统微服务架构设计与源码解析实战

    Java生鲜电商平台-秒杀系统微服务架构设计与源码解析实战 Java生鲜电商平台-  什么是秒杀 通俗一点讲就是网络商家为促销等目的组织的网上限时抢购活动 比如说京东秒杀,就是一种定时定量秒杀,在规定 ...

  2. Android Glide图片加载框架(二)源码解析之into()

    文章目录 一.前言 二.源码解析 1.into(ImageView) 2.GlideContext.buildImageViewTarget() 3.RequestBuilder.into(Targe ...

  3. Android Glide图片加载框架(二)源码解析之load()

    文章目录 一.前言 二.源码分析 1.load() Android Glide图片加载框架系列文章 Android Glide图片加载框架(一)基本用法 Android Glide图片加载框架(二)源 ...

  4. Android Glide图片加载框架(二)源码解析之with()

    文章目录 一.前言 二.如何阅读源码 三.源码解析 1.with() Android Glide图片加载框架系列文章 Android Glide图片加载框架(一)基本用法 Android Glide图 ...

  5. KBQA_多轮对话——模型源码解析(一)Pickle模块功能详解

    KBQA_多轮对话--模型源码解析(一)Pickle模块功能详解 pickle --- Python 对象序列化的基本功能 1.pickle基本概念 2.pickle 与 json 模块的比较 3.p ...

  6. 【详解】Ribbon 负载均衡服务调用原理及默认轮询负载均衡算法源码解析、手写

    Ribbon 负载均衡服务调用 一.什么是 Ribbon 二.LB负载均衡(Load Balancer)是什么 1.Ribbon 本地负载均衡客户端 VS Nginx 服务端负载均衡的区别 2.LB负 ...

  7. 美女图片采集器 源码+解析

    前言: 有一段时间没写博客了, "持之以恒"徽章都暗了, 实在不该. 前一段确实比较忙, ...小小地给自己的懒找个借口吧. 大二即将结束, 学习iOS也有一段时间了.今天抽点时间 ...

  8. 美女图片采集器 (源码+解析)

    前言: 有一段时间没写博客了, "持之以恒"徽章都暗了, 实在不该. 前一段确实比较忙, ...小小地给自己的懒找个借口吧. 大二即将结束, 学习iOS也有一段时间了.今天抽点时间 ...

  9. java毕业设计——基于Java+sqlserver的通用安全模块设计与实现(毕业论文+程序源码)——安全模块

    基于Java+sqlserver的通用安全模块设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于Java+sqlserver的通用安全模块设计与实现,文章末尾附有本毕业设计的论文和源码下载地 ...

最新文章

  1. 「深入浅出」了解语音识别的技术原理和应用价值?
  2. struts2中各版本jar包需求及配置设置
  3. 【ACM-ICPC 2018 沈阳赛区网络预赛 I】Lattice's basics in digital electronics
  4. 前端学习(1883)vue之电商管理系统电商系统之每次只能打开一个菜单项并解决边框问题
  5. Codeforces Round #346 (Div. 2) D. Bicycle Race 叉积
  6. iPhone12年简史:手机之王的荣耀与溃败
  7. HDOJ2026 ( 首字母变大写 ) 【水题】
  8. python 基础及资料汇总
  9. 深圳信息职业技术学校 计算机辅助设计和制造,大学生职业生涯规划书样稿.doc...
  10. 阿拉丁2021年度小程序白皮书发布,凡泰极客 FinClip 技术再度入选(内附完整白皮书下载)
  11. Python运算(五)统计statistic模块
  12. 共阴共阳数码管(及74HC595控制)
  13. Android4.1 新功能 新特性
  14. 在 Kubernetes 上运行 GitHub Actions Self-hosted Runner
  15. CUDA矩阵乘法优化
  16. 【排序】快排(霍尔快排)
  17. Procreate闪闪的神仙笔刷合集,IPad绘画必备
  18. java decvm_java – 如何使用-XX:UnlockDiagnosticVMOptions -XX:CompileCommand =打印选项与JVM HotSpot...
  19. ZYNQ从放弃到入门(八)-PS和PL交互
  20. PHP保持静态页面,PHP 实现页面静态化的几种方法

热门文章

  1. qsql 关联_SQL 中各种 join 用法
  2. C# 中使用SendMessage 函数
  3. 打开键盘遮住View的问题解决方法-IOS开发
  4. SPSS Statistics 24 中文版下载
  5. 【JAVA电子相册】
  6. mysql 冗余字段 同步_冗余数据一致性,到底如何保证?
  7. Java基础面试常常死在这几个问题上,看这篇足矣了!
  8. 2020年PHP面试题
  9. Springboot+WebSocket 自动重连机制
  10. ORACLE数据库 某用户账户被锁定问题解决