设计图片轮播器

模拟异步加载网络图片

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
public class MainActivity extends AppCompatActivity {

private ViewPager vp;
private ViewPageAdapter viewPageAdapter;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

vp = (ViewPager) findViewById(R.id.vp);
viewPageAdapter = new ViewPageAdapter(this, Images.imageArray);
vp.setAdapter(viewPageAdapter);
}
}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<androidx.viewpager.widget.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="200dp" />

</LinearLayout>

public class ViewPageAdapter extends PagerAdapter {

private Context mContext;
private LayoutInflater layoutInflater;
private int[] datas;

public ViewPageAdapter(Context mContext, int[] datas) {
this.mContext = mContext;
this.datas = datas;
layoutInflater = LayoutInflater.from(mContext);
}

@Override
public int getCount() {
return datas.length;
}

@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return object == view;
}

@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView((View) object);
}
//渲染每一页的数据
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
View layout = layoutInflater.inflate(R.layout.item_shufflinf, null);
ImageView iv = (ImageView) layout.findViewById(R.id.iv);
//iv.setImageResource(datas[position]);

//异步任务加载图片
BitmapTask bitmapTask = new BitmapTask(mContext, iv);
bitmapTask.execute(datas[position]);

container.addView(layout);
return layout;
}
}

public class BitmapTask extends AsyncTask<Integer, Void, Bitmap> {

private Context mContext;
private ImageView imageView;
private int res;

public BitmapTask(Context mContext, ImageView imageView) {
this.mContext = mContext;
this.imageView = imageView;
}

@Override
protected Bitmap doInBackground(Integer... integers) {
res = integers[0];
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), res);
return bitmap;
}

//返回到主线程 显示成功加载的图片
@Override
protected void onPostExecute(Bitmap bitmap) {

imageView.setImageBitmap(bitmap);

}
}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv"
android:scaleType="fitXY"
android:layout_width="match_parent"
android:layout_height="200dp" />
</LinearLayout>

public class Images {
public final static int[] imageArray = new int[]{
R.drawable.img1,
R.drawable.img2,
R.drawable.img3,
R.drawable.img4,
R.drawable.img5
};
}

加载轮播图片有两种方式

一是欺骗适配器

将适配器中的getCount的值设置为无限大

只需要修改三个地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ViewPageAdapter中
设置无限的长度
@Override
public int getCount() {
return Integer.MAX_VALUE;
//return datas.length;
}
取余数 0,1,2,3,4
bitmapTask.execute(datas[position % datas.length]);


MainActivity中添加
为了能够左边循环
vp.setCurrentItem(Images.imageArray.length * 1000, true);

二是构造数据源

假如有五张图片,在viewpage中需要设置7个view,设置成下面的数据

4–0–1–2–3–4–0

进入图片时显示0图片,向右滑动到0时,将当前页设置为0页,就可以继续向右滑动了

同理,向左滑动到4时,将当前页设置为4页。

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
设置数据源
private int[] datas = new int[Images.imageArray.length + 2];

public void initData(){
//设置为新数据源的第一个数据
datas[0] = Images.imageArray[Images.imageArray.length-1];

for(int i = 0; i < Images.imageArray.length; i++){
datas[i+1] = Images.imageArray[i];
}
//设置新数据源的最后一个数据
datas[datas.length - 1] = Images.imageArray[0];
}

对页面改动进行监听
class ViewPagerChangeListener implements ViewPager.OnPageChangeListener{

int pageIndex;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

}

@Override
public void onPageSelected(int position) {
pageIndex = position;
//当前视图为第一个时,将页面索引设置为数据源的倒数第二个
if(pageIndex == 0){
pageIndex = datas.length-2;
//当前视图为最后一个是,将页面索引设置为数据源的正数第二个
} else if (pageIndex == datas.length - 1){
pageIndex = 1;
}

if(pageIndex != position){
vp.setCurrentItem(pageIndex, true);
}
}

@Override
public void onPageScrollStateChanged(int state) {

}
}

绑定监听事件
vp.setOnPageChangeListener(new ViewPagerChangeListener());
设置进入页面显示0图片
vp.setCurrentItem(1, true);

自动轮播图片

在欺骗适配器的基础上完成的这个自动轮播的功能

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
定义一个定长线程池 可以定时的操作图片 因为是在页面加载完成之后才轮播图片 所以在onStart()中去实现定时轮播的功能
@Override
protected void onStart() {
super.onStart();
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
currentPage++;
//在子线程中不能设置vp.setCurrentItem 所以需要发送一个消息给主线程,让主线程去处理这个事件
handler.sendEmptyMessage(1);
}
}, 1, 3, TimeUnit.SECONDS);
}

private Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 1:
vp.setCurrentItem(currentPage, true);
break;
}
}
};

还需要监听图片的位置,因为如果手动更改了的话,轮播的位置就会发生变化
class ViewPagerChangeListener implements ViewPager.OnPageChangeListener{

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

}

@Override
public void onPageSelected(int position) {
currentPage = position;
}

@Override
public void onPageScrollStateChanged(int state) {

}
}


当页面不可见时我们需要清楚掉这个线程池
@Override
protected void onStop() {
super.onStop();
scheduledExecutorService.shutdown();
}