美文网首页手机移动程序开发Android开发Android技术知识
Android自定义控件辅助利器之EventParser

Android自定义控件辅助利器之EventParser

作者: e4e52c116681 | 来源:发表于2018-11-15 10:59 被阅读33次

    零、前言

    自定义View经常和事件打交道,不过那个event对象用着感觉挺麻烦
    打算自己写一个事件的解析类来辅助事件的分析,功能包括:
    1.点击监听:回调-->传出落点(类型PointF)
    2.抬起监听:回调-->手指抬起点(类型PointF)、移动方向(类型Orientation,八个)
    3.移动监听:回调-->速度(double) y位移(float) x位移(float) 角度(double)、移动方向
    4.是否移动、是否按下的判断--------源码比较简单,我注释也很清楚,都贴在文尾,自行cv。

    测试效果:

    1.方向测试

    方向测试.gif

    2.角度、位移测试

    角度、位移测试.gif

    3.速度解析

    速度解析.gif

    一、使用:

    1.view初始化时初始化EventParser并为EventParser设置监听器
    2.在onTouchEvent里为mEventParser设置解析对象(不止是view,在Activity中也可以用,只有有event)

    public class EventView extends View {
        private EventParser mEventParser;
        public EventView(Context context) {
            this(context, null);
        }
        public EventView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init();
        }
        private void init() {
            mEventParser = new EventParser();//初始化EventParser
            //为EventParser设置监听器
            mEventParser.setOnEventListener(new OnEventListener() {
                @Override
                public void down(PointF pointF) {
                }
                @Override
                public void up(PointF pointF, Orientation orientation) {
                }
                @Override
                public void move(double v, float dy, float dx, double dir, Orientation orientation) {
                }
            });
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            mEventParser.parseEvent(event);//设置解析对象
            return true;
        }
    }
    

    这样所有的这些事件参数就是你的了。
    当然也提供了适配器,只想用一个回调方法的,不需要直接实现接口,你可以:

    mEventParser.setOnEventListener(new OnEventAdapter(){
        @Override
        public void move(double v, float dy, float dx, double dir, Orientation orientation) {
        }
    });
    

    二、代码实现

    1.解析器主类:EventParser
    /**
     * 作者:张风捷特烈<br/>
     * 时间:2018/11/6 0006:20:22<br/>
     * 邮箱:1981462002@qq.com<br/>
     * 说明:事件解析器
     */
    public class EventParser {
        private OnEventListener onEventListener;
        private Orientation mOrientation = Orientation.NO;
    
        private PointF mTagPos;//按下坐标点
        //移动时坐标点---在此创建对象,避免在move中创建大量对象
        private PointF mMovingPos = new PointF(0, 0);
    
        private float detaY = 0;//下移总量
        private float detaX = 0;//右移总量
    
        private boolean isDown = false;//是否按下
        private boolean isMove = false;//是否移动
    
        private PointF mDownPos;//记录按下时点
        private long lastTimestamp = 0L;//最后一次的时间戳
    
        public void setOnEventListener(OnEventListener onEventListener) {
            this.onEventListener = onEventListener;
        }
    
        /**
         * 添加自己的事件解析
         *
         * @param event 事件
         */
        public void parseEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    isDown = true;
                    //按下---为p0赋值
                    mTagPos = new PointF(event.getX(), event.getY());
                    mDownPos = mTagPos;
                    lastTimestamp = System.currentTimeMillis();
                    if (onEventListener != null) {
                        onEventListener.down(mTagPos);
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    //移动的那刻的坐标(移动中,不断更新)
                    mMovingPos.x = event.getX();
                    mMovingPos.y = event.getY();
                    //处理速度
                    detaX = mMovingPos.x - mDownPos.x;
                    detaY = mMovingPos.y - mDownPos.y;
                    //下移单量
                    float dx = mMovingPos.x - mTagPos.x;
                    //右移单量
                    float dy = mMovingPos.y - mTagPos.y;
                    double ds = Math.sqrt(dx * dx + dy * dy);//偏移位移单量
                    double dir = deg((float) Math.acos(detaX / ds));//角度
    
                    long curTimestamp = System.currentTimeMillis();
                    long dt = curTimestamp - lastTimestamp;
                    //由于速度是C*px/ms
                    double v = ds / dt * 100;
                    orientationHandler(dir);//处理方向
                    if (onEventListener != null) {
                        onEventListener.move(v, detaY, detaX, detaY < 0 ? dir : -dir, mOrientation);
                    }
                    if (Math.abs(detaY) > 50 / 3.0) {
                        isMove = true;
                    }
                    mTagPos.x = mMovingPos.x;//更新位置
                    mTagPos.y = mMovingPos.y;//更新位置----注意这里不能让两个对象相等
                    lastTimestamp = curTimestamp;//更新时间
                    break;
                case MotionEvent.ACTION_UP:
                    if (onEventListener != null) {
                        onEventListener.up(mTagPos, mOrientation);
                    }
                    reset();//重置工作
                    break;
            }
        }
    
        /**
         * 重置工作
         */
        private void reset() {
            isDown = false;//重置按下状态
            isMove = false;//重置移动状态
            mDownPos.x = 0;//重置:mDownPos
            mDownPos.y = 0;//重置:mDownPos
            mOrientation = Orientation.NO;//重置方向
        }
    
        /**
         * 处理方向
         *
         * @param dir 方向
         */
        private void orientationHandler(double dir) {
            if (detaY < 0 && dir > 70 && dir < 110) {
                mOrientation = Orientation.TOP;
            }
            if (detaY > 0 && dir > 70 && dir < 110) {
                mOrientation = Orientation.BOTTOM;
            }
            if (detaX > 0 && dir < 20) {
                mOrientation = Orientation.RIGHT;
            }
            if (detaX < 0 && dir > 160) {
                mOrientation = Orientation.LEFT;
            }
            if (detaY < 0 && dir <= 70 && dir >= 20) {
                mOrientation = Orientation.RIGHT_TOP;
            }
            if (detaY < 0 && dir >= 110 && dir <= 160) {
                mOrientation = Orientation.LEFT_TOP;
            }
            if (detaX > 0 && detaY > 0 && dir >= 20 && dir <= 70) {
                mOrientation = Orientation.RIGHT_BOTTOM;
            }
            if (detaX < 0 && detaY > 0 && dir >= 110 && dir <= 160) {
                mOrientation = Orientation.LEFT_BOTTOM;
            }
        }
    
        public boolean isDown() {
            return isDown;
        }
    
        public boolean isMove() {
            return isMove;
        }
    
        /**
         * 弧度制化为角度制
         *
         * @param rad 弧度
         * @return 角度
         */
        private float deg(float rad) {
            return (float) (rad * 180 / Math.PI);
        }
    }
    
    2.方向枚举:
    /**
     * 作者:张风捷特烈<br/>
     * 时间:2018/11/15 0015:8:14<br/>
     * 邮箱:1981462002@qq.com<br/>
     * 说明:移动方向枚举
     */
    public enum Orientation {
    
        NO("无"),//无
        TOP("上"), //上
        BOTTOM("下"),//下
        LEFT("左"),//左
        RIGHT("右"),//右
        LEFT_TOP("左上"),// 左上
        RIGHT_TOP("右上"), // 右上
        LEFT_BOTTOM("左下"),//左下
        RIGHT_BOTTOM("右下")//右下
        
        private String or;
        
        Orientation(String or) {
            this.or = or;
    
        }
    
        public String value() {
            return or;
        }
    }
    
    3.事件监听回调
    /**
     * 作者:张风捷特烈<br/>
     * 时间:2018/11/15 0015:8:13<br/>
     * 邮箱:1981462002@qq.com<br/>
     * 说明:事件监听回调
     */
    
    public interface OnEventListener {
        /**
         * 点击
         *
         * @param pointF 落点
         */
        void down(PointF pointF);
    
        /**
         * 抬起
         *
         * @param pointF      抬起点
         * @param orientation 方向
         */
        void up(PointF pointF, Orientation orientation);
    
        /**
         * 移动
         *
         * @param v           速度
         * @param dy          y 位移
         * @param dx          x位移
         * @param dir         角度
         * @param orientation 方向
         */
        void move(double v, float dy, float dx, double dir, Orientation orientation);
    }
    
    4.事件处理适配器
    /**
     * 作者:张风捷特烈<br/>
     * 时间:2018/11/15 0015:8:18<br/>
     * 邮箱:1981462002@qq.com<br/>
     * 说明:事件处理适配器
     */
    public class OnEventAdapter implements OnEventListener {
        @Override
        public void down(PointF pointF) {
    
        }
    
        @Override
        public void up(PointF pointF, Orientation orientation) {
    
        }
    
        @Override
        public void move(double v, float dy, float dx, double dir, Orientation orientation) {
    
        }
    }
    

    后记:捷文规范

    1.本文成长记录及勘误表
    项目源码 日期 备注
    V0.1--无 2018-11-15 Android自定义控件辅助利器之EventParser
    2.更多关于我
    笔名 QQ 微信 爱好
    张风捷特烈 1981462002 zdl1994328 语言
    我的github 我的简书 我的CSDN 个人网站
    3.声明

    1----本文由张风捷特烈原创,转载请注明
    2----欢迎广大编程爱好者共同交流
    3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
    4----看到这里,我在此感谢你的喜欢与支持

    相关文章

      网友评论

      本文标题:Android自定义控件辅助利器之EventParser

      本文链接:https://www.haomeiwen.com/subject/adnefqtx.html