网上的文章很少,我感觉这个东西搞得好也是完全可以和adb 的触摸媲美的。
目前我已经用这个做了键盘自动输入验证码各种页面自动填表。
要点击子view,使用dispatchTouchEvent
如果只需要点击当前,而且能找到当前view,则直接调用此view的onTouchEvent方法。
点击屏幕中的某个view通过父view方式
View decorView = mainActivity.getWindow().getDecorView();
int[] outlocation = new int[2];
btn_btn1.getLocationInWindow(outlocation);
int y = outlocation[1];
final long downTime = SystemClock.uptimeMillis();
Log.w(TAG, "按下时间:");
int rawX=outlocation[0];
int rawY=outlocation[1];
rawY=rawY+10;
int finalRawY = rawY;
int width = decorView.getWidth();
MotionEvent obtain = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, rawX, rawY, 0);
decorView.dispatchTouchEvent(obtain);
decorView.postDelayed(new Runnable() {
@Override
public void run() {
final long upTime = SystemClock.uptimeMillis();
MotionEvent obtainUp = MotionEvent.obtain(upTime, upTime, MotionEvent.ACTION_MOVE, width, finalRawY, 0);
decorView.dispatchTouchEvent(obtainUp);
Log.w(TAG, "长按完成,模拟抬起事件");
}
}, 2000);
decorView.postDelayed(new Runnable() {
@Override
public void run() {
final long upTime = SystemClock.uptimeMillis();
MotionEvent obtainUp = MotionEvent.obtain(upTime, upTime, MotionEvent.ACTION_UP, width, finalRawY, 0);
decorView.dispatchTouchEvent(obtainUp);
Log.w(TAG, "长按完成,模拟抬起事件");
}
}, 6000);
Log.w(TAG, "Y:" + y + ",screenHeight:" + decorView.getHeight() + "");
}
},1200);
测试触摸效果的代码。
package cn.qssq666.main;
import android.os.SystemClock;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import java.util.Random;
/**
* Created by qssq on 2018/4/5 [email protected]
*/
public class UiClickUtil {
private static final String TAG = "UiClickUtil";
public static void clickView(View paramX) {
performViewOnTouchEvent(paramX, 0);
}
public static void longPressView(View paramX) {
longPressView(paramX, 2 * 1000);
}
/**
* @param paramX
* @param actionUpTime 长按时间
*/
public static void longPressView(View paramX, int actionUpTime) {
performViewOnTouchEvent(paramX, actionUpTime);
}
public static void performViewOnTouchEvent(View paramX, int actionUpTime) {
int[] actualRawX = getActualRawX(paramX);
performViewOnTouchEvent(paramX, actualRawX[0], actualRawX[1], actionUpTime);
}
public static void performViewOnTouchEvent(View view, final int rawX, final int rawY, int actionUpTime) {
final long downTime = SystemClock.uptimeMillis();
Log.w(TAG, "按下时间:");
MotionEvent obtain = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, rawX, rawY, 0);
view.onTouchEvent(obtain);
view.postDelayed(new Runnable() {
@Override
public void run() {
final long upTime = SystemClock.uptimeMillis();
MotionEvent obtainUp = MotionEvent.obtain(upTime, upTime, MotionEvent.ACTION_UP, rawX, rawY, 0);
view.onTouchEvent(obtainUp);
Log.w(TAG, "长按完成,模拟抬起事件");
}
}, actionUpTime);
}
public static void performClickChildView(View view, final int rawX, final int rawY, int actionUpTime) {
final long downTime = SystemClock.uptimeMillis();
Log.w(TAG, "按下时间:");
MotionEvent obtain = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, rawX, rawY, 0);
view.dispatchTouchEvent(obtain);
view.postDelayed(new Runnable() {
@Override
public void run() {
final long upTime = SystemClock.uptimeMillis();
MotionEvent obtainUp = MotionEvent.obtain(upTime, upTime, MotionEvent.ACTION_UP, rawX, rawY, 0);
view.dispatchTouchEvent(obtainUp);
Log.w(TAG, "长按完成,模拟抬起事件");
}
}, actionUpTime);
}
public static int[] getActualRawX(View view) {
int[] location = new int[2];
view.getLocationOnScreen(location);
location[0] = location[0] + new Random().nextInt(view.getWidth());
location[1] = location[1] + new Random().nextInt(view.getHeight());
return location;
}
public static void performUpEvent(View paramX) {
int[] actualRawX = getActualRawX(paramX);
performUpEvent(paramX, actualRawX[0], actualRawX[1]);
}
public static void performUpEvent(View paramX, int rawX, int rawY) {
MotionEvent obtain = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis() + 5000, MotionEvent.ACTION_UP, rawX, rawY, 0);
paramX.onTouchEvent(obtain);
}
public static void performMoveEvent(View paramX) {
int[] actualRawX = getActualRawX(paramX);
performMoveEvent(paramX, actualRawX[0], actualRawX[1]);
}
public static void performMoveEvent(View paramX, int rawX, int rawY) {
MotionEvent obtain = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis() + 5000, MotionEvent.ACTION_MOVE, rawX, rawY, 0);
paramX.onTouchEvent(obtain);
}
}
package cn.qssq666.ui;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
import android.view.View;
public class MyView extends SurfaceView implements Callback, View.OnTouchListener {
private static final String TAG = "MyView";
private Paint p = new Paint();
private Path path = new Path();
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
p.setColor(Color.RED);
p.setTextSize(10);
p.setAntiAlias(true);
p.setStyle(Paint.Style.STROKE);
setOnTouchListener(this);
}
public void draw() {
Canvas canvas = getHolder().lockCanvas();
canvas.drawColor(Color.WHITE);
canvas.drawPath(path, p);
getHolder().unlockCanvasAndPost(canvas);
}
public void clear() {
path.reset();
draw();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
draw();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(event.getX(), event.getY());
draw();
break;
case MotionEvent.ACTION_MOVE:
path.lineTo(event.getX(), event.getY());
Log.w(TAG,"屏幕Y"+event.getRawY());
draw();
break;
}
return true;
}
}
getRawY
配合getLocationInWindow()
因此父view点击子view,用这两个进行测试才比较合理,精准。
getY是相对于view自身空间,
一个某自定义绘制的abcd索引view点击第一个条目,忽略标题高度,经过计算标题高度17dp 所以加上17+第一个条目的高度减去一半就点了第一个条目中间
try {
int rl_content = ResourcesUtil.getId(decorView.getContext(), "rl_content");
ViewGroup currentView = (ViewGroup) decorView.findViewById(rl_content);
if (currentView == null || currentView.getChildCount() == 0) {
ToastUtils.showToast("无法完成银行自动选择,请手动选择");
Commons.finishAndclearFirstTask();
} else {
}
int[] outlocation = new int[2];
currentView.getLocationInWindow(outlocation);
int y = outlocation[1] +AppUtil.dip2px(AppContext.getInstance(), 20);//这里的30是为了找到这个容器往下面一点点击一个item.
int x=outlocation[0];
UiClickUtil.performClickChildView(decorView, x+currentView.getWidth()/2, y, 2000);
// UiClickUtil.performClickChildView(decorView, x+currentView.getWidth()/2, 455, 2000);
// View view = viewGroup.getChildAt(0);
// view.callOnClick();
Log.w(TAG, "getRawY:" + y + ",screenHeight:" + decorView.getHeight() + "rawx:"+x+",rawY:"+outlocation[1]);
ToastUtils.showToast("已点击完成");
} catch (Throwable e) {
Log.w(TAG, "ERROR", e);
}