Android轮播图

漏洞百出

轮播图是 Android 常用功能之一,效果大概是这样的:


之前我封装写了一个,基本达到了要求,是继承了 Fragment(当时脑袋肯定锈掉了),里面 Viewpager add Fragment,这次项目多处有轮播图,发现之前封装的不够用,简直漏洞百出:
1、比如底部 point 的位置,之前固定在中间,现在可能要放在右下角,point 最好也能动态改图片;
2、现在项目跟微信一样,底部 tab 切换,中间是 Fragment 替换,发现轮播图有问题,Fragment A 循环的 point 的 positoin 居然影响到了 Fragment B,照理,这是两个 BannerFragment,不会影响的啊,报以下错误:

     
     
1
     
     
java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged!

经过排查,找到了原因,因为 Viewpager add Fragment 我全部放在一个类,因此:

     
     
1
     
     
public static List<Object> bannerList = new ArrayList<>();

这里 static 坏事了,之前一个 banner 没有暴露出来。
3、继承了 Fragment,引用比较麻烦,Fragment 有两者引用方法,xml 和代码,两者方式 addData 却报错;
4、banner 没有写点击回调。

再次封装

综合以上问题,我进行了优化,继承 LinearLayout,当一个控件来引用,省去不必要的麻烦,底部 point 的位置可以设置:

     
     
1
     
     
pointLayout.setGravity(bannerPointGravity);

另外自定义了属性,动态设置 point 大小和图片,轮播图循环时间,也能代码设置,完整代码示例:

     
     
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
     
     
/**
* Created by WuXiaolong on 2017/8/24.
* 个人博客:http://wuxiaolong.me
*/
public class BannerLayout extends LinearLayout {
private ViewPager viewPager;
private LinearLayout pointLayout;
private ScheduledExecutorService scheduler;
private int mPosition = 0;
private int mBannerCount = 1;
private Context context;
private Activity activity;
private int bannerPointSize;
private int bannerPointGravity;
private int bannerPointDrawableSelected, bannerPointDrawableUnselected;
private int bannerDelaySecond;
public BannerLayout(Context context) {
this(context, null);
}
public BannerLayout(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public BannerLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs);
}
private void initView(Context context, AttributeSet attrs) {
this.context = context;
activity = (Activity) context;
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BannerLayout);
bannerPointSize = typedArray.getDimensionPixelSize(R.styleable.BannerLayout_bannerPointSize, 10);
bannerPointGravity = typedArray.getInt(R.styleable.BannerLayout_bannerPointGravity, Gravity.CENTER);
bannerDelaySecond = typedArray.getInt(R.styleable.BannerLayout_bannerDelaySecond, 5);
bannerPointDrawableSelected = typedArray.getResourceId(R.styleable.BannerLayout_bannerPointDrawableSelected, R.mipmap.point01);
bannerPointDrawableUnselected = typedArray.getResourceId(R.styleable.BannerLayout_bannerPointDrawableUnselected, R.mipmap.point02);
typedArray.recycle();
View view = View.inflate(context, R.layout.banner_view_pager, null);
addView(view);
viewPager = (ViewPager) view.findViewById(R.id.viewPager);
pointLayout = (LinearLayout) view.findViewById(R.id.pointLayout);
pointLayout.setGravity(bannerPointGravity);
viewPager.addOnPageChangeListener( new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
addPointLayout(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
public void start(List<Object> bannerList) {
bannerShutdown();
mBannerCount = bannerList.size();
BannerPagerAdapter bannerPagerAdapter = new BannerPagerAdapter(context, bannerList);
viewPager.setAdapter(bannerPagerAdapter);
addPointLayout( 0);
startScheduler();
}
private void addPointLayout(int position) {
pointLayout.removeAllViews();
for ( int i = 0; i < mBannerCount; i++) {
ImageView imageView = new ImageView(context);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(bannerPointSize, bannerPointSize);
layoutParams.setMargins( 10, 0, 0, 0);
imageView.setLayoutParams(layoutParams);
if (position == i) {
imageView.setImageResource(bannerPointDrawableSelected);
} else {
imageView.setImageResource(bannerPointDrawableUnselected);
}
pointLayout.addView(imageView);
}
}
private void startScheduler() {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate( new Runnable() {
@Override
public void run() {
mPosition = viewPager.getCurrentItem();
if (mPosition < mBannerCount - 1) {
mPosition++;
} else {
mPosition = 0;
}
activity.runOnUiThread( new Runnable() {
@Override
public void run() {
viewPager.setCurrentItem(mPosition);
}
});
}
}, 1, bannerDelaySecond, TimeUnit.SECONDS);
}
public void bannerShutdown() {
if (scheduler != null)
scheduler.shutdown();
}
private class BannerPagerAdapter extends PagerAdapter {
private List<Object> bannerList = new ArrayList<>();
private Context context;
BannerPagerAdapter(Context context, List<Object> bannerList) {
this.context = context;
this.bannerList.clear();
this.bannerList.addAll(bannerList);
}
@Override
public int getCount() {
return bannerList.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
ImageView imageView = new ImageView(context);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
Object object = bannerList.get(position);
//这里我封装了 Glide 4.0 的工具类,用于显示图片
ImageLoaderUtil.load(context, object, imageView);
container.addView(imageView);
return imageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
public int dp2px(float var0) {
float var1 = context.getResources().getDisplayMetrics().density;
return ( int) (var0 * var1 + 0.5F);
}
public void setBannerPointSize(int bannerPointSize) {
this.bannerPointSize = dp2px(bannerPointSize);
}
public void setBannerPointGravity(int bannerPointGravity) {
this.bannerPointGravity = bannerPointGravity;
pointLayout.setGravity(bannerPointGravity);
}
public void setBannerPointDrawableSelected(int bannerPointDrawableSelected) {
this.bannerPointDrawableSelected = bannerPointDrawableSelected;
}
public void setBannerPointDrawableUnselected(int bannerPointDrawableUnselected) {
this.bannerPointDrawableUnselected = bannerPointDrawableUnselected;
}
public void setBannerDelaySecond(int bannerDelaySecond) {
this.bannerDelaySecond = bannerDelaySecond;
}
}

其中自定义属性的attrs.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"?>
<resources>
<declare-styleable name="BannerLayout">
<!--轮播图点的大小-->
<attr name="bannerPointSize" format="dimension" />
<!--轮播图点的位置,分别有左中右-->
<attr name="bannerPointGravity" format="enum">
<enum name="left" value="3" />
<enum name="center" value="17" />
<enum name="right" value="5" />
</attr>
<!--轮播图点选中的图片-->
<attr name="bannerPointDrawableSelected" format="reference" />
<!--轮播图点未选中的图片-->
<attr name="bannerPointDrawableUnselected" format="reference" />
<!--轮播图循环时间,单位秒-->
<attr name="bannerDelaySecond" format="integer" />
</declare-styleable>
</resources>

使用说明

xml

     
     
1
2
3
4
5
6
7
8
9
     
     
<com.wuxiaolong.bannersample.BannerLayout
android:id= "@+id/bannerView"
android:layout_width= "match_parent"
android:layout_height= "198dp"
app:bannerDelaySecond= "3"
app:bannerPointDrawableSelected= "@drawable/gray_radius"
app:bannerPointDrawableUnselected= "@drawable/white_radius"
app:bannerPointGravity= "right"
app:bannerPointSize= "10dp" />

调用:

     
     
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
     
     
public class MainActivity extends AppCompatActivity {
private BannerLayout bannerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bannerView = (BannerLayout) findViewById(R.id.bannerView);
List<Object> bannerList = new ArrayList<>();
bannerList.add(R.mipmap.horizontal_default);
bannerList.add( "http://pic1.win4000.com/wallpaper/5/598161750eddb.jpg");
bannerList.add( "http://pic1.win4000.com/wallpaper/4/597efb5b6aae8.jpg");
bannerView.setBannerPointSize( 10);
bannerView.setBannerPointGravity(Gravity.CENTER);
bannerView.setBannerPointDrawableSelected(R.drawable.gray_radius);
bannerView.setBannerPointDrawableUnselected(R.mipmap.point01);
bannerView.setBannerDelaySecond( 5);
//banner 设置方法完毕时最后调用 start 方法
bannerView.start(bannerList);
}
@Override
protected void onStop() {
super.onStop();
bannerView.bannerShutdown();
}
}

最后

完整源码分享了我的知识星球(原名:小密圈),如果以上还满足不了你的需求,可以使用 GitHub上的库 banner,它丰富了 pointLayout,可能是文字,它还依赖了ViewPagerTransforms,因此 ViewPager 切换有各种炫酷效果,不过我觉得有些多余。

Android轮播图是一种在移动应用中展示多张图片或内容的效果。通过轮播图,可以实现图片或内容的自动切换,给用户带来更好的视觉体验。根据提供的引用内容,可以使用第三方库Banner来实现Android轮播图效果。 首先,你需要设置轮播图的基本属性。在XML布局文件中,你可以使用Banner控件,并且通过设置属性来定义轮播间隔时间和轮播图的圆角。例如,在给定的引用中,通过设置`app:banner_radius="15dp"`来设置轮播图的圆角,通过设置`app:banner_loop_time="2000"`来设置轮播间隔时间[1]。 其次,你需要准备轮播图的数据。在提供的引用中,通过创建一个ArrayList,并依次添加图片资源的ID来作为轮播图的数据。 最后,你可以使用Banner框架提供的适配器来实现轮播图效果。通过调用`setAdapter()`方法并传入适配器对象,可以将数据加载到轮播图中。在给定的引用中,使用BannerImageAdapter来设置轮播图的数据,并在`onBindView()`方法中设置每张图片显示。 综上所述,你可以按照以下步骤实现Android轮播图效果: 1. 在XML布局文件中,添加一个Banner控件,并设置属性来定义轮播间隔时间和轮播图的圆角。 2. 准备轮播图的数据,可以通过创建一个ArrayList并添加图片资源的ID来作为数据。 3. 使用Banner框架提供的适配器,通过调用`setAdapter()`方法将数据加载到轮播图中。 4. 在适配器的`onBindView()`方法中,设置每张图片显示。 需要注意的是,你需要根据自己的需求来调整轮播图的其他属性和样式,比如切换动画、指示器等。同时,记得在适当的时候调用`start()`方法启动轮播图,以触发自动切换效果。 希望这个回答对你有帮助,如果有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值