自定义ViewPagerIndicator-视图指示器
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-视图指示器的更多相关文章
- UICollectionView(集合视图)以及自定义集合视图
一.UICollectionView集合视图 其继承自UIScrollView. UICollectionView类是iOS6新引进的API,用于展示集合视图,布局 ...
- Android 自定义View修炼-自定义HorizontalScrollView视图实现仿ViewPager效果
开发过程中,需要达到 HorizontalScrollView和ViewPager的效果,于是直接重写了HorizontalScrollView来达到实现ViewPager的效果. 实际效果图如下: ...
- 自定义View视图
自定义View视图文件查找逻辑 之前MVC5和之前的版本中,我们要想对View文件的路径进行控制的话,则必须要对IViewEngine接口的FindPartialView或FindView方法进行重写 ...
- 自定义MVC视图引擎ViewEngine 创建Model的专属视图
MVC内置的视图引擎有WebForm view engine和Razor view engine,当然也可以自定义视图引擎ViewEngine.本文想针对某个Model,自定义该Model的专属视图. ...
- Swift自定义头视图和尾视图
var data: [[String]]! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup a ...
- ASP.NET MVC 自定义Razor视图WorkContext
概述 1.在ASP.NET MVC项目开发的过程中,我们经常需要在cshtml的视图层输出一些公用信息 比如:页面Title.服务器日期时间.页面关键字.关键字描述.系统版本号.资源版本号等 2.普通 ...
- Office365学习笔记—Xslt自定义列表视图
1,在Office365中需要添加自定义的视图!用Spd添加视图,这儿我添加一个testView! (1)打开testView.aspx将</ZoneTemplate>节点中的内容全部删除 ...
- 自定义ViewPagerIndicator
1. 简介 学习Android,自定义View不可避免,之前一直忽视这块内容,现在开始学,应该不算太晚.从常见的ViewPagerIndicator开始,当然,万能的Github上包罗万象,好用的in ...
- 解读ASP.NET 5 & MVC6系列(16):自定义View视图文件查找逻辑
之前MVC5和之前的版本中,我们要想对View文件的路径进行控制的话,则必须要对IViewEngine接口的FindPartialView或FindView方法进行重写,所有的视图引擎都继承于该IVi ...
- sap表维护工具来维护自定义表&视图簇的使用
一.通过表维护工具维护自定义表 1.SE11创建表 2.se11界面的菜单:实用程序->Table Maintenance Generator其实这里就是调用SE54 3.sm30 调用维护好的 ...
随机推荐
- 167 -两个Sum II - 输入数组已排序
给定已按升序排序的整数数组,找到两个数字,使它们相加到特定的目标数. 函数twoSum应返回两个数字的索引,以便它们加起来到目标,其中index1必须小于index2. 注意: 您返回的答案(inde ...
- java map常用的4种遍历方法
public static void main(String[] args) { Map<String, String> map = new HashMap<String, Stri ...
- 非法关闭idea后报错,插件无法正常加载解决方法
Problems found loading plugins: Plugin "GlassFish Integration" was not loaded: required pl ...
- 如何使Wpf浏览器应用程序被完全信任运行
原文地址链接:http://blogs.microsoft.co.il/maxim/2008/03/05/how-to-run-wpf-xbap-as-full-trust-application/ ...
- python_Django 实现登入功能form表单的参数接收处理
1.创建Django工程. 参考https://www.cnblogs.com/CK85/p/10159159.html中步骤. 2.在urls.py文件中添加url分发路径 "" ...
- ThreeJS文字作为纹理贴图
文字作为纹理贴图 From:http://www.linhongxu.com/post/view?id=222 这里可以使用canvas作为纹理贴图,Three为我们提供里CanvasTexture ...
- Qt Quick程序的发布
要将程序发布出去,首先需要使用release方式编译程序,然后将生成的.exe可执行文件和需要的库文件发在一起打包进行发布. 要确定需要哪些动态库文件,可以直接双击.exe文件,提示缺少那个dll文件 ...
- 解决nexus3报Cannot open local storage 'component' with mode=rw的异常问题
起因:正常使用的公司Maven.Docker私有仓库,突然镜像不能推送,返回getsockopt: connection refused,用docker客户端登录也是返回同样的错误,查看nexus3日 ...
- SQL 常用语法
一.SQL分类 DDL—数据定义语言(CREATE,ALTER,DROP,DECLARE) DML—数据操纵语言(SELECT,DELETE,UPDATE,INSERT) DCL—数据控制语言(GRA ...
- 自动化测试基础篇--Selenium unittest生成测试报告(HTMLTestRunner)
如何生成HTMLTestRunner测试报告.接上篇文章,对于unittest框架,运行后,测试结果不便于查看,同时多个case存在的时候,可能会导致case result记录不正确的情况. 为此,引 ...