自定义view————Banner轮播

自定义view————Banner轮播

今天给大家项目中应用很广泛的Banner轮播,每一个app都会用到这个,并且有时候会在多处去应用,这时候就在想了,把Banner轮播写成自定义view,直接传显示数据,接受点击事件的回调。在自己的实际项目中,可以根据自身的效果稍作修改,客官们,先上图(这次全部选择的是女神刘亦菲的照片)

效果图

各位客官,效果看了是否满意呀,来分析一下流程:viewpager+自身的监听方法+Handler实现滑动切换banner和banner轮播自身循环

显示view的选择

根据效果图,我们选取FrameLayout为父布局,里面用ViewPager+LinearLayout(代码中再去设置选择和未选择的状态)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:unselectedAlpha="1" />
<LinearLayout
android:id="@+id/layout_page"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center|bottom"
android:gravity="center"
android:orientation="horizontal"
android:padding="10dip" />
</FrameLayout>

将需要显示的view添加到自定义view中去显示,因为FrameLayout是父布局,我们这里也是继承FrameLayout去自定义view

这里在onFinishInflate()方法中去添加view,可以去了解一下onFinishInflate()的用法

1
2
3
4
5
6
7
8
9
10
11
@Override
protected void onFinishInflate() {
super.onFinishInflate();
View view = LayoutInflater.from(mContext).inflate(R.layout.banner_layout, null);
viewpager_banner = (ViewPager) view.findViewById(R.id.viewpager);
layout_page = (LinearLayout) view.findViewById(R.id.layout_page);
addView(view);
bannerModelList = new ArrayList<>();
bannerviewsList = new ArrayList<>();
}

根据假数据显示内容

实际项目中,数据都是传递过来的,我们也采用info传值过来的,然后根据数据进行显示的相关设置,后期可根基自己项目的info去修改

1
2
3
4
5
6
7
8
9
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
36
37
38
39
40
41
42
43
44
/**
* Created by wujun on 2017/8/11.
* banner的实体类,根据自己的实际项目去定制
* @author madreain
* @desc
*/
public class BannerModel {
private int id;
private String imgurl;
public BannerModel() {
}
public BannerModel(int id, String imgurl) {
this.id = id;
this.imgurl = imgurl;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getImgurl() {
return imgurl;
}
public void setImgurl(String imgurl) {
this.imgurl = imgurl;
}
@Override
public String toString() {
return "BannerModel{" +
"id=" + id +
", imgurl='" + imgurl + '\'' +
'}';
}
}

数据有了,就要有数据设置的方法和拿数据做展示

继承PagerAdapter去显示banner轮播中的照片

layout_page.addview()去添加效果图中的小圆点

addOnPageChangeListener()实现左右切换

1
2
3
4
5
6
7
8
9
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* 第一次设置数据的方法
*
* @param mbannerModelList
*/
public void setBannerModelList(List<BannerModel> mbannerModelList) {
this.bannerModelList = mbannerModelList;
// 本地
if (bannerModelList != null) {
if (bannerModelList.size() > 0) {
//本地存储
bannerModelListSize = bannerModelList.size();
for (BannerModel bannerModel : bannerModelList) {
ImageView imageView = new ImageView(mContext);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
// + "!thumb" 缩略图
Glide.with(mContext).load(bannerModel.getImgurl()).into(imageView);
bannerviewsList.add(imageView);
}
}
}
//添加小圆点的图片
if (bannerModelList != null) {
imageViews = new ImageView[bannerModelListSize];
for (int i = 0; i < bannerviewsList.size(); i++) {
imageView = new ImageView(mContext);
//设置小圆点imageview的参数
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(20, 20);
layoutParams.setMargins(10, 0, 10, 0);
// imageView.setLayoutParams(new ViewGroup.LayoutParams(20,20));//创建一个宽高均为20 的布局
imageView.setLayoutParams(layoutParams);//创建一个宽高均为20 的布局
imageView.setPadding(20, 0, 20, 0);
//默认选中的是第一张图片,此时第一个小圆点是选中状态,其他不是
if (i == 0) {
imageView.setBackgroundResource(R.drawable.shape_intro);
} else {
imageView.setBackgroundResource(R.drawable.shape_intro_nor);
}
//将imageviews添加到小圆点视图组
layout_page.addView(imageView);
imageViews[i] = imageView;
}
bannerViewPagerAdapter = new BannerViewPagerAdapter(bannerviewsList);
viewpager_banner.setAdapter(bannerViewPagerAdapter);
viewpager_banner.addOnPageChangeListener(new GuidePageChangeListener());
// viewpager_banner.setOnPageChangeListener(new GuidePageChangeListener());
}
}

继承PagerAdapter去显示banner轮播中的照片

1
2
3
4
5
6
7
8
9
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
36
37
38
39
40
41
42
43
44
45
//照片轮播的适配器
private class BannerViewPagerAdapter extends PagerAdapter {
private List<View> views;
private BannerViewPagerAdapter(List<View> views) {
this.views = views;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(views.get(position));
}
@Override
public void finishUpdate(ViewGroup container) {
}
@Override
public int getCount() {
if (views != null) {
return views.size();
}
return 0;
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
container.addView(views.get(position));
//单独的点击事件
views.get(position).setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
//todo这里后面将点击进行接口回调返回
}
});
return views.get(position);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}

addOnPageChangeListener()实现左右切换,实现OnPageChangeListener,来回切换,照片显示改变,小圆点的选中与未选中也跟着改变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//viewpager 监听 照片轮播
private class GuidePageChangeListener implements ViewPager.OnPageChangeListener {
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageSelected(int position) {
for (int i = 0; i < imageViews.length; i++) {
//设置index 防止下次自动播放顺序出错
index = viewpager_banner.getCurrentItem();
imageViews[position].setBackgroundResource(R.drawable.shape_intro);
//不是当前选中的page,其小圆点设置为未选中的状态
if (position != i) {
imageViews[i].setBackgroundResource(R.drawable.shape_intro_nor);
}
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
}

无限循环轮播

实际项目中的banner轮播是无限循环轮播的,这里我们使用Handler来达到预期的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//自动播放
private final int AUTO_MSG = 1;
private final int HANDLE_MSG = AUTO_MSG + 1;
private static final int PHOTO_CHANGE_TIME = 2000;//定时变量
private int index = 0;
//照片轮播设置无限循环播放
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case AUTO_MSG:
//无线循环播放
if (index >= bannerModelListSize) {
index = 0;
}
viewpager_banner.setCurrentItem(index++);//收到消息后设置当前要显示的图片
mHandler.sendEmptyMessageDelayed(AUTO_MSG, PHOTO_CHANGE_TIME);
break;
case HANDLE_MSG:
mHandler.sendEmptyMessageDelayed(AUTO_MSG, PHOTO_CHANGE_TIME);
break;
default:
break;
}
}
};

方法写完了,什么去触发了,我这里是在设置数据后调用,调用方法如下

1
2
//设置自动播放
mHandler.sendEmptyMessageDelayed(AUTO_MSG, PHOTO_CHANGE_TIME);

刷新方法

实际项目中banner轮播是要有刷新方法的,其实刷新方法和设置数据方法类似

1
2
3
4
5
6
7
8
9
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
* 刷新的方法
*
* @param mbannerModelList
*/
public void refreshBannerModelList(List<BannerModel> mbannerModelList) {
this.bannerModelList = mbannerModelList;
if (bannerModelList.size() > 0) {
bannerModelListSize = bannerModelList.size();
//刷新时上一次的数据要进行清除
if (bannerviewsList != null) {
bannerviewsList.clear();
} else {
bannerviewsList = new ArrayList<View>();
}
for (BannerModel bannerModel : bannerModelList) {
ImageView imageView = new ImageView(mContext);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
Glide.with(mContext).load(bannerModel.getImgurl()).into(imageView);
bannerviewsList.add(imageView);
}
}
//添加小圆点的图片
if (bannerModelList != null) {
//照片轮播下方的小圆点刷新时需要重新加载 并将上次的进行remove
if (layout_page != null) {
layout_page.removeAllViews();
}
//小圆点显示的个数就是照片轮播的实体个数
imageViews = new ImageView[bannerModelListSize];
for (int i = 0; i < bannerviewsList.size(); i++) {
imageView = new ImageView(mContext);
//设置小圆点imageview的参数
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(20, 20);
layoutParams.setMargins(10, 0, 10, 0);
// imageView.setLayoutParams(new ViewGroup.LayoutParams(20,20));//创建一个宽高均为20 的布局
imageView.setLayoutParams(layoutParams);//创建一个宽高均为20 的布局
imageView.setPadding(20, 0, 20, 0);
//默认选中的是第一张图片,此时第一个小圆点是选中状态,其他不是
if (i == 0) {
imageView.setBackgroundResource(R.drawable.shape_intro);
} else {
imageView.setBackgroundResource(R.drawable.shape_intro_nor);
}
//将imageviews添加到小圆点视图组
layout_page.addView(imageView);
imageViews[i] = imageView;
}
bannerViewPagerAdapter = new BannerViewPagerAdapter(bannerviewsList);
viewpager_banner.setAdapter(bannerViewPagerAdapter);
viewpager_banner.addOnPageChangeListener(new GuidePageChangeListener());
// viewpager_banner.setOnPageChangeListener(new GuidePageChangeListener());
}
}

点击事件回调

我们将点击事件后的结果进行回调,采用接口,设置相关监听方法,在使用中直接拿到数据进行跳转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private OnSelectItemClickstener onSelectItemClickstener;
/***
* bannerview点击监听方法
* @param onSelectItemClickstener
*/
public void setsetSelectItemClickstener(OnSelectItemClickstener onSelectItemClickstener) {
this.onSelectItemClickstener = onSelectItemClickstener;
}
/**
* 接受回调参数
*/
interface OnSelectItemClickstener {
void onSelectItem(int position, BannerModel bannerModel);
}

接口准备好了,在什么时候去调用了,当然是在banner点击的时候去调用呀,上面注释todo的地方去将接口进行回调

1
2
3
4
5
6
7
8
9
//单独的点击事件
views.get(position).setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (onSelectItemClickstener != null) {
BannerModel bannerModel = bannerModelList.get(position);
onSelectItemClickstener.onSelectItem(position, bannerModel);
}
}
});

代码中使用

xml布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.bannerview.MainActivity">
<com.bannerview.BannerView
android:id="@+id/bannerView"
android:layout_width="match_parent"
android:layout_height="200dp" />
<Button
android:id="@+id/btn"
android:text="刷新"
android:layout_width="368dp"
android:layout_height="wrap_content" />
</LinearLayout>

java代码中使用,第一次设置数据,模拟刷新数据,点击事件跳转模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
btn = (Button) findViewById(R.id.btn);
bannerView = (BannerView) findViewById(R.id.bannerView);
final List<BannerModel> bannerModelList = new ArrayList<>();
bannerModelList.add(new BannerModel(1, "http://bmob-cdn-10899.b0.upaiyun.com/2017/05/09/1add12e3407aa2ac80899838f5e5a097.jpg"));
bannerModelList.add(new BannerModel(2, "http://bmob-cdn-10899.b0.upaiyun.com/2017/05/09/34b6d85c406894f3803d949a78c4546e.jpg"));
bannerModelList.add(new BannerModel(3, "http://bmob-cdn-10899.b0.upaiyun.com/2017/05/09/1664c954400bf4d880fdd4d70b31ff2c.jpg"));
//第一次设置数据
bannerView.setBannerModelList(bannerModelList);
//模拟执行刷新
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
bannerView.refreshBannerModelList(bannerModelList);
}
});
/**
* 点击事件的数据回调
* 实际项目中根据数据挑战到相应的界面
*/
bannerView.setsetSelectItemClickstener(new BannerView.OnSelectItemClickstener() {
@Override
public void onSelectItem(int position, BannerModel bannerModel) {
Toast.makeText(MainActivity.this, "第"+position +"个"+ bannerModel.toString(), Toast.LENGTH_SHORT).show();
}
});

BannerView github demo地址

坚持原创技术分享,您的支持将鼓励我继续创作!
Fork me on GitHub