Android开发之自定义ViewPager三角形指示器
最近公司的产品要进行改版,其中涉及到了登陆页面的UI,需要把注册和登陆功能换成ViewPager的页面切换,本想利用下原生自带的TabLayout作为ViewPager指示器就完事了,谁知UI设计在指示器上多了个小三角,虽然网上已经有封装的很完善的ViewPager指示器,不过这个小东西确实没什么难度,就没必要引入第三方了,顺手自己写了个,先来看下实现效果:
ViewPager三角形指示器我准备从三部分来讲
1、ViewPager指示器的简单实现
2、ViewPager指示器的完整封装
3、ViewPager指示器的封装使用(两行代码完成)
1、ViewPager指示器的实现
这部分其实很简单,我们先不考虑其他过多的干扰因素,我们就单纯的把它当成一个可跟随ViewPager滑动的标题栏,来看下这张图:
简易版ViewPager指示器拆分图
实现思路:
1、首先这个页面是由一个横向排列的线性布局LinearLayout和ViewPager组成,其中这个线性布局LinearLayout里包含了多个大小一样的TextView。
2、再来我们去监听这个ViewPager的滑动事件把对应位置上的文字进行高亮显示即可。
3、然后我们要做的就是在这个线性布局LinearLayou里去绘制小三角形,让其也跟随着ViewPager的移动,位置上的相关数据我们在监听ViewPager的滑动事件里的回调方法中就可以得到,所以应该没什么大问题。
接下来我们分析下这个三角形的绘制:
所需要的数据:三角形的底边宽,高度,绘制的起始位置
为了能够适应不同屏幕大小,这里我们就不对三角形的底边宽和高度进行固定值写死了,我们通过测量的方式去得到,然后用闭合路径Path去勾勒。
三角形的底边宽:我们取Tab宽度的六分之一(屏幕宽度/可见Tab数量/6)
三角形的高度:我们取底边宽的一半(屏幕宽度/可见Tab数量/6/2)
三角形绘制的起始位置:第一个Tab的中点减去底边宽度的一半(屏幕宽度/可见Tab数量/2-屏幕宽度/可见Tab数量/6/2)
附加:怎么确定三角形跟随着ViewPager滑动的位置呢?
在ViewPager的滑动监听回调接口中的onPageScrolled里的positionOffset参数已经给我们提供好了,它代表着页面滑动的偏移值,区间在[0,1),也就是当前页面的滑动距离为:Tab的宽度*偏移值,这样三角形的某事某刻的x轴位置也就确定了,即初始位置+偏移距离
/**
* This method will be invoked when the current page is scrolled, either as part
* of a programmatically initiated smooth scroll or a user initiated touch scroll.
*
* @param position Position index of the first page currently being displayed.
* Page position+1 will be visible if positionOffset is nonzero.
* @param positionOffset Value from [0, 1) indicating the offset from the page at position.
* @param positionOffsetPixels Value in pixels indicating the offset from position.
*/
void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
这里是简单版本的代码实现(固定三个Tab页):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.lcw.viewpagertriangleindicator.ViewPagerTriangleIndicator
android:id="@+id/vpti_main_tab"
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@color/colorAccent"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="新闻"
android:textColor="#FFFFFF" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="音乐"
android:textColor="#FFFFFF" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="游戏"
android:textColor="#FFFFFF" />
</com.lcw.viewpagertriangleindicator.ViewPagerTriangleIndicator>
<android.support.v4.view.ViewPager
android:id="@+id/vp_main_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
package com.lcw.viewpagertriangleindicator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.WindowManager;
import android.widget.LinearLayout;
/**
* 自定义ViewPager指示器(三角形)
* Create by: chenwei.li
* Date: 2017/7/16
* Time: 下午1:39
* Email: lichenwei.me@foxmail.com
*/
public class ViewPagerTriangleIndicator extends LinearLayout {
private int mTriangleWidth;//三角形底边宽
private int mTriangleHeigh;//三角形高度
private int mTriangleInitPos;//三角形起始点
private int mTriangleMoveWidth;//三角形移动偏移
private Paint mPaint;
private Path mPath;
public ViewPagerTriangleIndicator(Context context) {
super(context, null);
}
public ViewPagerTriangleIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
}
/**
* 初始化画笔
*/
private void initPaint() {
mPaint = new Paint();
mPaint.setColor(Color.parseColor("#FFFFFF"));
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
}
/**
* 初始化三角形
*/
private void initTriangle() {
mPath = new Path();
mPath.moveTo(0, 0);
mPath.lineTo(mTriangleWidth, 0);
mPath.lineTo(mTriangleWidth / 2, -mTriangleHeigh);
mPath.close();
}
/**
* 当布局大小发生变化时回调
*
* @param w
* @param h
* @param oldw
* @param oldh
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mTriangleWidth = w / 3 / 6;
mTriangleHeigh = mTriangleWidth / 2 - 12;
mTriangleInitPos = getScreenWidth() / 3 / 2 - mTriangleWidth / 2;
initTriangle();
}
/**
* 绘制子View
*
* @param canvas
*/
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.translate(mTriangleInitPos + mTriangleMoveWidth, getHeight());
canvas.drawPath(mPath, mPaint);
}
/**
* 监听ViewPager滑动,联动Indicator
*
* @param position
* @param positionOffset
*/
protected void scroll(int position, float positionOffset) {
int tabWidth = getScreenWidth() / 3;
mTriangleMoveWidth = (int) (tabWidth * position + tabWidth * positionOffset);
invalidate();
}
/**
* 获取屏幕宽度
*
* @return
*/
private int getScreenWidth() {
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
}
package com.lcw.viewpagertriangleindicator;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* ViewPgaer三角形指示器演示
* Create by: chenwei.li
* Date: 2017/7/16
* Time: 下午1:54
* Email: lichenwei.me@foxmail.com
*/
public class MainActivity extends AppCompatActivity {
private ViewPager mViewPager;
private ViewPagerTriangleIndicator mViewPagerTriangleIndicator;
private List<String> mTitles = Arrays.asList("新闻", "音乐", "游戏");
private List<Fragment> mFragments = new ArrayList<Fragment>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.vp_main_content);
mViewPagerTriangleIndicator = (ViewPagerTriangleIndicator) findViewById(R.id.vpti_main_tab);
//创建Fragment
for (String title : mTitles) {
SimpleFragmet simpleFragmet = SimpleFragmet.newInstance(title);
mFragments.add(simpleFragmet);
}
//设置适配器
mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getCount() {
return mFragments.size();
}
});
//添加滑动监听
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
mViewPagerTriangleIndicator.scroll(position, positionOffset);
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
}
看下效果图:
简单版本ViewPager指示器实现2、ViewPager指示器的封装
在上面我们已经实现了简单版本的ViewPager带三角形的滑动指示器实现,接下来我们需要对其进行封装,当它变得更加简单易用。
首先我们来分析下简单版本的不足:
1、Tab数量是固定的,每次都需要在XML里编写TextView,太过繁琐,当Tab数量很多的时候,并且weight都是1时,就会挤在一屏幕里。
2、调用太复杂,需要在Activity里去实现滑动监听,并调用三角形联动。
3、其他一些小细节,比如当Tab页只有1页或者2页的时候,指示器三角形会变得很大,影响美观等。
带着这些问题,我们开启ViewPagerTriangleIndicator的优化之旅吧!
首先我们需要一个当前页面可显示的最大Tab数,也就是屏幕可见区域的最大Tab数,这里引入我们的自定义属性(关于自定义属性的使用,这里就不再做过多阐述):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="visible_tab_num" format="integer" />
<declare-styleable name="ViewPagerTriangleIndicator">
<attr name="visible_tab_num" />
</declare-styleable>
</resources>
/**
* 获取自定义属性值(获取xml设置最大可见Tab数量)
*
* @param context
* @param attrs
*/
private void initAttr(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ViewPagerTriangleIndicator);
if (typedArray != null) {
mVisibleTabNum = typedArray.getInt(R.styleable.ViewPagerTriangleIndicator_visible_tab_num, VISIBLE_COUNT_NUM);
}
}
通过上面的代码我们就可以拿到在XML文件中visible_tab_num的值了,根据这个值我们按照上文提到的思路就可以得到一些数据,比如三角形的底边宽,高度,起始位置等。
需要注意的是当前的Tab的宽度就需要动态去计算了,我们根据屏幕宽度/可见Tab数,就可以得到每个Tab的宽度,我们在XML加载完毕的时候去进行动态的修改。
/**
* 在XML布局加载完毕后回调
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
//根据可显示的Tab数量动态去改变Tab的宽度
int totalTabNum = getChildCount();
if (mVisibleTabNum != 0 && totalTabNum != 0) {
for (int i = 0; i < totalTabNum; i++) {
View view = getChildAt(i);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) view.getLayoutParams();
layoutParams.weight = 0;
layoutParams.width = getScreenWidth() / mVisibleTabNum;
view.setLayoutParams(layoutParams);
}
}
}
还有,我们还需要对scroll方法进行一些改造:
/**
* 监听ViewPager滑动,联动Indicator
*
* @param position
* @param positionOffset
*/
protected void scroll(int position, float positionOffset) {
int tabWidth = getScreenWidth() / mVisibleTabNum;
mTriangleMoveWidth = (int) (tabWidth * position + tabWidth * positionOffset);
if ((mVisibleTabNum - 2) <= position && positionOffset > 0 && getChildCount() > mVisibleTabNum) {
this.scrollTo((int) ((position - (mVisibleTabNum - 2)) * tabWidth + tabWidth * positionOffset), 0);
}
invalidate();
}
当Tab数量超出一页的时候,随着三角形的滑动我们也需要对Tab进行一个滑动处理,这里举个例子:
当屏幕可见Tab数为4时,那么Tab从第3个滑动到第4个的时候,需要同时把第1个Tab往左移出屏幕,此时滑动距离相对于整个指示器为1个Tab的距离。
当屏幕可见Tab数为4时,那么Tab从第4个滑动到第5个的时候,需要同时把第2个Tab往左移出屏幕,此时滑动距离相对于整个指示器为2个Tab的距离。
哈哈,是不是有点绕,没想明白的朋友拿笔在纸上吧,上面的判断也是由此得出。
好了,接下来就要开始解决我们的问题了。
解决问题1:
既然ViewPager指示器是继承于线性布局LinearLayout,那也就是ViewGroup,我们很自然的可以想到addView这个方法,所以我们只需要让其接收一个List<String>的集合对象并根据集合元素的文字信息动态添加子View即可,实现代码如下:
/**
* 设置指示器标题并给标题添加监听事件
*
* @param titles
*/
public void setPageTitle(List<String> titles) {
this.mTitles = titles;
if (mTitles != null && mTitles.size() > 0) {
removeAllViews();
for (int i = 0; i < mTitles.size(); i++) {
TextView textView = new TextView(getContext());
LinearLayout.LayoutParams layoutParams = new LayoutParams(getScreenWidth() / mVisibleTabNum, LayoutParams.MATCH_PARENT);
layoutParams.width = getScreenWidth() / mVisibleTabNum;
textView.setText(mTitles.get(i));
textView.setGravity(Gravity.CENTER);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
textView.setTextColor(Color.parseColor("#FFFFFF"));
textView.setLayoutParams(layoutParams);
addView(textView);
}
}
}
解决问题2:
我们可以在ViewPager指示器内部去持有外部ViewPager的引用并且去实现滑动监听即可:
/**
* 绑定ViewPager
*
* @param viewPager
*/
public void setViewPagerWithIndicator(ViewPager viewPager) {
this.mViewPager = viewPager;
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (mAddPageChangeListener != null) {
mAddPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
scroll(position, positionOffset);
}
@Override
public void onPageSelected(int position) {
setInitPageTitlesColor();
setPageTitleHighColor(position);
mViewPager.setCurrentItem(position);
if (mAddPageChangeListener != null) {
mAddPageChangeListener.onPageSelected(position);
}
}
@Override
public void onPageScrollStateChanged(int state) {
if (mAddPageChangeListener != null) {
mAddPageChangeListener.onPageScrollStateChanged(state);
}
}
});
}
这里大家可能会注意到mAddPageChangeListener这个变量,这里是重写了原生自带addOnPageChangeListener的一个回调函数,因为我们在内部去实现了addOnPageChangeListener监听,当外部的ViewPager再去实现滑动监听时,此时就会把我们内部的实现方法覆盖,也就是会导致 scroll(position, positionOffset);
方法失效,所以这里我们需要再去定义一个滑动监听器即可,并且提供注册监听器方法。
/**
* 复制官方addOnPageChangeListener对应的接口方法
* Callback interface for responding to changing state of the selected page.
*/
public interface AddPageChangeListener {
/**
* This method will be invoked when the current page is scrolled, either as part
* of a programmatically initiated smooth scroll or a user initiated touch scroll.
*
* @param position Position index of the first page currently being displayed.
* Page position+1 will be visible if positionOffset is nonzero.
* @param positionOffset Value from [0, 1) indicating the offset from the page at position.
* @param positionOffsetPixels Value in pixels indicating the offset from position.
*/
void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
/**
* This method will be invoked when a new page becomes selected. Animation is not
* necessarily complete.
*
* @param position Position index of the new selected page.
*/
void onPageSelected(int position);
/**
* Called when the scroll state changes. Useful for discovering when the user
* begins dragging, when the pager is automatically settling to the current page,
* or when it is fully stopped/idle.
*
* @param state The new scroll state.
* @see ViewPager#SCROLL_STATE_IDLE
* @see ViewPager#SCROLL_STATE_DRAGGING
* @see ViewPager#SCROLL_STATE_SETTLING
*/
void onPageScrollStateChanged(int state);
}
/**
* 避免用户监听ViewPager复写了addOnPageChangeListener使得三角形滑动效果失效
*
* @param addPageChangeListener
*/
public void addPageChangeListener(AddPageChangeListener addPageChangeListener) {
this.mAddPageChangeListener = addPageChangeListener;
}
解决问题3:
这里我们只需要去定义一个三角形底部宽度的默认最大值即可,这个默认值可以是屏幕宽度的三分之一的六分之一,也就是当有3个Tab时候,三角形底部的宽度。
private int DEFAULT_TRIANGLE_WIDTH = getScreenWidth() / 3 / 6;//最大三角形底边宽度
if (mTriangleWidth > DEFAULT_TRIANGLE_WIDTH) {
mTriangleWidth = DEFAULT_TRIANGLE_WIDTH;
}
再来我们还可以去做一些事情,比如设置Tab的文字默认颜色,高亮颜色,监听事件等。
这里我把完整的ViewPagerTriangleIndicator代码贴一下:
package com.lcw.viewpagertriangleindicator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.List;
/**
* 自定义ViewPager指示器(三角形)
* Create by: chenwei.li
* Date: 2017/7/16
* Time: 下午1:39
* Email: lichenwei.me@foxmail.com
*/
public class ViewPagerTriangleIndicator extends LinearLayout {
private int mTriangleWidth;//三角形底边宽
private int mTriangleHeigh;//三角形高度
private int mTriangleInitPos;//三角形起始点
private int mTriangleMoveWidth;//三角形移动偏移
private int DEFAULT_TRIANGLE_WIDTH = getScreenWidth() / 3 / 6;//最大三角形底边宽度
private Paint mPaint;
private Path mPath;
private int mVisibleTabNum;//最大可显示Tab数量值
private static final int VISIBLE_COUNT_NUM = 4;//默认可显示的TAB数量为4个
private List<String> mTitles;//保存指示器标题
private ViewPager mViewPager;//次有外部ViewPager引用
private AddPageChangeListener mAddPageChangeListener;
public ViewPagerTriangleIndicator(Context context) {
super(context, null);
}
public ViewPagerTriangleIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
initAttr(context, attrs);
initPaint();
}
/**
* 获取自定义属性值(获取xml设置最大可见Tab数量)
*
* @param context
* @param attrs
*/
private void initAttr(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ViewPagerTriangleIndicator);
if (typedArray != null) {
mVisibleTabNum = typedArray.getInt(R.styleable.ViewPagerTriangleIndicator_visible_tab_num, VISIBLE_COUNT_NUM);
}
}
/**
* 初始化画笔
*/
private void initPaint() {
mPaint = new Paint();
mPaint.setColor(Color.parseColor("#FFFFFF"));
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
}
/**
* 初始化三角形
*/
private void initTriangle() {
mPath = new Path();
mPath.moveTo(0, 0);
mPath.lineTo(mTriangleWidth, 0);
mPath.lineTo(mTriangleWidth / 2, -mTriangleHeigh);
mPath.close();
}
/**
* 当布局大小发生变化时回调
*
* @param w
* @param h
* @param oldw
* @param oldh
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mTriangleWidth = w / mVisibleTabNum / 6;
if (mTriangleWidth > DEFAULT_TRIANGLE_WIDTH) {
mTriangleWidth = DEFAULT_TRIANGLE_WIDTH;
}
mTriangleHeigh = mTriangleWidth / 2 - 8;
mTriangleInitPos = w / mVisibleTabNum / 2 - mTriangleWidth / 2;
initTriangle();
}
/**
* 在XML布局加载完毕后回调
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
//根据可显示的Tab数量动态去改变Tab的宽度
int totalTabNum = getChildCount();
if (mVisibleTabNum != 0 && totalTabNum != 0) {
for (int i = 0; i < totalTabNum; i++) {
View view = getChildAt(i);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) view.getLayoutParams();
layoutParams.weight = 0;
layoutParams.width = getScreenWidth() / mVisibleTabNum;
view.setLayoutParams(layoutParams);
}
}
}
/**
* 绘制子View
*
* @param canvas
*/
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.translate(mTriangleInitPos + mTriangleMoveWidth, getHeight());
canvas.drawPath(mPath, mPaint);
}
/**
* 监听ViewPager滑动,联动Indicator
*
* @param position
* @param positionOffset
*/
protected void scroll(int position, float positionOffset) {
int tabWidth = getScreenWidth() / mVisibleTabNum;
mTriangleMoveWidth = (int) (tabWidth * position + tabWidth * positionOffset);
if ((mVisibleTabNum - 2) <= position && positionOffset > 0 && getChildCount() > mVisibleTabNum) {
this.scrollTo((int) ((position - (mVisibleTabNum - 2)) * tabWidth + tabWidth * positionOffset), 0);
}
invalidate();
}
/**
* 获取屏幕宽度
*
* @return
*/
private int getScreenWidth() {
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displayMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
/**
* 设置指示器标题并给标题添加监听事件
*
* @param titles
*/
public void setPageTitle(List<String> titles) {
this.mTitles = titles;
if (mTitles != null && mTitles.size() > 0) {
removeAllViews();
for (int i = 0; i < mTitles.size(); i++) {
final int pageIndex = i;
TextView textView = new TextView(getContext());
LinearLayout.LayoutParams layoutParams = new LayoutParams(getScreenWidth() / mVisibleTabNum, LayoutParams.MATCH_PARENT);
layoutParams.width = getScreenWidth() / mVisibleTabNum;
textView.setText(mTitles.get(i));
textView.setGravity(Gravity.CENTER);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
textView.setTextColor(Color.parseColor("#FFFFFF"));
textView.setLayoutParams(layoutParams);
textView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//点击高亮文本
setInitPageTitlesColor();
((TextView) v).setTextColor(Color.parseColor("#FFFFFF"));
mViewPager.setCurrentItem(pageIndex);
}
});
addView(textView);
}
}
setInitPageTitlesColor();
setPageTitleHighColor(0);
}
/**
* 把所有标题颜色置为不高亮
*/
private void setInitPageTitlesColor() {
int totalView = getChildCount();
for (int i = 0; i < totalView; i++) {
View view = getChildAt(i);
if (view instanceof TextView) {
((TextView) view).setTextColor(Color.parseColor("#70FFFFFF"));
}
}
}
/**
* 设置标题高亮
*
* @param pos
*/
private void setPageTitleHighColor(int pos) {
View view = getChildAt(pos);
if (view instanceof TextView) {
((TextView) view).setTextColor(Color.parseColor("#FFFFFF"));
}
}
/**
* 绑定ViewPager
*
* @param viewPager
*/
public void setViewPagerWithIndicator(ViewPager viewPager) {
this.mViewPager = viewPager;
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (mAddPageChangeListener != null) {
mAddPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
scroll(position, positionOffset);
}
@Override
public void onPageSelected(int position) {
setInitPageTitlesColor();
setPageTitleHighColor(position);
mViewPager.setCurrentItem(position);
if (mAddPageChangeListener != null) {
mAddPageChangeListener.onPageSelected(position);
}
}
@Override
public void onPageScrollStateChanged(int state) {
if (mAddPageChangeListener != null) {
mAddPageChangeListener.onPageScrollStateChanged(state);
}
}
});
}
/**
* 避免用户监听ViewPager复写了addOnPageChangeListener使得三角形滑动效果失效
*
* @param addPageChangeListener
*/
public void addPageChangeListener(AddPageChangeListener addPageChangeListener) {
this.mAddPageChangeListener = addPageChangeListener;
}
/**
* 复制官方addOnPageChangeListener对应的接口方法
* Callback interface for responding to changing state of the selected page.
*/
public interface AddPageChangeListener {
/**
* This method will be invoked when the current page is scrolled, either as part
* of a programmatically initiated smooth scroll or a user initiated touch scroll.
*
* @param position Position index of the first page currently being displayed.
* Page position+1 will be visible if positionOffset is nonzero.
* @param positionOffset Value from [0, 1) indicating the offset from the page at position.
* @param positionOffsetPixels Value in pixels indicating the offset from position.
*/
void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
/**
* This method will be invoked when a new page becomes selected. Animation is not
* necessarily complete.
*
* @param position Position index of the new selected page.
*/
void onPageSelected(int position);
/**
* Called when the scroll state changes. Useful for discovering when the user
* begins dragging, when the pager is automatically settling to the current page,
* or when it is fully stopped/idle.
*
* @param state The new scroll state.
* @see ViewPager#SCROLL_STATE_IDLE
* @see ViewPager#SCROLL_STATE_DRAGGING
* @see ViewPager#SCROLL_STATE_SETTLING
*/
void onPageScrollStateChanged(int state);
}
}
3、ViewPager指示器的使用
经过我们封装之后,我们的调用就非常简单了,只需要短短的2行代码:
//设置指示器标题
mViewPagerTriangleIndicator.setPageTitle(mTitles);
//绑定ViewPager
mViewPagerTriangleIndicator.setViewPagerWithIndicator(mViewPager);
好了,文章到这里就结束了,由于篇幅限制,这里不能对一些东西讲的太细,比如一些自定义View的基础,大家自行查阅相关资料哈。
源码下载:
这里附上源码地址(欢迎Star,欢迎Fork):源码下载