模拟手指点击滑动事件

一、需求:

下载完apk并安装后,希望能不用人为操作就实现特定位置的点击跟滑动。

这个需求要实现有几种方法,下面讲讲尝试过的使用MotionEvent去模拟用户手指点击跟滑动屏幕事件的实现。

**

二、思路:

**
主要用到的是onTouch常用的4个事件:

1、ACTION_DOWN
表示按下了屏幕,第一个执行也是必然执行的方法。

2、ACTION_MOVE
表示为移动手势,会不断的执行直到触摸停止。

3、ACTION_UP
表示为离开屏幕,触摸停止的时候执行。

4、ACTION_CANCEL
表示取消手势,不会由用户产生,而是由程序产生的。
一个Action_DOWN, 多个ACTION_MOVE, 1个ACTION_UP,就构成了Android中众多的事件。

思路挺简单的:

1.获得事件对象MotionEvent

MotionEvent eventUp = MotionEvent.obtain(System.currentTimeMillis(),
                System.currentTimeMillis() + 100, MotionEvent.ACTION_UP, x, y, 0);

2.分发该事件对象

activity.dispatchTouchEvent(eventUp);

三、代码实现:
封装成工具类如下,传入参数就能直接使用:

/**
 * 模拟点击屏幕、滑动屏幕等操作
 * Created by Jim斌 on 2017/9/9.
 */

public class TouchEvent {
    /**
     * 模仿手指点击控件事件
     * @param view  控件
     * @param x     相对控件的X坐标
     * @param y     相对控件的Y坐标
     */
    private static void simulateClick(View view, float x, float y) {
        long downTime = SystemClock.uptimeMillis();
        final MotionEvent downEvent = MotionEvent.obtain(downTime, downTime,MotionEvent.ACTION_DOWN, x, y, 0);
        downTime += 1000;
        final MotionEvent upEvent = MotionEvent.obtain(downTime, downTime,MotionEvent.ACTION_UP, x, y, 0);
        view.onTouchEvent(downEvent);
        view.onTouchEvent(upEvent);
        downEvent.recycle();
        upEvent.recycle();
    }

    /**
     * 模仿手机点击屏幕事件
     * @param x X坐标
     * @param y Y坐标
     * @param activity 传进去的活动对象
     */
    public static void setFingerClick(int x, int y, Activity activity){
        MotionEvent evenDownt = MotionEvent.obtain(System.currentTimeMillis(),
                System.currentTimeMillis() + 100, MotionEvent.ACTION_DOWN, x, y, 0);
        activity.dispatchTouchEvent(evenDownt);
        MotionEvent eventUp = MotionEvent.obtain(System.currentTimeMillis(),
                System.currentTimeMillis() + 100, MotionEvent.ACTION_UP, x, y, 0);
        activity.dispatchTouchEvent(eventUp);
        evenDownt.recycle();
        eventUp.recycle();
        Log.d(TAG, "setFingerClick: ");
    }

    /**
     * 模拟向下滑动事件
     * @param distance 滑动的距离
     * @param activity 传进去的活动对象
     */
    public static void setMoveToBottom(int distance,Activity activity){
        activity.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                MotionEvent.ACTION_DOWN, 400, 500, 0));
        activity.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                MotionEvent.ACTION_MOVE, 400, 500-distance, 0));
        activity.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                MotionEvent.ACTION_UP, 400, 500-distance, 0));
        Log.d(TAG, "setMoveToBottom: ");
    }

    /**
     * 模拟向上滑动事件
     * @param distance 滑动的距离
     * @param activity 传进去的活动对象
     */
    public static void setMoveToTop(int distance,Activity activity){
        activity.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                MotionEvent.ACTION_DOWN, 400, 500, 0));
        activity.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                MotionEvent.ACTION_MOVE, 400, 500+distance, 0));
        activity.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                MotionEvent.ACTION_UP, 400, 500+distance, 0));
        Log.d(TAG, "setMoveToTop: ");
    }

}

当然,这个方法需要获取到手机屏幕的坐标,下面提供个拿坐标的方法,其实就是弄个自定义view,通过监听触摸事件拿到手指坐标。

1.自定义TextView

/**
 * Created by Jim斌 on 2017/9/9.
 */

public class CustomTextView extends android.support.v7.widget.AppCompatTextView{

    private LogListener mLogListener;

    public CustomTextView(Context context) {
        super(context);
    }

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

    public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setLogListener(LogListener pListener) {
        mLogListener = pListener;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_MOVE:
                float rawX = event.getRawX();
                float rawY = event.getRawY();
                float x = event.getX();
                float y = event.getY();

                if (mLogListener != null) {
                    mLogListener.output("rawX = " + rawX
                            + "\n rawY = " + rawY
                            + "\n x = " + x
                            + "\n Y = " + y);
                }
                break;
        }
        return true;
    }
    /**
     *  用于在Actvity中实时Touch位置输出信息
     */
    public interface LogListener {
        public void output(String pOutput);
    }

}

2.在Activity初始化这个view,设置监听:

CustomTextView customTextView = (CustomTextView) findViewById(R.id.custom_textview);
customTextView.setLogListener((CustomTextView.LogListener) new CustomLogListener());

3.监听到变化时把坐标显示在textview上

/**
 * 用于获取TouchEvent中位置信息
 */
private class CustomLogListener implements CustomTextView.LogListener {
    @Override
    public void output(String pOutput) {
        tv.setText(pOutput);
    }

}

4.然后把自定义view设置到布局文件上。

<com.example.jim.motionevent.CustomTextView
    android:id="@+id/custom_textview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center_horizontal"
    android:background="#666666"/>

**

四、总结:

**

这里遇到了一个**

**,我想把事件组合起来,比如点击完按钮后等待几秒,再去滑动屏幕。刚开始的时候我使用的是Thread.sleep()方法,调用完点击方法后sleep几秒、再调用滑动方法。
然而出来的效果并不是我想要的,展示出来的效果是先sleep后点击跟滑动的效果同时出现。猜想着可能受事件的分发机制影响,查了一阵子查不到原因后,决定先放一边以后再了解,有明白这个原因的大佬方便的话可以交流一下。后来我就使用java的定时器,间隔几秒去执行某个功能操作,这样出来效果就符合要求了。

然而… 我发现这个做出来后只能在demo里面实现模拟点击、模拟滑动操作,就是说,当另一个程序获得焦点,而我们在本程序跑模拟点击的逻辑时,模拟点击的代码还是有实现的,只不过它不会点到另一个程序当前占据屏幕的页面,而是在它自己的程序页面去模拟点击。所以其实并不符合我的需求,解决方案可能是找找看能不能获取到其他程序的活动对象(感觉不是很可行),或者考虑使用辅助功能(AccessibilityService)去实现。

五、资料来源:

http://blog.sina.com.cn/s/blog_7256fe8f01016tyz.html
http://www.android-doc.com/guide/components/android7.0.html?q=AlarmManager#q=AlarmManager

你可能感兴趣的:(android)