1. 自动点击
1.1. 调用View方法
直接调用view.performClick()
即可实现单击;调用view.performLongClick()
即可实现长按。
但是对一些复杂的操作,View自带的方法可能不够用了,就需要用到第二种方法
1.2. 使用MotionEvent设置触摸事件
可以通过设置MotionEvent对象的参数,再通过View的dispatchTouchEvent
分发点击事件,完成一些复杂的触摸操作。
MotionEvent.obtain()
参数说明:
参数 | 说明 |
---|---|
downTime | 触发当前触摸事件的手指第一次按下的时间,从手指接触屏幕到手指离开屏幕的时间内,该手指产生的所有触摸事件,其downTime都不会发生改变 |
eventTime | 当前触摸事件产生的时间。如果是第一次按下,则该时间与getDownTime相同 |
action | 事件类型。如MotionEvent.ACTION_DOWN、MotionEvent.ACTION_MOVE、MotionEvent.ACTION_UP |
x | 事件的x坐标 |
y | 事件的y坐标 |
说明:
downTime、eventTime这两个参数并不控制事件的触发时间,推测是用于处理触摸事件时获取一些数据,比如从按下到当前触摸事件的时间间隔。虽然注释说这两个都需要通过
SystemClock.uptimeMillis()
获取,但实测发现,设置任意值都可以触发touch事件。如果只是要实现点击,x、y设置任意值都可以,只要用对应的view去调用
dispatchTouchEvent
即可。
2. 延迟点击
我们希望实现的效果是:在延迟自动点击前,可以响应用户操作,延时时间到了以后,自动完成点击事件。
第一时间想到的是启动一个子线程,在子线程中sleep一段时间,然后进行点击,但是会有各种问题,详情如下:
2.1. TimerTask
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
button.performClick();
}
}, 3000L);
这种方法在delayMillis结束之前可以交互,但delayMillis结束之后自动点击会抛出异常:
- 若使用
button.performClick();
,则报错android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
; - 若使用MotionEvent,则报错
android.util.AndroidRuntimeException: Animators may only be run on Looper threads
。
2.2. new Handler(Looper.getMainLooper()).post()
new Handler(Looper.getMainLooper()).post(() -> {
try {
Thread.sleep(3000L);
} catch (InterruptedException exception) {
throw new RuntimeException(exception);
}
button.performClick();
});
这种方法在delayMillis结束之前不可以交互,点击事件被累积,delayMillis结束之后自动点击正常,并响应之前积压的点击事件。
2.3. new Handler(Looper.getMainLooper()).postDelayed()
new Handler(Looper.getMainLooper()).postDelayed(() -> {
button.performClick();
}, 3000L);
这种方法在delayMillis结束之前可以交互,delayMillis结束之后自动点击正常,满足需求。
3. 完整示例
布局文件activity_auto_click.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center">
<Button
android:id="@+id/auto_click_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/white"
android:text="-" />
</LinearLayout>
</LinearLayout>
activity类:
package org.tao.hetools.activities;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import androidx.activity.ComponentActivity;
import androidx.annotation.Nullable;
import org.tao.hetools.R;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class AutoClickActivity extends ComponentActivity {
private int index = 0;
private Button button;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_auto_click);
button = findViewById(R.id.auto_click_button);
button.setText(String.valueOf(index));
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
button.setOnClickListener(view -> {
Log.i("AutoClick", "===>click once" + simpleDateFormat.format(new Date()));
button.setText(String.valueOf(++index));
});
button.setOnLongClickListener(view -> {
Log.i("AutoClick", "===>long click once" + simpleDateFormat.format(new Date()));
int backgroundColor = ((ColorDrawable) button.getBackground()).getColor();
button.setBackgroundColor(backgroundColor == Color.WHITE ? Color.BLUE : Color.WHITE);
return true;
});
new Handler(Looper.getMainLooper()).postDelayed(() -> {
// button.performClick(); // 单击
// button.performLongClick(); // 长按
clickOnce(button);
}, 3000L);
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
button.performClick();
}
}, 3000L);
}
public void clickOnce(View view) {
int x = view.getWidth() / 2;
int y = view.getHeight() / 2;
long downTime = SystemClock.uptimeMillis();
// 按下手指
long actionDown = downTime;
MotionEvent event = MotionEvent.obtain(downTime, actionDown, MotionEvent.ACTION_DOWN, x, y, 0);
view.dispatchTouchEvent(event);
// 抬起手指
long actionUp = downTime + 500;
event = MotionEvent.obtain(downTime, actionUp, MotionEvent.ACTION_UP, x, y, 0);
view.dispatchTouchEvent(event);
event.recycle();
}
}