上一期学习了ViewPager的简单使用,本期一起来学习ViewPager的更多用法。
相信很多同学都使用过今日头条APP吧,一打开主界面就可以看到顶部有很多Tab,然后通过左右滑动来切换,就可以通过ViewPager来完成。当然具体实现又会有很多方式,我们本期就先来学习最简单的Tab切换吧,有一点类似于之前了解的TabHost。
一、PagerTitleStrip与PagerTabStrip
在实际运用中,很多时候只有页面滑动是不够的,还需要有标题栏才够友好。首先来学习一下官方自带的,在android.support.v4包中的两个控件PagerTabStrip与PagerTitleStrip。
上面提到的2个控件,其中PagerTitleStrip是普通文字,PagerTabStrip带有下划线。PagerTabStrip在效果上包含了PagerTitleStrip。
如果只添加PagerTabStrip可以看到只有线,但是它占的布局是有一定高度的,而且默认是不显示标题的,如果要显示出来,需在适配器里重写getPageTitle(int position)方法。关于标题及这条线的颜色,和整个标识View的背景,都可以在代码里设置。
还有一个区别就是,PagerTabStrip可以点击切换View,而PagerTitleStrip不能点击。
接下来通过一个案例来学习PagerTabStrip的使用。
继续再上一期的案例基础上来进行修改,首先修改viewpager_layout.xml文件,修改后的代码如下:
[代码]xml代码:01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17<?xml version="1.0" encoding="utf-8"?>
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:id="@+id/view_pager_tabstrip"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
然后几个页面布局文件不变,既然需要在顶部显示Tab和标题,那就需要我们通过适配器来设置,修改后的ViewPagerAdapter类代码如下:
[代码]java代码:01
02
03
04
05
06
07
08
09
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
52package com.jinyu.cqkxzsxy.android.advancedviewsample.adapter;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
/**
* @创建者 鑫鱻
* @描述 Android零基础入门到精通系列教程
*首发微信公众号分享达人秀(ShareExpert)
*/
public class ViewPagerAdapter extends PagerAdapter {
private ArrayList mPageLists = null;
private ArrayList mTitleLists = null;
public ViewPagerAdapter(ArrayList pageLists, ArrayList titleLists) {
this.mPageLists = pageLists;
this.mTitleLists = titleLists;
}
@Override
public int getCount() {
return (null == mPageLists) ? 0 :mPageLists.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View pageView = mPageLists.get(position);
container.addView(pageView);
return pageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
//将当前位置的View移除
container.removeView(mPageLists.get(position));
}
@Override
public CharSequence getPageTitle(int position) {
return (null == mTitleLists && position < mTitleLists.size())
? null : mTitleLists.get(position);
}
}
接着修改ViewPagerActivity,修改的代码如下:
[代码]java代码:01
02
03
04
05
06
07
08
09
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
72package com.jinyu.cqkxzsxy.android.advancedviewsample;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.view.PagerTabStrip;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Toast;
import com.jinyu.cqkxzsxy.android.advancedviewsample.adapter.ViewPagerAdapter;
import java.util.ArrayList;
/**
* @创建者 鑫鱻
* @描述 Android零基础入门到精通系列教程,欢迎关注微信公众号ShareExpert
*/
public class ViewPagerActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener {
private ViewPager mViewPager = null;
private PagerTabStrip mPagerTabStrip = null;
private ViewPagerAdapter mAdapter = null;
private ArrayList mPageLists = null;
private ArrayList mTitleLists = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewpager_layout);
mViewPager = (ViewPager) findViewById(R.id.view_pager);
mPagerTabStrip = (PagerTabStrip) findViewById(R.id.view_pager_tabstrip);
//装入分页显示hi的View视图
mPageLists = new ArrayList<>();
LayoutInflater inflater = getLayoutInflater();
mPageLists.add(inflater.inflate(R.layout.viewpager_page1, null, false));
mPageLists.add(inflater.inflate(R.layout.viewpager_page2, null, false));
mPageLists.add(inflater.inflate(R.layout.viewpager_page3, null, false));
mPageLists.add(inflater.inflate(R.layout.viewpager_page4, null, false));
//装入每个页面的Title
mTitleLists = new ArrayList<>();
mTitleLists.add("第一页");
mTitleLists.add("第二页");
mTitleLists.add("第三页");
mTitleLists.add("第四页");
mAdapter = new ViewPagerAdapter(mPageLists, mTitleLists);
mViewPager.setAdapter(mAdapter);
//更改下划线颜色
mPagerTabStrip.setTabIndicatorColor(Color.BLUE);
mViewPager.addOnPageChangeListener(this);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
Toast.makeText(this, "第" + (position + 1) + "页", Toast.LENGTH_SHORT).show();
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
重新运行程序,可以看到界面中已经出现了久违的Tab和标题,左右滑动页面也可以看到Tab处的线条跟随改变,
从上面的案例可以发现,PagerTabStrip是ViewPager的一个关于当前页面、上一个页面和下一个页面的一个可交互的指示器。其默认显示在顶部,还可以通过android:layout_gravity 属性设置为TOP或BOTTOM将它显示在ViewPager的顶部或底部。
关于PagerTitleStrip的使用,和PagerTabStrip基本差不多,只是布局文件中ViewPager包含的控件不同而已,这里就不再详细说明了,建议自己动手练习,如果有问题,欢迎进Android入门讨论群一起探讨。
二、自定义实现
上面我们使用了系统自带的控件来完成Tab显示,可能有的同学已经发现其与TabHost还是有一定的差别的,上面的Tab只显示3个,而且也不能完全满足实际需求,就需要我们自定义来实现了。
接下来依然通过一个案例来学习如何自定义ViewPager的Tab标签。
继续使用WidgetSample工程的advancedviewsample模块,在src/main/res/layout/目录下创建viewpager_custom_layout.xml文件,在其中填充如下代码片段:
[代码]xml代码:01
02
03
04
05
06
07
08
09
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<?xml version="1.0" encoding="utf-8"?>
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#FFFFFF">
android:id="@+id/viewpager_tv_one"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:gravity="center"
android:text="第一页"
android:textColor="#000000" />
android:id="@+id/viewpager_tv_two"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:gravity="center"
android:text="第二页"
android:textColor="#000000" />
android:id="@+id/viewpager_tv_three"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:gravity="center"
android:text="第三页"
android:textColor="#000000" />
android:id="@+id/cursor_img"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="matrix"
android:class="lazyload" src="https://img-blog.csdnimg.cn/2022010623135611729.png" data-original="@drawable/line" />
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:flipInterval="30"
android:persistentDrawingCache="animation" />
在页面顶部有一个线性布局,里面包含3个TextView,也就是ViewPager顶部的3个Tab标签。然后下面紧跟一个ImageView,主要用于指示当前是哪一个Tab标签对应的页面,也就是常说的滑块。最后在最底下是一个ViewPager,其中android:flipInterval属性设置了动画的时间间隔,android:persistentDrawingCache属性指控件的绘制缓存策略,一共有4个可选值,或者选择2个进行组合,分别如下:
· none:不在内存中保存绘图缓存。
· animation:只保存动画绘图缓存。
· scrolling:只保存滚动效果绘图缓存。
· all:所有的绘图缓存都应该保存在内存中。
然后新建几个页面文件,这里继续使用上一期ViewPager快速实现引导页里面的页面文件,同样使用相同的适配器ViewPagerAdapter。
最后新建ViewPagerCustomActivity.java文件,加载上面新建的布局文件,具体代码如下:
[代码]java代码:001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
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
158package com.jinyu.cqkxzsxy.android.advancedviewsample;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.TextView;
import com.jinyu.cqkxzsxy.android.advancedviewsample.adapter.ViewPagerAdapter;
import java.util.ArrayList;
/**
* @创建者 鑫鱻
* @描述 Android零基础入门到精通系列教程,欢迎关注微信公众号ShareExpert
*/
public class ViewPagerCustomActivity extends AppCompatActivity
implements ViewPager.OnPageChangeListener, View.OnClickListener {
private ViewPager mViewPager = null;
private ImageView mCursorImg = null;
private TextView mOneTv = null;
private TextView mTwoTv = null;
private TextView mThreeTv = null;
private ViewPagerAdapter mAdapter = null;
private ArrayList mPageList = null;
private int mOffset = 0;//移动条图片的偏移量
private int mCurrIndex = 0; //当前页面的编号
private int mOneDis = 0; //移动条滑动一页的距离
private int mTwoDis = 0; //滑动条移动两页的距离
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewpager_custom_layout);
//获取界面组件
mViewPager = (ViewPager) findViewById(R.id.view_pager);
mCursorImg = (ImageView) findViewById(R.id.cursor_img);
mOneTv = (TextView) findViewById(R.id.viewpager_tv_one);
mTwoTv = (TextView) findViewById(R.id.viewpager_tv_two);
mThreeTv = (TextView) findViewById(R.id.viewpager_tv_three);
//初始化指示器位置
initCursorPosition();
mPageList = new ArrayList<>();
LayoutInflater inflater = getLayoutInflater();
mPageList.add(inflater.inflate(R.layout.viewpager_page1, null, false));
mPageList.add(inflater.inflate(R.layout.viewpager_page2, null, false));
mPageList.add(inflater.inflate(R.layout.viewpager_page3, null, false));
//设置适配器
mAdapter = new ViewPagerAdapter(mPageList);
mViewPager.setAdapter(mAdapter);
//文本框点击监听器
mOneTv.setOnClickListener(this);
mTwoTv.setOnClickListener(this);
mThreeTv.setOnClickListener(this);
//页面改变监听器
mViewPager.addOnPageChangeListener(this);
//初始默认第一页
mViewPager.setCurrentItem(0);
}
private void initCursorPosition() {
//获取指示器图片宽度
int cursorWidth = BitmapFactory.decodeResource(getResources(), R.drawable.line).getWidth();
//获取分辨率宽度
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int screenWidth = dm.widthPixels;
//计算偏移量
mOffset = (screenWidth / 3 - cursorWidth) / 2;
//设置动画初始位置
Matrix matrix = new Matrix();
matrix.postTranslate(mOffset, 0);
mCursorImg.setImageMatrix(matrix);
//计算指示器图片的移动距离
mOneDis = mOffset * 2 + cursorWidth;//页卡1 -> 页卡2 偏移量
mTwoDis = mOneDis * 2;//页卡1 -> 页卡3 偏移量
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.viewpager_tv_one:
mViewPager.setCurrentItem(0);
break;
case R.id.viewpager_tv_two:
mViewPager.setCurrentItem(1);
break;
case R.id.viewpager_tv_three:
mViewPager.setCurrentItem(2);
break;
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
//指示器图片动画设置
Animation animation = null;
switch (position) {
case 0:
if (1 == mCurrIndex) {
animation = new TranslateAnimation(mOneDis, 0, 0, 0);
} else if (2 == mCurrIndex) {
animation = new TranslateAnimation(mTwoDis, 0, 0, 0);
}
break;
case 1:
if (0 == mCurrIndex) {
animation = new TranslateAnimation(mOffset, mOneDis, 0, 0);
} else if (2 == mCurrIndex) {
animation = new TranslateAnimation(mTwoDis, mOneDis, 0, 0);
}
break;
case 2:
if (0 == mCurrIndex) {
animation = new TranslateAnimation(mOffset, mTwoDis, 0, 0);
} else if (1 == mCurrIndex) {
animation = new TranslateAnimation(mOneDis, mTwoDis, 0, 0);
}
break;
default:
break;
}
mCurrIndex = position;
animation.setFillAfter(true); // True:图片停在动画结束位置
animation.setDuration(300);
mCursorImg.startAnimation(animation);
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
可以发现这里的代码和上期大致相同,只是在其中增加了滑块的位置及动画设置,为3个Tab标签监听了点击事件。其中initCursorPosition()方法主要初始化指示器图标的位置,需要根据屏幕宽度来计算游标显示位置。然后同样设置了页面监听器,主要根据滑动到的页面把游标滑动找指定位置。关于动画的这一块代码,可能有很多新人不太懂,不要太介意这个了,后续会专门进行学习,这里只需要知道可以这样使用就行。
修改程序启动的Activity,运行程序,然后左右滑动屏幕或点击Tab标签,
通过上面的学习,是不是发现开发一个这样的漂亮界面其实非常简单。除了系统自带的和上面的自定义方法,在实际开发中常会结合Fragment来一起开发,建议后期学完Fragment后再来进一步学习。
除了学习的PagerAdapter适配器,还有另外2个FragmentPagerAdapter和FragmentStatePagerAdapter,主要也是结合Fragment一起使用的,这里先不做过多学习。
今天就先到这里,如果有问题欢迎留言一起探讨,也欢迎加入Android零基础入门技术讨论微信群,共同成长!