首先明确需求:
看一下我画的设计结构图(很丑,轻拍)
可以看到有这么几个对象:
ImageBanner:自定义控件,包含定时任务管理器TimerController、增强ViewPager、指示器BannerIndicator。内部包含了诸如开启,关闭轮播等逻辑。设计为抽象类,通过钩子方法实现UI样式的自定义。
TimerController: 定时任务管理器, 无论是Timer也好,手动设计的定时Handler也好,它的职责就是执行定时任务,具体到图片轮播器里,职责就通知CirclePageAdapter和BannerIndicator切换到下一张。
CustomSwipeViewPager: 增强ViewPager, 方便随时禁止和开启手势滑动。
CirclePageAdapter: ViewPager的adapter, 通过在左右两边各增加一个伪Pager,滑动到0,和最后一个时,无动画切换到最后一个和0,从而实现循环滑动。同样设计为抽象类,ImageView的样式,图片加载的方式等同样通过钩子方法留出来供使用者自定义。
BannerIndicator: 指示器,设计成接口形式,实现该接口的自定义View都可以作为轮播器当中的指示器。最大程度自定义UI。
如何使用?
派生CirclePageAdapter,实现单个图片加载的样式和点击事件
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接口即可
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
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中使用:
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" /> |
传入数据,正确的开启和关闭轮播的定时器:
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的样式就是博文上的示意图,谢谢大家的阅读~