android 自定义控件 ontouch,Android自定义控件细节

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

概述

在开发过程中,当系统提供的控件不能满足我们的需求的时候,通常都会采用自定义控件来完成,自定义控件的一般流程:

attrs.xml–>onMeasure()–>onLayout(ViewGroup)–>onDraw()–>onTouchEvent()–>onInterceptTouchEvent(ViewGroup);

其中带有ViewGroup的是自定义ViewGroup需要用到的方法.

自定义属性

自定义属性,一般定义用户可自定义的一些特性,关于自定义属性的声明和获取,网上的讲解也比较多了,之前关于自定义属性的总结Android 自定义属性解析,主要步骤:

在values目录下声明相关属性,在自定义控件的构造方法中获取这些属性,应用到自定义控件中.

onMeasure

onMeasure即测量,测量自定义控件的大小.测量的值是由两部分决定的[Mode和Size],Mode和Size都封装到了一个叫做MeasureSpec的类中;1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23private int (int widthMeasureSpec){

int result;

int mode = MeasureSpec.getMode(widthMeasureSpec);

int size = MeasureSpec.getSize(widthMeasureSpec);

if (mode == MeasureSpec.EXACTLY) {

// 这种模式通常是我们给View设置了一个值,如:android:layout_width="300dp"

// 或者 android:layout_width="match_parent",屏幕的宽度

result = size;

} else {

// MeasureSpec.UNSPECIFIED View的大小没有限制.

// 通常在ScrollView或者ListView中出现

result = getNeedWidth() + getPaddingLeft() + getPaddingRight();

if (mode == MeasureSpec.AT_MOST) {

// 至多不能超过某个值,一般出现在我们设置android:layout_width="wrap_content" 时

// 设置wrap_content,则View的尺寸由自身内容决定,但最大不能超过父控件的尺寸

// 这里 即和父控件传入的值 进行比较,取小(最多不能超过size)

result = Math.max(result, size);

}

}

return result;

}

在得到result 之后需要调用setMeasuredDimension(width,height);

requestLayout();会触发重新测量onMeasure()

onLayout

onLayout即布局,决定了ViewGroup中子View的显示位置. View中提供了空实现的onLayout,但自定义View一般不需要管,ViewGroup中的onLayout是抽象的,即必须实现.1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16protected 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 = getChildAt(i);

if (child.getVisibility() == GONE){

continue; //如果child为GONE,则不需要布局

}

int left = caculateChildLeft();//计算ChildView左上角x坐标

int top = caculateChildTop();//计算ChildView左上角y坐标

child.layout(left,top,left+childWidth,top+childHeight);//childWidth 和 childHeight 是child的宽和高

}

}

尽可能将onMeasure中的一些与Measure无关的操作移动到onLayout中,因为onMeasure在一次自定义控件流程中,可能会执行多次,而onLayout只执行一次.

requestLayout();会触发重新布局onLayout()

onDraw

onDraw决定自定义控件的样子,在onDraw()我们只负责View内容的绘制,

背景系统已经帮我们绘制好了, 这里主要借助的是Canvas这个类.

同时在onDraw方法中,我们一般会使用translate,rotate,scale,skew等来实现canvas的变换

如果使用了变换操作,我们需要使用save()和restore()来保存于恢复canvas的状态

如果是自定义ViewGroup一般我们也不需要管onDraw这个方法,draw由子控件自己完成1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23protected void onDraw(Canvas canvas){

super.onDraw(canvas);

// allocations per draw cycle.

int paddingLeft = getPaddingLeft();

int paddingTop = getPaddingTop();

int paddingRight = getPaddingRight();

int paddingBottom = getPaddingBottom();

int contentWidth = getWidth() - paddingLeft - paddingRight;

int contentHeight = getHeight() - paddingTop - paddingBottom;

// Draw the text.

canvas.drawText(mExampleString, paddingLeft + (contentWidth - mTextWidth) / 2,

paddingTop + (contentHeight + mTextHeight) / 2, mTextPaint);

// Draw the example drawable on top of the text.

if (mExampleDrawable != null) {

mExampleDrawable.setBounds(paddingLeft, paddingTop, paddingLeft + contentWidth,

paddingTop + contentHeight);

mExampleDrawable.draw(canvas);

}

}

postInvalidate();和invalidate();会触发重新绘制onDraw().

onTouchEvent

它是在view中定义的一个方法,用于处理传递到view 的手势事件,

其中涉及到几个常量;MotionEvent.ACTION_DOWN: 按下的时候,做一些初始化,赋值操作.

MotionEvent.ACTION_MOVE: 移动的事件

MotionEvent.ACTION_UP: 手指抬起时,做一些释放资源,重置变量的操作

MotionEvent.ACTION_CANCEL:手势释放操作,释放资源,重置变量

MotionEvent.ACTION_POINTER_DOWN: 多点触控操作,需要借助event.getActionIndex(),getPointerId(actionIndex)等一系列方法

MotionEvent.ACTION_POINTER_UP:多点触控非最后一个点被释放时执行,这里需要注意的是activePointer才会起作用1

2

3

4

5

6

7

8

9

10

11

12private void onSecondaryPointerUp(MotionEvent ev){

//...

final int pointerId = ev.getPointerId(pointerIndex);

if (pointerId == mActivePointerId) {

// This was our active pointer going up. Choose a new

// active pointer and adjust accordingly.

// TODO: Make this decision more intelligent.

final int newPointerIndex = pointerIndex == 0 ? 1 : 0;

//...

mActivePointerId = ev.getPointerId(newPointerIndex);

}

}1

2

3

4

5// 通知父控件不要拦截事件

final ViewParent parent = getParent();

if (parent != null) {

parent.requestDisallowInterceptTouchEvent(true);

}

onInterceptTouchEvent

ViewGroup的方法,表示是否拦截事件,其中传递的参数也是MotionEvent,

同样包含上面那些常量,我们可以在不同时机调用不同的方法来完成逻辑

其他

Configuration: 述设备的配置信息(locale,scaling,..):官网Configuration介绍

ViewConfiguration: 包含了设置UI的超时、大小和距离 de 方法和标准的常量用来,官网ViewConfiguration介绍

VelocityTracker: 触摸速率跟踪 官网介绍Tracking Movement

onSaveInstanceState和onRestoreInstanceState: 存储和恢复自定义控件的状态,参考onSaveInstanceState & onRestoreInstanceState

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值