如何自定义控件

1、自定义属性的声明与获取

2、测量onMeasure

3、布局onLayout(ViewGroup)

4、绘制onDraw

5、onTouchEven

6、onInterceptTouchEven(ViewGroup)


一、自定义属性的声明与获取

1.分析需要的自定义属性

2.在res/values/attrs.xml定义声明

<?xml version="1.0" encoding="utf-8"?>
<resources>
	<attr name="icon" format="reference"></attr>
	<attr name="color" format="color"></attr>
	<attr name="text" format="string"></attr>
	<attr name="text_size" format="demension"></attr>
	<declare-styleable name="ChangeColorIconWithText">
		<attr name="icon"></attr>
		<attr name="color"></attr>
		<attr name="text"></attr>
		<attr name="text_size"></attr>
	</declare-styleable>
</resources>

3.在layout xml文件中进行使用

4.在View的构造方法中进行获取

TypedArray a = context.obtainStyledAtributes(attrs, R.styleable.ChangeColorIconWithText);
int n = a.getIndexCount();
for(int i=0; i<n; i++){
	int attr = a.getIndex(i);
	switch(attr){
	case R.styleable.ChangeColorIconWithText_icon:
		BitmapDrawable drawable = (BitmapDrawable) a.getDrawable(attr);
		mmIconBitmap = drawable.getBitmap();
		break;
	case R.styleable.ChangeColorIconWithText_color:
		mColor = a.getColor(attr, 0xFF45C01A);
		break;
	case R.styleable.ChangeColorIconWithText_text:
		mText = a.getString(attr);
		break;
	case R.styleable.ChangeColorIconWithText_text_size:
		mTextSize = (int) a.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, getReources().getDisplayMetrics()));
		break;
	}
}
a.recycke();

二、测量onMeasure

1.EXACTLY,AT_MOST,UNSPECIFIED
2.MeasureSpec
3.setMeasuredDimension
4.requestLayout()

private int measureHeight(int heightMeasureSpec){
	int result = 0;
	int mode = MeasureSpec.getMode(heightMeasureSpec);
	int size = MeasureSpec.getSize(heightMeasureSpec);
	
	if(mode == MeasureSpec.EXACTLY){
		requestLayout = size;
	}else {
		// 计算自身需要的高度
		requestLayout = getNeedHeight() + getPaddingTop() + getPaddingBottom();
		
		if(mode == MeasureSpec.AT_MOST){
			result = Math.min(result, size);
		}
	}
	return result;
}
三、布局onLayout(ViewGroup)
1.决定子Veiw的位置

2.尽可能将onMeasure中一些操作移动到此方法中

3.requestLayout()

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b){
	final int childCount = getChildCount();
	for(int i=0; i<childCount; i++){
		final View child = getChilAt(i);
		
		if(child.getVisibiility()==GONE){
			continue;
		}
		
		//计算childview layout的左上角x坐标
		left = caculateChildLeft();
		//计算childview layout的左上角y坐标
		top = caculateChildRight();
		
		child.layout(left, top, left + cWidth, top + cWidth);
	}
}
四、绘制onDraw

1.绘制内容区域
2.invalidate(), postInvalidate();
3.Canvas.drawXXX
4.translate、rotate、scale、skew
5.save()、restore()

@Override
protected synchronized void onDraw(Canvas canvas){
	//使用Canvas相关的API绘制anything you want
}
五、onTouchEven

1.ACTION_DOWN、ACTION_MOVE、ACTION_UP
2.ACTION_POINER_DOWN、ACTION_POINTER_UP
3.parent.requedtDisallowInterceptTouchEvent(true);
4.VelocityTracker

@Override
public boolean onTouchEven(MotionEvent ev){
	initVelocityTrackerIfNotExists();
	mVelocityTracker.addMovement(ev);
	
	final int action = ev.getAtction();
	switch(action & MotionEvent.ACTION_MASK){
	case MotionEvent.ACTION_DWON:
		//进行一些初始化、赋值等的操作
		break;
	case MotionEvent.ACTION_MOVE:
		break;
	case MotionEvent.ACTION_UP:
		//如果需要进行速度判断
		int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
		//释放各种资源、重复变量
		break;
	case MotionEvent.CANCLE:
		//释放各种资源、重复变量
		break;
	case MotionEvent.ACTION_POINER_DOWN:
		/如果支持多指,在此设置activePoniter
		final int index = ev.getAtctionIndex();
		mLastMotionY = (int) ev.getY(index);
		mActivePointerId = ev.getPointerId(index);
		break;
	case MotionEvent.ACTION_POINER_UP:
		//如果支持的是多指且抬起的是activePoniter,则重新选择一个手指为活跃的手指
		if(pointerId == mActivePointerId){
			final int newPointerIndex = pointerIndex == 0?1:0;
			mLastMotionY = (int) ev.getY(newPointerIndex);
			mActivePointerId = ev.getPointerId(newPointerIndex);
			if(mVelocityTracker != null){
				mVelocityTracker.clear();
			}
		}
		break;
	}
	return true;
}
六、onInterceptTouchEven(ViewGroup)
1.ACTION_DOWN、ACTION_MOVE、ACTION_UP
2.ACTION_POINER_DOWN、ACTION_POINTER_UP
3.决定是否拦截该手势

@Override
public boolean onInterceptTouchEven(MotionEvent ev){
	int action = ev.getAtction();
	
	switch(action & MotionEvent.ACTION_MASK){
	case MotionEvent.ACTION_MOVE:
		final int activePointerId = mActivePointerId;
		if(activePointerId == INVALID_POINTER){
			break;
		}
		final int pointerIndex = ev.getAtctionIndex(activePointerId);
		final int y = (int) ev.getY(pointerIndex);
		final int yDiff = Math.abs(y - mLastMotionY);
		if(yDiff > mTouchSlop){
			mIsBeingDragged = true;
			mLastMotionY = y;
		}
		break;
	case MotionEvent.ACTION_DWON:
		break;
	case MotionEvent.CANCLE:
	case MotionEvent.ACTION_UP:
		break;
	return mIsBeingDragged;
}
七、还有什么?
1.onSaveInstanceState、onRestoreInstanceState
2.ViewConfiguration(mTouchSlop等)
3.ScaleGestureDetector
4.更多...

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值