1.基础
- 掌握View体系事件分发与处理,参考Android自定义View(9):事件分发&处理
- 掌握基础的手势监听及手势动作有关的回调时机,参考Android自定义View(10):手势监听&处理
- 了解GestureLibrary和GestureOverlayView的api使用,参考官方API文档
2.绘制
绘制简述:
(具体用法及要点见代码注释)
1.首先在布局文件中添加GestureOverlayView控件;
2.然后在代码中获取控件对象;
3.初始化绘制画笔;
4.设置监听;
5.若关联activity,则在onDestroy()解除。
2.1 xml代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.gesture.GestureOverlayView
android:id="@+id/gesture_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:gravity="center"
android:layout_height="match_parent">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</android.gesture.GestureOverlayView>
</RelativeLayout>
2.2 activity代码
package com.cupster.android_x_frame;
import android.gesture.Gesture;
import android.gesture.GestureOverlayView;
import android.graphics.Color;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class DrawGestureActivity extends AppCompatActivity implements GestureOverlayView.OnGesturePerformedListener, GestureOverlayView.OnGesturingListener {
GestureOverlayView mGestureOverlayView;
TextView mTvHint;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_draw_gesture);
mGestureOverlayView = findViewById(R.id.gesture_overlay);
mTvHint = findViewById(R.id.text);
mGestureOverlayView.setFadeOffset(800);//默认420ms,设置为800ms
mGestureOverlayView.setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);//默认单指连续绘制,设置为多指绘制
mGestureOverlayView.setGestureStrokeWidth(10);//绘制线宽
mGestureOverlayView.setGestureColor(Color.parseColor("#3ca1f9"));//绘制颜色
mGestureOverlayView.setUncertainGestureColor(Color.parseColor("#a7dbf7"));//渐成色
//设置监听
mGestureOverlayView.addOnGesturePerformedListener(this);
mGestureOverlayView.addOnGesturingListener(this);
}
@Override
protected void onDestroy() {
mGestureOverlayView.removeOnGesturePerformedListener(this);
mGestureOverlayView.removeOnGesturingListener(this);
super.onDestroy();
}
//==============================================
//=========GesturePerformedListener=============
//==============================================
@Override
public void onGesturePerformed(GestureOverlayView gestureOverlayView, Gesture gesture) {
mTvHint.append("\n");
mTvHint.append("--> 所有绘制路径,识别完成");
}
//===============================================
//=========GesturingListener=====================
//===============================================
@Override
public void onGesturingStarted(GestureOverlayView gestureOverlayView) {
mTvHint.append("\n");
mTvHint.append("--> 单笔手势绘制开始");
}
@Override
public void onGesturingEnded(GestureOverlayView gestureOverlayView) {
mTvHint.append("\n");
mTvHint.append("--> 单笔手势绘制结束");
}
}
2.3 源码简析
2.3.1 结论
- GestureOverlayView继承FrameLayout,FrameLayout继承ViewGroup(继承View);
- GestureOverlayView重写View的dispatchTouchEvent方法
- GestureOverlayView.setEnabled()默认设置为true,即夺取事件分发;
- GestureOverlayView.setEnabled(false)时,可视为FrameLayout,即不响应手势绘制;
验证代码:
//测试禁用,mGestureOverlayView默认启用绘制==读取手势事件
mGestureOverlayView.setEnabled(false);
mTvHint.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mTvHint.append("\n");
mTvHint.append("绘制未启用,事件正常分发");
return true;
}
});
2.3.2 源码
解析 见代码注释
public class GestureOverlayView extends FrameLayout {
...
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (isEnabled()) {
final boolean cancelDispatch = (mIsGesturing || (mCurrentGesture != null &&
mCurrentGesture.getStrokesCount() > 0 && mPreviousWasGesturing)) &&
mInterceptEvents;
processEvent(event);//即夺取事件分发
if (cancelDispatch) {
event.setAction(MotionEvent.ACTION_CANCEL);
}
super.dispatchTouchEvent(event);
return true;//回复上级已处理事件,不下发
}
//isEnabled== false ,可视为FrameLayout,正常分发事件
return super.dispatchTouchEvent(event);
}
...
}
...
private boolean processEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchDown(event);//这里回调onGestureStarted
invalidate();
return true;
case MotionEvent.ACTION_MOVE:
if (mIsListeningForGestures) {
Rect rect = touchMove(event);//这里回调onGesture
if (rect != null) {
invalidate(rect);
}
return true;
}
break;
case MotionEvent.ACTION_UP:
if (mIsListeningForGestures) {
touchUp(event, false);//回调onGestureEnded
invalidate();
return true;
}
break;
case MotionEvent.ACTION_CANCEL:
if (mIsListeningForGestures) {
touchUp(event, true);//标志位true,代表取消,清除绘制的手势
invalidate();
return true;
}
}
return false;
}
...
...
/**
* 每次执行完touchDown、touchMove方法后都会调用invalidate()、invalidate(rect)刷新手势
*/
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
if (mCurrentGesture != null && mGestureVisible) {
canvas.drawPath(mPath, mGesturePaint);
}
}
...