Android手掌抑制功能的实现

        最近需要实现一个功能,在Activity中有一个手写区域,为了更好的用户体验,需要满足即使整个手掌放在屏幕上时(android平板,屏幕比较大)也只响应手写区域内的操作,即在支持多点触控的情况下,只响应指定的区域,我将这个功能称作“手掌抑制”,即在手写时,手掌放在屏幕上面不做任何响应。

        初看这个功能很简单,按照之前处理listview、gridview里面的子view不能响应的方式,只要在activity层不拦截向手写view传递的消息即可实现想要的效果,但经过实际测试和对android消息机制的详细研究发现,要实现这个功能会有点小复杂。

 

一、android的消息传递机制:

1、基础知识:

        (1) 所有Touch事件都被封装成了MotionEvent对象,包括Touch的位置、时间、历史记录以及第几个手指(多指触摸)等。

        (2) 事件类型分为ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每个事件都是以ACTION_DOWN开始ACTION_UP结束。

        (3) 对事件的处理包括三类:

        传递——dispatchTouchEvent()

        拦截——onInterceptTouchEvent()

        消费——onTouchEvent()和OnTouchListener

 

2、传递流程

        (1) 事件从Activity.dispatchTouchEvent()开始传递,只要没有被停止或拦截,从最上层的View(ViewGroup)开始一直往下(子View)传递。子View可以通过onTouchEvent()对事件进行处理。

        (2) 事件由父View(ViewGroup)传递给子View,ViewGroup可以通过onInterceptTouchEvent()对事件做拦截,停止其往下传递。

        (3) 如果事件从上往下传递过程中一直没有被停止,且最底层子View没有消费事件,事件会反向往上传递,这时父View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到Activity的onTouchEvent()函数。

        (4) 如果View没有对ACTION_DOWN进行消费,之后的其他事件不会传递过来。

        (5) OnTouchListener优先于onTouchEvent()对事件进行消费。

        上面的消费即表示相应函数返回值为true。

 

3、实际情况:

        能够响应事件处理方法的控件包括:ViewGroup、View、Activity,各类控件对三个事件响应处理方法的支持情况如下:

 

         这三个控件,Activity是处于最外层的,消息的传递首先是系统回调消息给Activity,Activity将消息传递给每一个ViewGroup,然后ViewGroup会将消息传递给相应地子View。

        本文所描述的手写控件是一个view,在有系统消息回调时只有上层控件将消息分发下来,它才能够消费和处理这些消息。

 

二、问题现象:

        接着我们进入正题,按照我在开篇介绍的那种处理方式,写一个手写view,在Activity和ViewGroup(自定义一个Layout即可)层将消息分发给该view,目前的代码看上去是这样子的:

 

public class DrawView extends View {
	public DrawView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initPaintView( );
	}

	public DrawView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initPaintView( );
	}

	public DrawView(Context context) {
		super(context);
		initPaintView( );
	}
	
	public void clear() {  
        if (null != mPath) {  
            mPath.reset();  
            invalidate();  
        }  
    }  
  
    private void initPaintView() {  
        mPaint.setAntiAlias(true);  
        mPaint.setColor(Color.WHITE);  
        mPaint.setStyle(Paint.Style.STROKE);  
        mPaint.setStrokeJoin(Paint.Join.ROUND);  
        mPaint.setStrokeWidth(5f);  
    }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    	super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    	mViewWidth = MeasureSpec.getSize(widthMeasureSpec);   //获取ViewGroup宽度    
    	mViewHeight = MeasureSpec.getSize(heightMeasureSpec);  //获取ViewGroup高度
    }
  
    @Override  
    protected void onDraw(Canvas canvas) {  
        canvas.drawPath(mPath, mPaint);  
    }  
    
    public boolean inArea( float x, float y ){
    	return ( x >= 0 && x <= mViewWidth && y >= 0 && y <= mViewHeight)?true:false;
    }
  
	@Override  
    public boolean onTouchEvent(MotionEvent event) {
    	float eventX = event.getX( );  
        float eventY = event.getY( );
    	
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {  
            mPath.moveTo(eventX, eventY);
            mLastTouchX = eventX;  
            mLastTouchY = eventY;
            invalidate( );
        }  
            return true;  
        case MotionEvent.ACTION_MOVE:{
        	drawView( event, eventX, eventY );
        }
        break;
        case MotionEvent.ACTION_UP:{  
        	drawView( event, eventX, eventY );
        }  
            break;  
        default:  
            return false;  
        }  
  
        return true;  
    }
    
    private void drawView( MotionEvent event, float eventX, float eventY ){
    	resetDirtyRect(eventX, eventY);  
        int historySize = event.getHistorySize();  
        for (int i = 0; i < historySize; i++) {  
            float historicalX = event.getHistoricalX(i);  
            float historicalY = event.getHistoricalY(i);  
            getDirtyRect(historicalX, historicalY);  
            mPath.lineTo(historicalX, historicalY);  
        }  

        mPath.lineTo(eventX, eventY);  
        invalidate((int) (mDirtyRect.left - HALF_STROKE_WIDTH), 
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值