自定义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 调用维护好的 ...
随机推荐
- Spring中的Bean配置方式
1.IOC和DI概述 IOC(Inversion of Control):其思想是反转资源获取的方向. 传统的资源查找方式要求组件向容器发起请求查找资源. 作为回应, 容器适时的返回资源. 而应用了 ...
- idea 常用快捷键 笔记
1. main方法 输入psv tab或回车 类似的 psf fori (for循环) sout 备注: 通过ctrl+j 可以查询 2. 删除当前行 ctrl + y 3. 复制当前行 ctrl ...
- CSS实现太极图(3个div实现)
使用三个div实现太极图的步骤如下: HTML部分 <div class="box"> <div class="yin"></di ...
- js组件开发-移动端地区选择控件mobile-select-area
移动端地区选择控件mobile-select-area 由于之前的[js开源组件开发]js手机联动选择地区仿ios 开源git 很受欢迎,于是我又对其进行了一些优化,包括可选的范围变大了,添加了默认空 ...
- C语言四舍五入算法
对h进行四舍五入 1. 网络上搜索来的: C语言取整规则: (int)(h + 0.5) 2. 二级教程: 四舍五入并精确到小数点后面的第n位: 实例:
- Raspberry Pi - Huawei HiLink E3256 3G modem to ethernet adapter
Raspberry Pi - Huawei HiLink E3256 3G modem to ethernet adapter This page documents how to configure ...
- 七、angularjs 倒计时
使用定时器时离开页面需要清除定时器,清除的方法有两种分别针对页面有缓存和没有缓存 1.页面有缓存 2.页面没有缓存 angularjs倒计时首先需要注入:$interval 60s倒计时 vm.sec ...
- 深入理解C++中的初始化
C++经过这么多年的发展,已然成了一种文化和艺术,而这种艺术和文化并不是C++所固有的,是C++在各个方面的应用的总结和艺术化的结果.C++看起来比较复杂,但是深入其中你会发现C++是那么优美而富有哲 ...
- Scratch3.0——作品截图
原文地址:https://blog.csdn.net/weiwoyonzhe/article/details/86603217 Scratch 的舞台是基于canvas,最初尝试直接通过canvas的 ...
- Android开发精彩博文收藏——UI界面类
本文收集整理Android开发中关于UI界面的相关精华博文,共大家参考!本文不定期更新! 1. Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各 ...