ViewPage是我们非常常用的控件,他的功能就是多视图的切换
ViewPage
· ViewPage他继承了ViewGroup,所以他是一个容器类,可以在其中添加其他的View。
· ViewPage需要一个Adatper来给他提供数据
· ViewPage经常与Fragment和TabLayout一起使用
使用ViewPage+TabLayout
首先看看布局,这个就是一个最基本的ViewPage+TabLayout的布局了,可能TabLayout需要额外导入compile ‘com.android.support:design:26.1.0’
1 | <?xml version="1.0" encoding="utf-8"?> |
然后看看Fragment的代码,很简单的1
2
3
4
5
6
7public class MyFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.activity_main,null);
return view;
}
}
然后编写ViewPage的适配器,注意重写getPageTitle(int position)这个方法是用来设置TabLayout的title的,因为TabLayout是跟ViewPager绑定起来的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class myViewPageAdatper extends FragmentPagerAdapter {
private List<MyFragment> myFragments;
public myViewPageAdatper(FragmentManager fm, List<MyFragment> fragments) {
super(fm);
this.myFragments=fragments;
}
public Fragment getItem(int position) {
return myFragments.get(position);
}
public int getCount() {
return myFragments.size();
}
public CharSequence getPageTitle(int position) {
return "标题:"+position;
}
}
下面是ViewPage的设置

最后的效果

对于ViewPage我们的程序有各种各样的需求,有时候我们需要他不能够滑动
这是我们可以设置setOnTouchListener()返回值为true,根据事件分发机制,在onTouch中的DOWN事件时候,将事件拦截。
1 | viewpager.setOnTouchListener(new View.OnTouchListener() { |
这样子是可以实现,但是如果ViewPager的Fragment里面有可以滑动的控件,比如又一个ViewPager,这样我们上面的那种办法就没有用了viewPager还是可以被拖出来,对于这种情况我们只有继承ViewPager来重新分发它的事件,禁止它的滑动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
54public class ZwViewPage extends ViewPager {
private boolean isScroll;
public ZwViewPage(Context context) {
super(context);
}
public ZwViewPage(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* 1.dispatchTouchEvent一般情况不做处理
*,如果修改了默认的返回值,子孩子都无法收到事件
*/
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev); // return true;不行
}
/**
* 是否拦截
* 拦截:会走到自己的onTouchEvent方法里面来
* 不拦截:事件传递给子孩子
*/
public boolean onInterceptTouchEvent(MotionEvent ev) {
// return false;//可行,不拦截事件,
// return true;//不行,孩子无法处理事件
//return super.onInterceptTouchEvent(ev);//不行,会有细微移动
if (isScroll){
return super.onInterceptTouchEvent(ev);
}else{
return false;
}
}
/**
* 是否消费事件
* 消费:事件就结束
* 不消费:往父控件传
*/
public boolean onTouchEvent(MotionEvent ev) {
//return false;// 可行,不消费,传给父控件
//return true;// 可行,消费,拦截事件
//super.onTouchEvent(ev); //不行,
//虽然onInterceptTouchEvent中拦截了,
//但是如果viewpage里面子控件不是viewgroup,还是会调用这个方法.
if (isScroll){
return super.onTouchEvent(ev);
}else {
return true;// 可行,消费,拦截事件
}
}
public void setScroll(boolean scroll) {
isScroll = scroll;
}
}
这样子我们就实现了禁止ViewPager的滑动,下面我们来说说ViewPager的预加载。
ViewPager会默认加载当前页和当前页的左右两页。
一开始当前页是下标0,所以一开始默认加载第0页(指下标,下同)和第1页。
当你向右滑动,当前页为第1页时,ViewPager会加载第2页,这时一共有3页存在(第0,1,2页)。
再向右滑动,当前页为第2页时,会移除第0页,加载第3页,同理向左滑动当前页为第1页时,会移除第3页。
我们可以设置下面的这个方法来预加载多个页面。1
viewpager.setOffscreenPageLimit(int i);
但是如果我们不想要他预加呢?当每个fragment都需要去联网加载网络数据或者做一些耗时的操作,而且有其他的fragment并不是必须的,用户不一定会打开。
这样的话如果还预加载的话将会浪费资源,用户体验也不好。
虽然可以通过setOffscreenPageLimit(0)来设置不提前预加载,但这样的设置没有效果。通过研究ViewPager的源码,可以设置该类默认的DEFAULT_OFFSCREEN_PAGES = 0,来预防预加载。
还有一直办法就是判断fragment的位置是否为当前显示ViewPager,如果是就加载,不是的话就不给加载
设置ViewPager默认显示的页面,通过这个方法就可以通过代码设置页面的切换了1
ViewPager.setCurrentItem(2)
如果想要下面这种效果

在布局文件中色湖之ClipToPadding=“false”然后设置padding,就可以实现了