Android常用控件-ViewPage

ViewPage是我们非常常用的控件,他的功能就是多视图的切换

ViewPage
· ViewPage他继承了ViewGroup,所以他是一个容器类,可以在其中添加其他的View。
· ViewPage需要一个Adatper来给他提供数据
· ViewPage经常与Fragment和TabLayout一起使用

使用ViewPage+TabLayout
首先看看布局,这个就是一个最基本的ViewPage+TabLayout的布局了,可能TabLayout需要额外导入compile ‘com.android.support:design:26.1.0’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tabLayout">
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/tabLayout">
</android.support.v4.view.ViewPager>
</RelativeLayout>

然后看看Fragment的代码,很简单的

1
2
3
4
5
6
7
public class MyFragment extends Fragment {
@Override
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
22
public class myViewPageAdatper extends FragmentPagerAdapter {    
private List<MyFragment> myFragments;
public myViewPageAdatper(FragmentManager fm, List<MyFragment> fragments) {
super(fm);
this.myFragments=fragments;
}

@Override
public Fragment getItem(int position) {
return myFragments.get(position);
}

@Override
public int getCount() {
return myFragments.size();
}

@Override
public CharSequence getPageTitle(int position) {
return "标题:"+position;
}
}

下面是ViewPage的设置



最后的效果



对于ViewPage我们的程序有各种各样的需求,有时候我们需要他不能够滑动
这是我们可以设置setOnTouchListener()返回值为true,根据事件分发机制,在onTouch中的DOWN事件时候,将事件拦截。
1
2
3
4
5
6
viewpager.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
return true;
}
});

这样子是可以实现,但是如果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
54
public class ZwViewPage extends ViewPager {
private boolean isScroll;
public ZwViewPage(Context context) {
super(context);
}
public ZwViewPage(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* 1.dispatchTouchEvent一般情况不做处理
*,如果修改了默认的返回值,子孩子都无法收到事件
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev); // return true;不行
}
/**
* 是否拦截
* 拦截:会走到自己的onTouchEvent方法里面来
* 不拦截:事件传递给子孩子
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// return false;//可行,不拦截事件,
// return true;//不行,孩子无法处理事件
//return super.onInterceptTouchEvent(ev);//不行,会有细微移动
if (isScroll){
return super.onInterceptTouchEvent(ev);
}else{
return false;
}
}
/**
* 是否消费事件
* 消费:事件就结束
* 不消费:往父控件传
*/
@Override
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,就可以实现了