自定义Indicator 脑洞打开的指示器

我们的APP中,对ViewPage + Fragment 应用比较多
毕竟是花样展示
这里就设计到ViewPager的指示器的运用了
Android本身带有PagerTitleStrip,但原生的并不一定符合我们的审美
也见过太多自定义的Indicator,大都在控件外绘制
到了这里,大家有没有考虑到,如果我们把这个绘制指示器的功能一并放在我们的自定义控件了呢
这样是不是代码简化了好多

这里带着大家试试

1.首先,自定义控件属性

<resources>

    <declare-styleable name="Indicator">
        <attr name="color" format="color|reference" />
    </declare-styleable>

</resources>

2. 编写我们的自定义控件,这里我是继承LinearLayout ,测量绘制大大简化,都教给系统了

MyIndicator.class

/**
 * @author ruyi
 * @version 创建时间:2016年5月26日 下午5:55:14
 * 
 */
public class MyIndicator extends LinearLayout {
	private Paint mPaint; 

	private int mTop;
	private int mLeft; 
	private int mWidth; 
	private int mHeight = 5; 
	private int mColor; 
	private int mChildCount; 
	

	public MyIndicator(Context context, AttributeSet attrs) {
		super(context, attrs);
		setOrientation(LinearLayout.HORIZONTAL);
		setBackgroundColor(Color.TRANSPARENT); // 必须设置背景,否则onDraw不执行

		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.Indicator, 0, 0);
		mColor = a.getColor(R.styleable.Indicator_color, 0X0000FF);
		a.recycle();

		mPaint = new Paint();
		mPaint.setColor(mColor);
		mPaint.setAntiAlias(true);
	}

	/**
	 * 布局加载结束 ,获取childView 个数
	 */
	@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; //条目4等分

		setMeasuredDimension(width, height);
	}

	public void scroll(int position, float offset) {
		mLeft = (int) ((position + offset) * mWidth);
		invalidate();
	}

	/**
	 * 除绘制组件外,额外绘制指示器(一个矩形)
	 */
	@Override
	protected void onDraw(Canvas canvas) {
		Rect rect = new Rect(mLeft, mTop, mLeft + mWidth, mTop + mHeight);
		canvas.drawRect(rect, mPaint); 
		super.onDraw(canvas);
	}
}
这里指示器高度我们固定为5,宽度为屏幕宽度的1/4

在构造方法中初始化属性

在onFinishInflate(),中得到ChildView个数

重写onMeasure()方法,设置自定义控件为 在本来的高度上在加上指示器条的高度

在onDraw()方法里绘制指示器

当然必须提供一个方法来供外界改变指示器的位置方法,来达到动态滑动即 scroll(),设置后再调用重绘

我先贴下布局代码和调用方法,在解释原理

xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ruiyi="http://schemas.android.com/apk/res/com.ruiyi.testtab"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.ruiyi.testtab.MyIndicator
        android:id="@+id/indicator"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="10dip"
        android:paddingTop="10dip"
        android:weightSum="4"
        ruiyi:color="#FFD02090" >

        <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="小学" />

        <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="初中" />

        <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="高中" />

        <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="大学" />
    </com.ruiyi.testtab.MyIndicator>

    <android.support.v4.view.ViewPager
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>
设置总权重weightSun = 4 , 每个子View的权重为1

自定义属性赋值,记得命名空间的限制

调用 Activity

mViewpager.setOnPageChangeListener(new OnPageChangeListener() {
			@Override
			public void onPageSelected(int position) {
				Log.i("ASDFGHJKL", "11111111------"+position);//TODO
			}

			@Override
			public void onPageScrolled(int position, float positionOffset,
					int positionOffsetPixels) {
				mIndicator.scroll(position, positionOffset);
			}

			@Override
			public void onPageScrollStateChanged(int position) {
			}
		});

我简单解释下

指示器矩形框定义mTop, mLeft, mWidth, mHeight = 5;

1)宽度与子View宽度一致


onMeasure() 中
mLeft = 0;
mTop = getMeasuredHeight();   -----测量控件最原先的高,即上面存在的Title 的高
mWidth = getMeasuredWidth() / mChildCount;  ------宽为屏幕宽度除以子View数量
mHeight = 5;  -----高度固定为5

最初绘制时,指示器得位置为上述值,布局加载结束后draw了一个与子View宽度一致的指示器
当ViewPager滑动时,mLeft = (int) ((position + offset) * mWidth);

2)当设置指示器宽度为子View宽度的一半时


onMeasure() 中
mLeft = (getMeasuredWidth() / mChildCount)/4;
mTop = getMeasuredHeight();   -----测量控件最原先的高,即上面存在的Title 的高
mWidth = (getMeasuredWidth() / mChildCount)/2;  ------宽为屏幕宽度除以子View数量
mHeight = 5;  -----高度固定为5
最初绘制时,指示器得位置为上述值,布局加载结束后draw了一个与子View宽度一致的指示器(mLeft = 屏幕宽度/16)
当ViewPager滑动时,mLeft = (int)(m/4+(position+offset)*m);

(int position, float offset) 这里的position, offset为ViewPager 滑动监听传递过来的值


嗯,就这样

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值