自定义ViewPager指示器

时间:2022-08-30 00:18:27

一、项目运行效果图

      自定义ViewPager指示器    自定义ViewPager指示器

 

二、项目结构

      自定义ViewPager指示器   自定义ViewPager指示器

 

三、自定义ViewPager指示器,继承LinearLayout

自定义ViewPager指示器自定义ViewPager指示器
package com.yuanlei.viewpagerindicator.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
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.ViewGroup;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.yuanlei.viewpagerindicator.R;

import java.util.List;

/**
* Created by 袁磊 on 2017/2/22.
*/
public class ViewPagerIndicator extends LinearLayout {


private Paint mPaint;//画笔
private Path mPath;//画笔路径
private int mTriangleWidth;//三角形宽度
private int mTriangleHeight;//三角形高度

private static final float RADIO_TRIANGLE_WIDTH = 1 / 6F;//三角形宽度与所指TextView的宽度比例
//三角形底边的最大宽度
private final int DIMENSION_TRIANGLE_WIDTH_MAX = (int) (getScreenWidth() / 3 * RADIO_TRIANGLE_WIDTH);

private int mInitTranslationX;//三角形所在初始位置
private int mTranslationX;//移动时候的位置坐标

private int mTabVisibleCount;//显示的tab数量
private static final int COUNT_DEFAULT_TAB = 4;//默认显示四个
private static final int COLOR_TEXT_NORMAL = 0x77FFFFFF;//字体颜色
private static final int COLOR_TEXT_HIGHLIGHT = 0xFFFFFFFF;//字体颜色高亮显示

private List<String> mTitles;


public ViewPagerIndicator(Context context) {
this(context, null);
}

public ViewPagerIndicator(Context context, AttributeSet attrs) {
super(context, attrs);

//获取自定义属性(可见Tab数量)
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewPagerIndicator);

mTabVisibleCount
= a.getInt(R.styleable.ViewPagerIndicator_visible_tab_count, COUNT_DEFAULT_TAB);
if (mTabVisibleCount < 0) {
mTabVisibleCount
= COUNT_DEFAULT_TAB;//获取到显示的Tab后在onFinishInflate()方法中使用
}

a.recycle();
//释放

//初始化画笔
mPaint = new Paint();
mPaint.setAntiAlias(
true);//抗锯齿
mPaint.setColor(Color.parseColor("#ffffffff"));
mPaint.setStyle(Paint.Style.FILL);
mPaint.setPathEffect(
new CornerPathEffect(3));//圆角
}

@Override
protected void dispatchDraw(Canvas canvas) {
//绘制三角形

canvas.save();

canvas.translate(mInitTranslationX
+ mTranslationX, getHeight() + 2);
canvas.drawPath(mPath, mPaint);

canvas.restore();

super.dispatchDraw(canvas);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);

mTriangleWidth
= (int) (w / mTabVisibleCount * RADIO_TRIANGLE_WIDTH);//三角形宽度
mTriangleWidth = Math.min(mTriangleWidth, DIMENSION_TRIANGLE_WIDTH_MAX);//获取最大值和当前值中最小的
mInitTranslationX = w / mTabVisibleCount / 2 - mTriangleWidth / 2;//三角形初始坐标

initTriangle();
}

/**
* 通过布局添加Tab的时候
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();

int cCount = getChildCount();
if (cCount == 0) return;

for (int i = 0; i < cCount; i++) {
View view
= getChildAt(i);//得到每一个子View
//注意:layoutParams为LinearLayout.LayoutParams
LayoutParams lp = (LayoutParams) view.getLayoutParams();
lp.weight
= 0;
lp.width
= getScreenWidth() / mTabVisibleCount;//每一个子View宽度=屏幕宽度/显示的Tab数量
view.setLayoutParams(lp);
}
setItemClickEvent();
//设置Tab点击事件

}

/**
* 初始化三角形
*/
private void initTriangle() {

mTriangleHeight
= mTriangleWidth / 2;

mPath
= new Path();
mPath.moveTo(
0, 0);//画笔从三角形左下角(0,0)开始
mPath.lineTo(mTriangleWidth, 0);
mPath.lineTo(mTriangleWidth
/ 2, -mTriangleHeight);//y轴向上是负
mPath.close();
}

/**
* 指示器跟随手指进行移动
*
*
@param position
*
@param offset
*/
public void scroll(int position, float offset) {
int tabWidth = getWidth() / mTabVisibleCount;
mTranslationX
= (int) (tabWidth * (offset + position));


/**
* 容器(整个指示器)移动,当Tab处于移动至最后一个时
*/
if (position >= (mTabVisibleCount - 2) && //三角形所在位置数>(当前显示Tab的个数-2)(position从0开始)
offset > 0 //偏移量>0
&& getChildCount() > mTabVisibleCount //所有Tab个数>当前显示Tab个数
&& position != (mTitles.size() - 2)) { //位置!=tab总个数-2(position从0开始)
if (mTabVisibleCount != 1) { //防止mTabVisibleCount - 2=-1
this.scrollTo((position - (mTabVisibleCount - 2)) * tabWidth + (int) (tabWidth * offset), 0);
}
else {
this.scrollTo(position * tabWidth + (int) (tabWidth * offset), 0);
}
}

//重绘方法
invalidate();
}

/**
* 获得屏幕宽度
*
*
@return
*/
private int getScreenWidth() {
WindowManager wm
= (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics
= new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.widthPixels;
}

/**
* 动态添加子View
*
*
@param titles
*/
public void setTabItemTitles(List<String> titles) {
if (titles != null && titles.size() > 0) {
this.removeAllViews();//先清理所有View
mTitles = titles;
for (String title : mTitles) {
addView(generateTextView(title));
}
setItemClickEvent();
//设置Tab点击事件
}
}


/**
* 设置可见的Tab数量
* 注意:需要在setTabItemTitles()之前调用
*
*
@param count
*/
public void setVisibleTabCount(int count) {
mTabVisibleCount
= count;
}

/**
* 根据title创建tab
*
*
@param title
*
@return
*/
private View generateTextView(String title) {
TextView tv
= new TextView(getContext());
LinearLayout.LayoutParams lp
= new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
lp.width
= getScreenWidth() / mTabVisibleCount;
tv.setText(title);
tv.setGravity(Gravity.CENTER);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP,
16);
tv.setTextColor(COLOR_TEXT_NORMAL);
tv.setLayoutParams(lp);
return tv;
}

private ViewPager mViewPager;

/**
* 自定义接口
* 复制源代码中的三个抽象方法
*/
public interface PagerOnChangeListener {

void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);

void onPageSelected(int position);

void onPageScrollStateChanged(int state);
}

//接口成员
private PagerOnChangeListener mListener;

//公布接口
public void setPagerOnChangeListener(PagerOnChangeListener listener) {
this.mListener = listener;
}

/**
* 设置关联的ViewPager
*
*
@param viewPager
*
@param position 当前位置
*/
public void setViewPager(ViewPager viewPager, int position) {
mViewPager
= viewPager;
mViewPager.addOnPageChangeListener(
new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
/**
* 三角形总的偏移量=
* tabWidth(三角形移动距离为一个tabWidth)*positionOffset(ViewPger的偏移量)+
* postion*tabWidth
*/
scroll(position, positionOffset);

//通过自定义接口将回调方法公布出去
if (mListener != null) {
mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
}

@Override
public void onPageSelected(int position) {
//通过自定义接口将回调方法公布出去
if (mListener != null) {
mListener.onPageSelected(position);
}
highLightTextView(position);
}

@Override
public void onPageScrollStateChanged(int state) {
//通过自定义接口将回调方法公布出去提供外部使用
if (mListener != null) {
mListener.onPageScrollStateChanged(state);
}
}
});
mViewPager.setCurrentItem(position);
highLightTextView(position);
}

/**
* 重置Tab的文本颜色
*/
private void resetTextView() {
for (int i = 0; i < getChildCount(); i++) {
View view
= getChildAt(i);
if (view instanceof TextView) {
((TextView) view).setTextColor(COLOR_TEXT_NORMAL);
}
}
}

/**
* 高亮某个Tab的文本
*
*
@param position
*/
private void highLightTextView(int position) {
resetTextView();
//高亮之前全部文本颜色全部重置
View view = getChildAt(position);
if (view instanceof TextView) {
((TextView) view).setTextColor(COLOR_TEXT_HIGHLIGHT);
}
}

/**
* 设置Tab点击事件
*/
private void setItemClickEvent() {
int cCount = getChildCount();

for (int i = 0; i < cCount; i++) {
final int j = i;//供内部类调用
View view = getChildAt(i);
view.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
mViewPager.setCurrentItem(j);
}
});
}
}
}
ViewPagerIndicator

 

四、自定义属性: attrs.xml

自定义ViewPager指示器自定义ViewPager指示器
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="visible_tab_count" format="integer" />
<declare-styleable name="ViewPagerIndicator">
<attr name="visible_tab_count" />
</declare-styleable>
</resources>
attrs

 

五、一个简单的Fragment,供ViewPager使用

自定义ViewPager指示器自定义ViewPager指示器
package com.yuanlei.viewpagerindicator.viewpagerindicator;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
* Created by 袁磊 on 2017/2/22.
*/
public class VpSimpleFragment extends Fragment {
private String mTitle;
public static final String BUNDLE_TITLE = "title";

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Bundle bundle
= getArguments();

if (bundle != null) {
mTitle
= bundle.getString(BUNDLE_TITLE);
}

TextView tv
= new TextView(getActivity());
tv.setText(mTitle);
tv.setGravity(Gravity.CENTER);

return tv;
}

public static VpSimpleFragment newInstanse(String title) {
Bundle bundle
= new Bundle();
bundle.putString(BUNDLE_TITLE, title);

VpSimpleFragment fragment
= new VpSimpleFragment();
fragment.setArguments(bundle);

return fragment;
}


}
VpSimpleFragment

 

六、设置没有标题

自定义ViewPager指示器

 

七、使用

      布局文件: 

自定义ViewPager指示器自定义ViewPager指示器
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width
="match_parent"
android:layout_height
="match_parent"
android:orientation
="vertical">

<com.yuanlei.viewpagerindicator.view.ViewPagerIndicator
android:id
="@+id/my_vp_indicator"
android:layout_width
="match_parent"
android:layout_height
="45dp"
android:background
="@drawable/bg_top"
android:orientation
="horizontal" />

<android.support.v4.view.ViewPager
android:id
="@+id/vp_content"
android:layout_width
="match_parent"
android:layout_height
="0dp"
android:layout_weight
="1" />

</LinearLayout>
activity_main

      代码:

自定义ViewPager指示器自定义ViewPager指示器
package com.yuanlei.viewpagerindicator.viewpagerindicator;

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 android.os.Bundle;

import com.yuanlei.viewpagerindicator.R;
import com.yuanlei.viewpagerindicator.view.ViewPagerIndicator;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MainActivity extends AppCompatActivity {

private ViewPagerIndicator myIndicator;
private ViewPager vpContent;

private List<String> mTitles = Arrays.asList("短信1", "收藏2", "推荐3", "短信4", "收藏5", "推荐6", "短信7", "收藏8", "推荐9");
private List<VpSimpleFragment> mContents = new ArrayList<>();
private FragmentPagerAdapter mAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);

initViews();
initDatas();

myIndicator.setVisibleTabCount(
4);
myIndicator.setTabItemTitles(mTitles);
myIndicator.setViewPager(vpContent,
0);

vpContent.setAdapter(mAdapter);
}

private void initViews() {
vpContent
= (ViewPager) findViewById(R.id.vp_content);
myIndicator
= (ViewPagerIndicator) findViewById(R.id.my_vp_indicator);
}


private void initDatas() {

for (String title : mTitles) {
VpSimpleFragment fragment
= VpSimpleFragment.newInstanse(title);
mContents.add(fragment);
}

mAdapter
= new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
return mContents.get(position);
}

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

}
MainActivity