怎么在这个类中用onTouchEvent的MotionEvent.ACTION_DOWN实现线程的暂停

本文介绍了一个基于Android平台的游戏视图(GameView)类的设计与实现。该类通过SurfaceView进行屏幕绘制,支持基本的游戏循环逻辑,包括每秒60帧的刷新率控制,并实现了触摸事件的处理。此外,还提供了回调钩子(callback hook)机制以便于扩展。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package edu.qypt.zzh;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public abstract class GameView extends SurfaceView implements Callback,
Runnable {

private static final MotionEvent MotionEvent = null;

protected int refreshTime = 1000 / 60;

private boolean isRunning = false;

protected SurfaceHolder holder;

protected Paint paint;

protected int screenWidth;

protected int screenHeight;

protected CallbackHook callbackHook;
protected boolean su=true;
protected int n=0;

public GameView(Context context) {
super(context);
holder = this.getHolder();
holder.addCallback(this);
paint = new Paint();
paint.setColor(Color.WHITE);
setFocusable(true);
setKeepScreenOn(true);
}


@Override
public void run() {
while (isRunning) {
if(su==true){
long start = System.currentTimeMillis();
play();
draw();
long end = System.currentTimeMillis();
try {
if (end - start < refreshTime) {
Thread.sleep(refreshTime - (end - start));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
        }
}

public void addCallbackHook(CallbackHook callbackHook) {
this.callbackHook = callbackHook;
}

@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format,
int width, int height) {
}

@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
this.screenWidth = this.getWidth();
this.screenHeight = this.getHeight();
if (callbackHook != null) {
callbackHook.onSurfaceCreated(surfaceHolder);
}
new Thread(this).start();
isRunning = true;
}

@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
isRunning = false;
}

protected void draw() {
Canvas canvas = null;

try {
canvas = holder.lockCanvas();
if (canvas != null) {
canvas.drawRGB(0, 0, 0);
doDraw(canvas);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
}

protected void doDraw(Canvas canvas) {
}

protected abstract void play();
}

<think>我们正在讨论Android中的MotionEvent事件,特别是ACTION_UP和ACTION_CANCEL的区别。 根据引用[1]和引用[2],我们知道ACTION_CANCEL是一个容易被忽略的事件型。而引用[3]则提供了一个生动的例子说明ACTION_CANCEL的发生场景。 首先,回顾一下常见的MotionEvent事件: - ACTION_DOWN: 手指按下 - ACTION_MOVE: 手指移动 - ACTION_UP: 手指抬起 那么ACTION_CANCEL是什么? 根据引用[1]和引用[2]:ACTION_CANCEL发生在当父视图拦截了原本由子视图处理的事件流时。也就是说,当事件序列(从DOWN开始)被中断,并且这个中断是由于父视图的干预(例如,父视图的onInterceptTouchEvent返回true)时,子视图会收到一个ACTION_CANCEL事件,而不是ACTION_UP。 引用[3]中的例子:子控件收到了ACTION_DOWN事件,然后父控件拦截了后续事件(比如MOVE和UP),那么子控件就会收到一个ACTION_CANCEL事件,而不是ACTION_UP。这样,子控件就知道这个事件序列已经被父控件接管,自己应该取消之前由ACTION_DOWN触发的一些状态(比如高亮、拖动等)。 因此,区别如下: 1. **触发时机不同**: - `ACTION_UP`:在用户正常抬起手指时触发,表示一个完整的手势结束(从DOWN到UP)。 - `ACTION_CANCEL`:在事件序列被父视图中断时触发,表示手势被取消,不会继续。 2. **触发原因不同**: - `ACTION_UP`:是正常结束手势。 - `ACTION_CANCEL`:是非正常结束,通常是因为父视图的拦截。 3. **处理逻辑不同**: - 在`onTouchEvent`中,当收到`ACTION_UP`时,我们通常会执行手势完成的逻辑(例如,确认点击、完成滑动等)。 - 当收到`ACTION_CANCEL`时,我们应该执行清理工作,将视图状态恢复到手势开始前的样子(例如,取消高亮、停止动画等),因为手势已经被取消。 4. **事件序列的完整性**: - 一个完整的事件序列应该是:DOWN -> [MOVE]* -> UP。 - 当发生拦截时,事件序列变为:DOWN -> [MOVE]* -> CANCEL(注意,这里没有UP)。 为什么要有ACTION_CANCEL? 如果没有ACTION_CANCEL,那么子视图在父视图拦截事件后,可能还保持着手势开始时的状态(比如按钮保持按下状态),这显然是不合理的。因此,ACTION_CANCEL的作用就是通知子视图:“你之前处理的事件序列已经被取消了,请恢复原状”。 举个例子: 假设有一个按钮(Button),当按下时按钮会变为按下状态(背景变暗)。如果用户按下按钮,然后手指滑出按钮区域,按钮会收到ACTION_CANCEL,然后按钮就会恢复到正常状态。如果用户按下按钮并在按钮区域内抬起,就会收到ACTION_UP,然后触发点击事件。 但是,如果按钮在父布局中,而父布局在用户按下按钮后决定拦截事件(例如,因为检测到滑动),那么按钮就会收到ACTION_CANCEL,而不是ACTION_UP,这样按钮就会恢复到正常状态,而不会触发点击事件。 总结: | 事件型 | 触发场景 | 处理建议 | |----------------|----------------------------------|----------------------------------| | ACTION_UP | 用户正常抬起手指 | 执行手势完成逻辑(如点击、滑动结束) | | ACTION_CANCEL | 事件被父视图拦截 | 恢复视图状态,取消所有由手势引起的临时变化 | 注意:在自定义View处理触摸事件时,一定要正确处理ACTION_CANCEL,否则可能导致视图状态错误。 相关问题: 1. 在自定义View时,如何处理ACTION_CANCEL事件? 2. 如何避免父视图意外拦截事件导致子视图收到ACTION_CANCEL? 3. 在RecyclerView中嵌套SeekBar时,如何避免ACTION_CANCEL? 4. 除了父视图拦截,还有哪些情况会触发ACTION_CANCEL?</think>在Android触摸事件处理中,`MotionEvent.ACTION_UP`和`MotionEvent.ACTION_CANCEL`都是手势结束的标志,但它们的触发场景和语义含义有本质区别: --- ### **核心区别** | **特性** | `ACTION_UP` | `ACTION_CANCEL` | |------------------------|--------------------------------------|--------------------------------------| | **触发条件** | 用户主动抬起手指 | 系统强制中断事件序列 | | **事件序列完整性** | 完整序列:`DOWN → MOVE* → UP` | 中断序列:`DOWN → MOVE* → CANCEL` | | **语义含义** | 正常完成手势操作 | 手势被外部因素强制取消 | | **典型场景** | 点击/滑动后自然抬手 | 父容器拦截、窗口失去焦点、系统事件打断 | | **子视图处理逻辑** | 执行手势完成逻辑(如提交操作) | 恢复初始状态(如取消高亮/动画) | --- ### **详细解析** #### 1. **触发机制差异** - **`ACTION_UP`** 当用户**主动抬起手指**时触发,表示一个完整手势的正常结束。例如: ```java public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: // 正常结束逻辑(如提交滑动结果) return true; } } ``` - **`ACTION_CANCEL`** 当**外部因素强制中断事件流**时由系统自动触发,常见场景包括: - 父容器通过`onInterceptTouchEvent()`拦截事件(引用[3]) - 窗口失去焦点(如来电、弹窗) - 系统级事件(如屏幕旋转) - 触摸超出视图边界且被其他组件接管 ```java public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_CANCEL: // 恢复初始状态(如重置SeekBar滑块位置) return true; } } ``` --- #### 2. **事件序列对比** - **正常序列**(以点击按钮为例): `ACTION_DOWNACTION_UP` → 触发`onClick()`回调 - **取消序列**(以父容器拦截为例): `ACTION_DOWN(父容器拦截)ACTION_CANCEL` → 按钮需在`ACTION_CANCEL`中取消按压状态(引用[2]) --- #### 3. **实际场景示例** 1. **嵌套滚动冲突**(引用[3]) - 子视图(如SeekBar)收到`ACTION_DOWN` - 用户滑动时,父容器(如RecyclerView)判定为垂直滚动并拦截事件 - **结果**:SeekBar收到`ACTION_CANCEL`而非`ACTION_UP` 2. **窗口焦点丢失** - 用户按下按钮时突然弹出系统对话框 - **结果**:按钮收到`ACTION_CANCEL`,避免误触发点击逻辑 --- ### **开发建议** 1. **必须同时处理两种事件** 在`onTouchEvent()`中需同时处理`ACTION_UP`和`ACTION_CANCEL`,确保状态一致性: ```java case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: resetViewState(); // 重置视图状态 break; ``` 2. **避免状态残留** 在`ACTION_CANCEL`中需撤销所有由手势引发的临时变更(如高亮、进度缓存),防止UI状态错误(引用[1])。 3. **解决事件冲突** 若子视图需独占事件(如SeekBar),可在`ACTION_DOWN`时调用: ```java parent.requestDisallowInterceptTouchEvent(true); // 阻止父容器拦截 ``` --- ### **总结** | **维度** | `ACTION_UP` | `ACTION_CANCEL` | |----------------|--------------------------------------|--------------------------------| | **用户意图** | 主动完成操作 | 操作被外力打断 | | **开发者响应** | 提交结果(如保存进度) | 回滚状态(如重置UI) | | **关键原则** | "用户想结束" | "系统不让继续" | 正确处理二者差异可避免诸如"SeekBar滑动卡顿后进度回跳"、"按钮按压状态残留"等问题(引用[1][3])。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值