自定义控件-ViewPagerIndicator(一)
本文摘录自元斌的博客 地址:
http://blog.csdn.net/qibin0506/article/details/42046559
上面的效果并没有加入fragment ,那是下一篇文章所记录的知识点,这个功能的亮点就在于 底部横线的滑动 ,虽然很简单但是总体的实现还是很有学习意义的。那么下来来看代码吧 。
先看整体的代码
public class ViewPagerIndicator extends LinearLayout {
private int mColor;//指示器的颜色
private int mItemCount;//tab的个数
private int DEFAULT_TAB_COUNT = 4;//默认的tab的个数
private int DEFAULT_INDICATOR_COLCR = 0x0000FF;//默认的indicator的颜色
private int mHeight = 5; // 指示符的高度,固定了
private int mTop;//整个Tab的高度
private int mWidth;//Indicator的宽
private Paint mPaint;//Indicator的画笔
private int mChildCount;//XML中的tab个数
private int mLeft; // 指示符的left
public ViewPagerIndicator(Context context) {
this(context, null);
}
public ViewPagerIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ViewPagerIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray tA = context.obtainStyledAttributes(attrs, R.styleable.ViewPagerIndicator, 0, 0);
mColor = tA.getColor(R.styleable.ViewPagerIndicator_indicator_color, DEFAULT_INDICATOR_COLCR);
mItemCount = tA.getInt(R.styleable.ViewPagerIndicator_item_count, DEFAULT_TAB_COUNT);
tA.recycle();
//初始化画笔
mPaint = new Paint();
mPaint.setColor(mColor);
mPaint.setAntiAlias(true);//抗锯齿设置
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mChildCount = getChildCount();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mTop = getMeasuredHeight(); // 测量的高度即指示符的顶部位置
int width = getMeasuredWidth(); // 获取测量的总宽度
int height = mTop + mHeight; // 重新定义一下测量的高度
mWidth = width / mChildCount; // 指示符的宽度为总宽度/item的个数
setMeasuredDimension(width, height);
}
@Override
protected void dispatchDraw(Canvas canvas) {
Rect rect = new Rect(mLeft, mTop, mWidth + mLeft, mTop + mHeight);
canvas.drawRect(rect, mPaint);
super.dispatchDraw(canvas);
}
/**
* 指示符滚动
*
* @param position 现在的位置
* @param offset 偏移量 0 ~ 1
*/
public void scroll(int position, float offset) {
mLeft = (int) ((position + offset) * mWidth);
invalidate();
}
众所周知要实现自定义控件 就要先集成 某个控件或者 集成View 这里我们集成 Linearlayout 重写三个构造方法
public ViewPagerIndicator(Context context) {
this(context, null);
}
public ViewPagerIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ViewPagerIndicator(Context context, AttributeSet attrs, int defStyleAttr)
在第三个构造中 初始化控件的属性
ublic ViewPagerIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray tA = context.obtainStyledAttributes(attrs, R.styleable.ViewPagerIndicator, 0, 0);
mColor = tA.getColor(R.styleable.ViewPagerIndicator_indicator_color, DEFAULT_INDICATOR_COLCR);
mItemCount = tA.getInt(R.styleable.ViewPagerIndicator_item_count, DEFAULT_TAB_COUNT);
tA.recycle();
//初始化画笔
mPaint = new Paint();
mPaint.setColor(mColor);
mPaint.setAntiAlias(true);//抗锯齿设置
}
属性的定义attr代码如下:
itemcount (抱歉此参数多余)
<declare-styleable name="ViewPagerIndicator">
<attr name="item_count" format="integer"></attr>
<attr name="indicator_color" format="color"></attr>
</declare-styleable>
重写onFinishInflate() 重新计算item的个数
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mChildCount = getChildCount();
}
onMeasure测量linerlayout的宽高并重新定义
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mTop = getMeasuredHeight(); // 测量的高度即指示符的顶部位置
int width = getMeasuredWidth(); // 获取测量的总宽度
int height = mTop + mHeight; // 重新定义一下测量的高度
mWidth = width / mChildCount; // 指示符的宽度为总宽度/item的个数
setMeasuredDimension(width, height);
}
接下来绘制indicator
@Override
protected void dispatchDraw(Canvas canvas) {
Rect rect = new Rect(mLeft, mTop, mWidth + mLeft, mTop + mHeight);
canvas.drawRect(rect, mPaint);
super.dispatchDraw(canvas);
}
这里要特别说明下ondraw()和 dispathdraw() 的区别
ViewGroup容器组件的绘制,当它没有背景时直接调用的是dispatchDraw()方法, 而绕过了draw()方法,当它有背景的时候就调用draw()方法,而draw()方法里包含了dispatchDraw()方法的调用。因此要在ViewGroup上绘制东西的时候往往重写的是dispatchDraw()方法而不是onDraw()方法。
下面就是关键点的所在了
自定义一个方法 scroll()把viewpage的滑动参数传递进来 动态的改变左侧左边的值就会看到咱们想要的结果了。 that’all is over!
/**
* 指示符滚动
*
* @param position 现在的位置
* @param offset 偏移量 0 ~ 1
*/
public void scroll(int position, float offset) {
mLeft = (int) ((position + offset) * mWidth);
invalidate();
}
***************使用***************************
XML代码
<com.yyr.custom.view.ViewPagerIndicator
xmlns:indicator="http://schemas.android.com/apk/res-auto"
android:id="@+id/indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dip"
android:paddingTop="10dip"
android:weightSum="4"
indicator:indicator_color="#FFFF0000" >
<TextView
android:id="@+id/tab_one"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:text="TAB1" />
<TextView
android:id="@+id/tab_two"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:text="TAB2" />
<TextView
android:id="@+id/tab_three"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:text="TAB3" />
<TextView
android:id="@+id/tab_four"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:text="TAB4" />
</com.yyr.custom.view.ViewPagerIndicator>
activity中调用
mViewPage.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
mIndicator.scroll(position, positionOffset);
}
@Override
public void onPageScrollStateChanged(int position) {
}
});
简单易理解才是一种提高!