博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android中ViewPager实现滑动条及与Fragment结合的实例教程
阅读量:4519 次
发布时间:2019-06-08

本文共 11451 字,大约阅读时间需要 38 分钟。

 

ViewPager类主要被用来实现可滑动的视图功能,这里我们就来共同学习Android中ViewPager实现滑动条及与Fragment结合的实例教程,需要的朋友可以参考下

自主实现滑动指示条

先上一个基本效果图:

2016629111834182.png (300×500)

2016629111902609.png (300×500)

1.XML布局

布局代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<
LinearLayout
xmlns:android
=
""
 
xmlns:tools
=
""
 
android:layout_width
=
"match_parent"
 
android:layout_height
=
"match_parent"
 
android:orientation
=
"vertical"
 
tools:context
=
"com.example.testviewpage_2.MainActivity"
>
   
  
<
ImageView
  
android:id
=
"@+id/cursor"
  
android:layout_width
=
"fill_parent"
  
android:layout_height
=
"wrap_content"
  
android:scaleType
=
"matrix"
  
android:src
=
"@drawable/a"
/>
  
 
<
android.support.v4.view.ViewPager
  
android:id
=
"@+id/viewpager"
  
android:layout_width
=
"wrap_content"
  
android:layout_height
=
"wrap_content"
  
android:layout_gravity
=
"center"
/>
  
</
LinearLayout
>

采用线性垂直布局,在滑动页面的上方添加一个小水平条。

2.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
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
public
class
MainActivity
extends
Activity {
  
 
private
View view1, view2, view3;
 
private
List<View> viewList;
// view数组
 
private
ViewPager viewPager;
// 对应的viewPager
  
 
private
ImageView cursor;
 
private
int
bmpw =
0
;
// 游标宽度
 
private
int
offset =
0
;
// // 动画图片偏移量
 
private
int
currIndex =
0
;
// 当前页卡编号
  
 
@Override
 
protected
void
onCreate(Bundle savedInstanceState) {
  
super
.onCreate(savedInstanceState);
  
setContentView(R.layout.activity_main);
  
  
viewPager = (ViewPager) findViewById(R.id.viewpager);
  
LayoutInflater inflater = getLayoutInflater();
  
view1 = inflater.inflate(R.layout.layout1,
null
);
  
view2 = inflater.inflate(R.layout.layout2,
null
);
  
view3 = inflater.inflate(R.layout.layout3,
null
);
  
  
viewList =
new
ArrayList<View>();
// 将要分页显示的View装入数组中
  
viewList.add(view1);
  
viewList.add(view2);
  
viewList.add(view3);
  
  
//初始化指示器位置
  
initCursorPos();
    
  
viewPager.setAdapter(
new
MyPagerAdapter(viewList));
  
viewPager.setOnPageChangeListener(
new
MyPageChangeListener());
  
 
}
   
 
//初始化指示器位置
 
public
void
initCursorPos() {
  
// 初始化动画
  
cursor = (ImageView) findViewById(R.id.cursor);
  
bmpw = BitmapFactory.decodeResource(getResources(), R.drawable.a)
    
.getWidth();
// 获取图片宽度
  
  
DisplayMetrics dm =
new
DisplayMetrics();
  
getWindowManager().getDefaultDisplay().getMetrics(dm);
  
int
screenW = dm.widthPixels;
// 获取分辨率宽度
  
offset = (screenW / viewList.size() - bmpw) /
2
;
// 计算偏移量
  
  
Matrix matrix =
new
Matrix();
  
matrix.postTranslate(offset,
0
);
  
cursor.setImageMatrix(matrix);
// 设置动画初始位置
 
}
   
  
 
//页面改变监听器
 
public
class
MyPageChangeListener
implements
OnPageChangeListener {
  
  
int
one = offset *
2
+ bmpw;
// 页卡1 -> 页卡2 偏移量
  
int
two = one *
2
;
// 页卡1 -> 页卡3 偏移量
  
  
@Override
  
public
void
onPageSelected(
int
arg0) {
   
Animation animation =
null
;
   
switch
(arg0) {
   
case
0
:
    
if
(currIndex ==
1
) {
     
animation =
new
TranslateAnimation(one,
0
,
0
,
0
);
    
}
else
if
(currIndex ==
2
) {
     
animation =
new
TranslateAnimation(two,
0
,
0
,
0
);
    
}
    
break
;
   
case
1
:
    
if
(currIndex ==
0
) {
     
animation =
new
TranslateAnimation(offset, one,
0
,
0
);
    
}
else
if
(currIndex ==
2
) {
     
animation =
new
TranslateAnimation(two, one,
0
,
0
);
    
}
    
break
;
   
case
2
:
    
if
(currIndex ==
0
) {
     
animation =
new
TranslateAnimation(offset, two,
0
,
0
);
    
}
else
if
(currIndex ==
1
) {
     
animation =
new
TranslateAnimation(one, two,
0
,
0
);
    
}
    
break
;
   
}
   
currIndex = arg0;
   
animation.setFillAfter(
true
);
// True:图片停在动画结束位置
   
animation.setDuration(
300
);
   
cursor.startAnimation(animation);
  
}
  
  
@Override
  
public
void
onPageScrolled(
int
arg0,
float
arg1,
int
arg2) {
  
}
  
  
@Override
  
public
void
onPageScrollStateChanged(
int
arg0) {
  
}
 
}
 
 
/**
  
* ViewPager适配器
  
*/
 
public
class
MyPagerAdapter
extends
PagerAdapter {
  
public
List<View> mListViews;
  
  
public
MyPagerAdapter(List<View> mListViews) {
   
this
.mListViews = mListViews;
  
}
  
  
@Override
  
public
boolean
isViewFromObject(View arg0, Object arg1) {
   
// TODO Auto-generated method stub
   
return
arg0 == arg1;
  
}
  
  
@Override
  
public
int
getCount() {
   
// TODO Auto-generated method stub
   
return
mListViews.size();
  
}
  
  
@Override
  
public
void
destroyItem(ViewGroup container,
int
position, Object object) {
   
// TODO Auto-generated method stub
   
container.removeView(mListViews.get(position));
  
}
  
  
@Override
  
public
Object instantiateItem(ViewGroup container,
int
position) {
   
// TODO Auto-generated method stub
   
container.addView(mListViews.get(position));
  
   
return
mListViews.get(position);
  
}
 
}
  
}

3.重点解析

从易到难一步步来讲。
(1)initCursorPos()---初始化指示器位置
游标在初始化显示时,我们要根据屏幕宽度来显示游标位置。先看看这部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//初始化指示器位置
public
void
initCursorPos() {
 
// 初始化动画
 
cursor = (ImageView) findViewById(R.id.cursor);
 
bmpw = BitmapFactory.decodeResource(getResources(), R.drawable.a)
   
.getWidth();
// 获取图片宽度
  
 
DisplayMetrics dm =
new
DisplayMetrics();
 
getWindowManager().getDefaultDisplay().getMetrics(dm);
 
int
screenW = dm.widthPixels;
// 获取分辨率宽度
 
offset = (screenW / viewList.size() - bmpw) /
2
;
// 计算偏移量
  
 
Matrix matrix =
new
Matrix();
 
matrix.postTranslate(offset,
0
);
 
cursor.setImageMatrix(matrix);
// 设置动画初始位置
}

可能有些同学不明白的位置在于,初始化位置的偏移量为什么这么算,下面,我画了张图,看下就应该明白了。

最后对于偏移的方法,可用的很多,这里仿网上的代码用了matrix;当然大家可以用其它的偏移方法,一样。

(2)MyPageChangeListener()---页面改变监听器
代码如下 :

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
public
class
MyPageChangeListener
implements
OnPageChangeListener {
  
 
int
one = offset *
2
+ bmpw;
// 页卡1 -> 页卡2 偏移量
 
int
two = one *
2
;
// 页卡1 -> 页卡3 偏移量
  
 
@Override
 
public
void
onPageSelected(
int
arg0) {
  
Animation animation =
null
;
  
switch
(arg0) {
  
case
0
:
   
if
(currIndex ==
1
) {
    
animation =
new
TranslateAnimation(one,
0
,
0
,
0
);
   
}
else
if
(currIndex ==
2
) {
    
animation =
new
TranslateAnimation(two,
0
,
0
,
0
);
   
}
   
break
;
  
case
1
:
   
if
(currIndex ==
0
) {
    
animation =
new
TranslateAnimation(offset, one,
0
,
0
);
   
}
else
if
(currIndex ==
2
) {
    
animation =
new
TranslateAnimation(two, one,
0
,
0
);
   
}
   
break
;
  
case
2
:
   
if
(currIndex ==
0
) {
    
animation =
new
TranslateAnimation(offset, two,
0
,
0
);
   
}
else
if
(currIndex ==
1
) {
    
animation =
new
TranslateAnimation(one, two,
0
,
0
);
   
}
   
break
;
  
}
  
currIndex = arg0;
  
animation.setFillAfter(
true
);
// True:图片停在动画结束位置
  
animation.setDuration(
300
);
  
cursor.startAnimation(animation);
 
}

原理是这样,根据滑动到的页面,把游标滑动找指定位置。

这里可能有难度的地方在于,数学……
我画了一张图,解释从第一个页面到第二个页面时的距离为什么是“游标宽度+offset*2”,其它距离类似。

 

使用Fragment实现ViewPager滑动

效果图:

2016629112007807.png (300×533)

在第一个页面加一个Btn      

2016629112029036.png (300×533)

第一页面向第二页面滑动

2016629112046609.png (300×533)

第二页面向第三个页面滑动

一些说明:
FragmentPagerAdapter派生自PagerAdapter,它是用来呈现Fragment页面的,这些Fragment页面会一直保存在fragment manager中,以便用户可以随时取用。
这个适配器最好用于有限个静态fragment页面的管理。尽管不可见的视图有时会被销毁,但用户所有访问过的fragment都会被保存在内存中。因此fragment实例会保存大量的各种状态,这就造成了很大的内存开销。所以如果要处理大量的页面切换,建议使用FragmentStatePagerAdapter.
每一个使用FragmentPagerAdapter的ViewPager都要有一个有效的ID集合,有效ID的集合就是Fragment的集合(感谢夫诸同学的提示)
对于FragmentPagerAdapter的派生类,只需要重写getItem(int)和getCount()就可以了。
具体实现:
1、适配器实现——FragmentPagerAdapter
先看完整代码,再细讲:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public
class
FragAdapter
extends
FragmentPagerAdapter {
  
 
private
List<Fragment> mFragments;
   
 
public
FragAdapter(FragmentManager fm,List<Fragment> fragments) {
  
super
(fm);
  
// TODO Auto-generated constructor stub
  
mFragments=fragments;
 
}
  
 
@Override
 
public
Fragment getItem(
int
arg0) {
  
// TODO Auto-generated method stub
  
return
mFragments.get(arg0);
 
}
  
 
@Override
 
public
int
getCount() {
  
// TODO Auto-generated method stub
  
return
mFragments.size();
 
}
  
}

这里有三个函数,根据第一部分的官方文档,可知,对于FragmentPagerAdapter的派生类,只重写getItem(int)和getCount()就可以了。

对于构造函数,这里申请了一个Fragment的List对象,用于保存用于滑动的Fragment对象,并在创造函数中初始化:

1
2
3
4
5
public
FragAdapter(FragmentManager fm,List<Fragment> fragments) {
 
super
(fm);
 
// TODO Auto-generated constructor stub
 
mFragments=fragments;
}

然后在getItem(int arg0)中,根据传来的参数arg0,来返回当前要显示的fragment。

最后,getCount()返回用于滑动的fragment总数;

从构造函数所以看出,我们要构造Fragment的集合才行,所以下面我们就先产生我们所需要的Fragment类;

2、三个Fragment类
第一个Fragment类:

XML:(layout1.xml)

1
2
3
4
5
6
7
8
9
10
11
12
13
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
LinearLayout
xmlns:android
=
""
 
android:layout_width
=
"match_parent"
 
android:layout_height
=
"match_parent"
 
android:background
=
"#ffffff"
 
android:orientation
=
"vertical"
>
   
 
<
Button
android:id
=
"@+id/fragment1_btn"
  
android:layout_width
=
"wrap_content"
  
android:layout_height
=
"wrap_content"
  
android:text
=
"show toast"
  
/>
</
LinearLayout
>

在其中加入了一个Btn

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public
class
Fragment1
extends
Fragment {
   
 
@Override
 
public
View onCreateView(LayoutInflater inflater, ViewGroup container,
   
Bundle savedInstanceState) {
  
// TODO Auto-generated method stub
  
View view= inflater.inflate(R.layout.layout1, container,
false
);
    
  
//对View中控件的操作方法
  
Button btn = (Button)view.findViewById(R.id.fragment1_btn);
  
btn.setOnClickListener(
new
View.OnClickListener() {
     
   
@Override
   
public
void
onClick(View v) {
    
// TODO Auto-generated method stub
    
Toast.makeText(getActivity(),
"点击了第一个fragment的BTN"
, Toast.LENGTH_SHORT).show();
   
}
  
});
  
return
view;
 
}
}

在onCreateView()中返回要显示的View,上面这段代码简单演示了如何对视图里的控件进行操作,难度不大,不再细讲,如果对Fragment不太熟悉的同学,先看看这篇文章:《Android Fragment完全解析,关于碎片你所需知道的一切》

第二个Fragment类:

XML代码:(layout2.xml)原生代码,没有做任何更改

1
2
3
4
5
6
7
8
9
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
LinearLayout
xmlns:android
=
""
 
android:layout_width
=
"match_parent"
 
android:layout_height
=
"match_parent"
 
android:background
=
"#ffff00"
 
android:orientation
=
"vertical"
>
   
  
</
LinearLayout
>
1
2
3
4
5
6
7
8
9
10
11
public
class
Fragment2
extends
Fragment {
   
 
@Override
 
public
View onCreateView(LayoutInflater inflater, ViewGroup container,
   
Bundle savedInstanceState) {
  
// TODO Auto-generated method stub
  
View view=inflater.inflate(R.layout.layout2, container,
false
);
  
return
view;
 
}
  
}

第三个Fragment类:

XML代码:(layout3.xml)同样,原生代码,没做任何更改

1
2
3
4
5
6
7
8
9
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
LinearLayout
xmlns:android
=
""
 
android:layout_width
=
"match_parent"
 
android:layout_height
=
"match_parent"
 
android:background
=
"#ff00ff"
 
android:orientation
=
"vertical"
>
   
  
</
LinearLayout
>

java代码:

1
2
3
4
5
6
7
8
9
10
11
public
class
Fragment3
extends
Fragment {
   
 
@Override
 
public
View onCreateView(LayoutInflater inflater, ViewGroup container,
   
Bundle savedInstanceState) {
  
// TODO Auto-generated method stub
  
View view=inflater.inflate(R.layout.layout3, container,
false
);
  
return
view;
 
}
  
}

3、主activity实现

核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public
class
MainActivity
extends
FragmentActivity {
  
 
@Override
 
protected
void
onCreate(Bundle savedInstanceState) {
  
super
.onCreate(savedInstanceState);
  
setContentView(R.layout.activity_main);
  
  
//构造适配器
  
List<Fragment> fragments=
new
ArrayList<Fragment>();
  
fragments.add(
new
Fragment1());
  
fragments.add(
new
Fragment2());
  
fragments.add(
new
Fragment3());
  
FragAdapter adapter =
new
FragAdapter(getSupportFragmentManager(), fragments);
    
  
//设定适配器
  
ViewPager vp = (ViewPager)findViewById(R.id.viewpager);
  
vp.setAdapter(adapter);
 
}
  
}

首先有一个最值得注意的地方:Activity派生自FragmentActivity,其实这是有关Fragment的基础知识,只有FragmentActivity才能内嵌fragment页面,普通Activity是不行的。

这段代码主要分为两步,第一步:构造适配器;第二步:设定适配器。

先看构造适配器的过程:

1
2
3
4
5
6
//构造适配器
List<Fragment> fragments=
new
ArrayList<Fragment>();
fragments.add(
new
Fragment1());
fragments.add(
new
Fragment2());
fragments.add(
new
Fragment3());
FragAdapter adapter =
new
FragAdapter(getSupportFragmentManager(), fragments);

构造一个fragment列表,然后将上面的三个Fragment类对应的实例添加进去,最后生成FragAdapter实例。

至于第二步,设定适配器,没什么好讲的。

转载于:https://www.cnblogs.com/xgjblog/p/8983296.html

你可能感兴趣的文章
【转】jbdc程序启动报错:ORA-12505;PL/SQL却可以登录的解决方法
查看>>
Java Spring学习笔记03.@component
查看>>
(十)桥接模式-代码实现
查看>>
Windows Phone开发(29):隔离存储C 转:http://blog.csdn.net/tcjiaan/article/details/7447469...
查看>>
循环单链表操作
查看>>
iOS --- Touch ID指纹解锁
查看>>
强制命令-hdfs 主备间切换
查看>>
echarts使用记录(三):x/y轴数据和刻度显示及坐标中网格显示、格式化x/y轴数据...
查看>>
Spring事务
查看>>
修改Arduino串口缓冲区大小(转)
查看>>
深入解读键值产生原理,linux中的软链接和硬链接(转)
查看>>
CodeForces 591A
查看>>
super 、static、final关键字加深记忆哦!还有父子类构造函数调用问题
查看>>
JDBC之java数据库的连接与简单的sql语句执行
查看>>
图形验证码如何美化?
查看>>
「题解」:[组合数学][DP]:地精部落
查看>>
两个input之间有空隙,处理方法
查看>>
让你秒懂什么是 SEM、EDM、CPS、CPA、ROI、SEO……
查看>>
nginx connect failed (110- Connection timed out) 问题排查
查看>>
python中set使用
查看>>