ViewPagerIndicator.java

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;
//三角形的底边最大宽度
private final float DIMENTION_TRIANGLE_WIDTH_MAX = getScreenWidth() / 3 * RADIO_TRIANGLE_WIDTH;
private int mInitTranslationX;
private int mTranslationX;
private int mVisibleTabCount;
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 ViewPager mViewPager;
private HorizontalScrollView mScrollView;
private boolean isClicked = false; //判断是否是由点击产生的滑动
private int scrollLocation; //Tab滚动的位置 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);
mVisibleTabCount = a.getInt(R.styleable.ViewPagerIndicator_visible_table_count, COUNT_DEFAULT_TAB); if (mVisibleTabCount < 0) {
mVisibleTabCount = COUNT_DEFAULT_TAB;
}
a.recycle(); int w = getScreenWidth(); //屏幕宽度
Log.i("屏幕宽度", w+""); mTriangleWidth = (int) (w / mVisibleTabCount * RADIO_TRIANGLE_WIDTH);
mTriangleWidth = (int) Math.min(mTriangleWidth, DIMENTION_TRIANGLE_WIDTH_MAX);
mInitTranslationX = w / mVisibleTabCount / 2 - mTriangleWidth / 2;
Log.i("InitTranslationX", ""+mInitTranslationX);
Log.i("mTrianglewidth", mTriangleWidth+"");
Log.i("TabWidth", ""+(int)(w/mVisibleTabCount));
initTriangle(); //初始化画笔
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.parseColor("#ffffff"));
mPaint.setStyle(Paint.Style.FILL);
mPaint.setPathEffect(new CornerPathEffect(3));
} public interface OnPageChangeListener {
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); public void onPageSelected(int position); public void onPageScrollStateChanged(int state);
} public OnPageChangeListener mListener; public void setOnPageChangedListener(OnPageChangeListener listener) {
this.mListener = listener;
} @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);
} /**
* 通过布局添加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);
LayoutParams lp = (LayoutParams) view.getLayoutParams();
lp.weight = 0;
lp.width = getScreenWidth() / mVisibleTabCount;
} setItemClickEvent();
} /**
* 获得屏幕的宽度
* @return
*/
private int getScreenWidth() {
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.widthPixels;
} /**
* 初始化三角形
*/
private void initTriangle() {
mTriangleHeight = mTriangleWidth / 2;
mPath = new Path();
mPath.moveTo(0,0);
mPath.lineTo(mTriangleWidth, 0);
mPath.lineTo(mTriangleWidth/2, -mTriangleHeight);
mPath.close();
} /**
* 指示器跟随手指进行滚动
* @param position
* @param offset
*/
public void scroll(int position, float offset) {
int tabWidth = getScreenWidth() / mVisibleTabCount;
mTranslationX = (int) (tabWidth * (position + offset));
invalidate(); //三角形的位置
int triangleLocation = mTranslationX + mInitTranslationX;
int screenWidth = getScreenWidth();
//当三角形处于滑动至屏幕外时移动外层ScrollView
if ((triangleLocation - scrollLocation) > (screenWidth - mInitTranslationX)
&& offset > 0.5 && !isClicked) {
if (mVisibleTabCount == 1) {
mScrollView.scrollTo(mTranslationX, 0);
scrollLocation = mTranslationX;
} else {
mScrollView.scrollTo((position - 2) * tabWidth, 0);
scrollLocation = (position - 2) * tabWidth;
}
} else if((triangleLocation - scrollLocation) < mInitTranslationX && offset > 0
&& offset < 0.5 && !isClicked) {
if (mVisibleTabCount == 1) {
mScrollView.scrollTo(mTranslationX, 0);
scrollLocation = mTranslationX;
} else {
mScrollView.scrollTo(position * tabWidth, 0);
scrollLocation = position * tabWidth;
}
}
//滑动完成时,将标记位恢复
if (offset == 0) {
isClicked = false;
}
} public void setTabItemTitles(List<String> titles) {
if(titles != null && titles.size() > 0) {
this.removeAllViews();
for (String title : titles) {
addView(generateTextView(title));
}
} setItemClickEvent();
} /**
* 根据title创建tab
* @param title
* @return
*/
private View generateTextView(String title) {
TextView tv = new TextView(getContext());
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
lp.width = getScreenWidth() / mVisibleTabCount;
tv.setText(title);
tv.setGravity(Gravity.CENTER);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
tv.setTextColor(COLOR_TEXT_NORMAL);
tv.setLayoutParams(lp);
return tv;
} /**
* 设置可见Tab数量
* @param count
*/
public void setVisibleTabCount(int count) {
mVisibleTabCount = count;
} /**
* 设置关联的ViewPager
* @param viewPager
* @param position
*/
public void setViewPager(ViewPager viewPager, int position) {
mViewPager = viewPager; viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
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);
}
}
}); viewPager.setCurrentItem(position);
highLightTextView(position);
} /**
* 设置外层HorizontalScrollView
* @param scrollView
*/
@RequiresApi(api = Build.VERSION_CODES.M)
public void setScrollView(HorizontalScrollView scrollView) {
mScrollView = scrollView; mScrollView.setOnScrollChangeListener(new OnScrollChangeListener() {
@Override
public void onScrollChange(View view, int i, int i1, int i2, int i3) {
scrollLocation = i2;
}
});
} /**
* 高亮显示选中tab文本
* @param position
*/
public void highLightTextView(int position) {
View view;
for (int i = 0; i < getChildCount(); i++) {
view = getChildAt(i);
if(view instanceof TextView) {
((TextView) view).setTextColor(COLOR_TEXT_NORMAL);
}
}
view = getChildAt(position);
if(view instanceof TextView) {
((TextView) view).setTextColor(COLOR_TEXT_HIGHLIGHT);
}
} /**
* 设置Tab的点击事件
*/
public 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 view) {
isClicked = true;
mViewPager.setCurrentItem(j);
}
});
}
} }

自定义ViewPagerIndicator-视图指示器的更多相关文章

  1. UICollectionView(集合视图)以及自定义集合视图

    一.UICollectionView集合视图           其继承自UIScrollView.         UICollectionView类是iOS6新引进的API,用于展示集合视图,布局 ...

  2. Android 自定义View修炼-自定义HorizontalScrollView视图实现仿ViewPager效果

    开发过程中,需要达到 HorizontalScrollView和ViewPager的效果,于是直接重写了HorizontalScrollView来达到实现ViewPager的效果. 实际效果图如下: ...

  3. 自定义View视图

    自定义View视图文件查找逻辑 之前MVC5和之前的版本中,我们要想对View文件的路径进行控制的话,则必须要对IViewEngine接口的FindPartialView或FindView方法进行重写 ...

  4. 自定义MVC视图引擎ViewEngine 创建Model的专属视图

    MVC内置的视图引擎有WebForm view engine和Razor view engine,当然也可以自定义视图引擎ViewEngine.本文想针对某个Model,自定义该Model的专属视图. ...

  5. Swift自定义头视图和尾视图

    var data: [[String]]! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup a ...

  6. ASP.NET MVC 自定义Razor视图WorkContext

    概述 1.在ASP.NET MVC项目开发的过程中,我们经常需要在cshtml的视图层输出一些公用信息 比如:页面Title.服务器日期时间.页面关键字.关键字描述.系统版本号.资源版本号等 2.普通 ...

  7. Office365学习笔记—Xslt自定义列表视图

    1,在Office365中需要添加自定义的视图!用Spd添加视图,这儿我添加一个testView! (1)打开testView.aspx将</ZoneTemplate>节点中的内容全部删除 ...

  8. 自定义ViewPagerIndicator

    1. 简介 学习Android,自定义View不可避免,之前一直忽视这块内容,现在开始学,应该不算太晚.从常见的ViewPagerIndicator开始,当然,万能的Github上包罗万象,好用的in ...

  9. 解读ASP.NET 5 & MVC6系列(16):自定义View视图文件查找逻辑

    之前MVC5和之前的版本中,我们要想对View文件的路径进行控制的话,则必须要对IViewEngine接口的FindPartialView或FindView方法进行重写,所有的视图引擎都继承于该IVi ...

  10. sap表维护工具来维护自定义表&视图簇的使用

    一.通过表维护工具维护自定义表 1.SE11创建表 2.se11界面的菜单:实用程序->Table Maintenance Generator其实这里就是调用SE54 3.sm30 调用维护好的 ...

随机推荐

  1. .NET MVC自定义Html辅助方法

    using System;using System.Web.Mvc;using System.Web.Routing; namespace MvcTest2.Helpers{ public stati ...

  2. [javaSE] 多线程(售票例子)

    需求:简单的买票程序,多个窗口卖票,多线程 定义一个类Ticket实现Runnable接口, 定义成员属性int类型的票数nums 实现run()方法,run方法中 while(true)的死循环,打 ...

  3. 1、类、封装(私有private、this关键字)

    类与对象 对象在需求中的使用 ​ 对面向对象有了了解之后,我们来说说在具体问题中如何使用面向对象去分析问题,和如何使用面向对象. ​ 我们把大象装冰箱为例进行分析. ​ 在针对具体的需求,可以使用名词 ...

  4. Spring MVC 实现Excel的导入导出功能(2:Excel的导入优化和Excel的导出)

    Excel的导入V2优化版 有些时候文件上传这一步骤由前端来处理,只将上传后的 URL 传输给后端(可以参考上一文中的图片上传功能),也就是导入请求中并不会直接处理 MultipartFile 对象, ...

  5. 小菜庄园 Spring------图片的上传和下载

    1.图片的上传前台三个条件 文件上传页面的3个要求:            < 1.表单提交为post.mothod="post"            < 2.表单的 ...

  6. H5演示文稿快速制作

    详见: http://www.geekfan.net/8107/ 或 http://www.jianshu.com/p/09a3bbb8b362

  7. [LeetCode]Delete and Earn题解(动态规划)

    Delete and Earn Given an array nums of integers, you can perform operations on the array. In each op ...

  8. uestc 1709 Binary Operations 位运算的灵活运用

    Binary Operations Time Limit: 2000 ms Memory Limit: 65535 kB Solved: 56 Tried: 674   Description   B ...

  9. 使用nodeJs安装Vue-cli (win10 使用管理员身份)

    TIP:win10下安装,使用管理员身份进行,否则会有权限限制. 1,安装完成node,node有自带的npm,可以直接在cmd中,找到nodeJs安装的路径下,进行命令行全局安装vue-cli.(n ...

  10. 计算球面两点间距离实现Vincenty+Haversine

    vincenty公式  精度很高能达到0.5毫米,但是很慢. Haversine公式半正矢公式,比vincenty快,精度没有vincenty高,也长使用. --------------------- ...