说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

手势识别兼容Android 1.x和2.x的代码

HTML文档下载 WORD文档下载 PDF文档下载
手势识别兼容Android 1.x和2.x的代码

作者:Android开发网


   由于Android 2.x开始很多API变动比较大新增了一些比如多点触控的支持,对于屏幕触控手势识别中我们需要考虑更多的实现方法,下面是一段兼容Android 1.x和2.x的代码,可以让我们的程序兼容几乎99%的Android手机。

  一、首先新建一个抽象类判断SDK版本问题

 public abstract class VersionedGestureDetector {
    private static final String TAG = "VersionedGestureDetector";

    OnGestureListener mListener;

    public static VersionedGestureDetector newInstance(Context context,
            OnGestureListener listener) {  //设计实例化构造方法,这里Android123提示大家目前有3种API的实现方法,我们需要逐一考虑最优的解决方法,以满足高平台更多的功能实现。

        final int sdkVersion = Integer.parseInt(Build.VERSION.SDK); //使用android.os.Build判断API Level,但需要将字符串转换为整形
        VersionedGestureDetector detector = null;
        if (sdkVersion < Build.VERSION_CODES.ECLAIR) { //如果版本小于2.0则使用1.5版本的API,可以兼容1.5和1.6
            detector = new CupcakeDetector();
        } else if (sdkVersion < Build.VERSION_CODES.FROYO) { //如果版本小于2.1则使用2.0版本的API,可以兼容2.0,2.0.1和2.1这三个版本
            detector = new EclairDetector();
        } else {  //否则使用2.2开始的新的触控API

            detector = new FroyoDetector(context);
        }

        Log.d(TAG, "Created new " + detector.getClass()); //判断最终选择的到底是哪个版本的类
        detector.mListener = listener;

        return detector;
    }

    public abstract boolean onTouchEvent(MotionEvent ev); //我们需要根据版本决定onTouchEvent的实现

    public interface OnGestureListener { //手势判断接口主要是实现两个方法
        public void onDrag(float dx, float dy);  //拖拽
        public void onScale(float scaleFactor); //缩放
    }

    private static class CupcakeDetector extends VersionedGestureDetector { //针对Android 1.5和1.6设计的兼容方式
        float mLastTouchX;
        float mLastTouchY;

        float getActiveX(MotionEvent ev) { //获得当前X坐标
            return ev.getX();
        }

        float getActiveY(MotionEvent ev) { //获得当前Y坐标
            return ev.getY();
        }

        boolean shouldDrag() { //是否是拖拽中或者说移动中
            return true;
        }

        @Override
        public boolean onTouchEvent(MotionEvent ev) { //重写onTouchEvent方法
            switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN: {  //向下
                mLastTouchX = getActiveX(ev);
                mLastTouchY = getActiveY(ev);
                break;
            }
            case MotionEvent.ACTION_MOVE: { //Android开发网提醒大家,由于1.x时代的API比较简单,很多手势没有封装,我们只能从ACTION_MOVE中根据坐标变化判断手势样式
                final float x = getActiveX(ev);
                final float y = getActiveY(ev);

                if (shouldDrag()) {
                    mListener.onDrag(x - mLastTouchX, y - mLastTouchY); //处理拖拽移动
                }

                mLastTouchX = x;
                mLastTouchY = y;
                break;
            }
            }
            return true;
        }
    }

    private static class EclairDetector extends CupcakeDetector { //这个是针对Android 2.0,2.0.1和2.1提供的解决方法,可以看到有很多多点触控相关API出现
        private static final int INVALID_POINTER_ID = -1;
        private int mActivePointerId = INVALID_POINTER_ID;
        private int mActivePointerIndex = 0;

        @Override
        float getActiveX(MotionEvent ev) {
            return ev.getX(mActivePointerIndex);
        }

        @Override
        float getActiveY(MotionEvent ev) {
            return ev.getY(mActivePointerIndex);
        }

        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            final int action = ev.getAction();
            switch (action & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                mActivePointerId = ev.getPointerId(0);
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                mActivePointerId = INVALID_POINTER_ID;
                break;
            case MotionEvent.ACTION_POINTER_UP: //有个点松开
                final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                final int pointerId = ev.getPointerId(pointerIndex); //获取第几个点
                if (pointerId == mActivePointerId) {
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    mActivePointerId = ev.getPointerId(newPointerIndex);
                    mLastTouchX = ev.getX(newPointerIndex); //处理第newPointerIndex个点的x位置
                    mLastTouchY = ev.getY(newPointerIndex);
                }
                break;
            }

            mActivePointerIndex = ev.findPointerIndex(mActivePointerId);
            return super.onTouchEvent(ev);
        }
    }

    private static class FroyoDetector extends EclairDetector { //从Android 2.2开始可以很好的处理多点触控的缩放问题
        private ScaleGestureDetector mDetector;

        public FroyoDetector(Context context) {
            mDetector = new ScaleGestureDetector(context,
                    new ScaleGestureDetector.SimpleOnScaleGestureListener() {
                @Override public boolean onScale(ScaleGestureDetector detector) {
                    mListener.onScale(detector.getScaleFactor()); //根据 ScaleGestureDetector.SimpleOnScaleGestureListener这个系统类处理缩放情况通过onScale方法
                    return true;
                }
            });
        }

        @Override
        boolean shouldDrag() {
            return !mDetector.isInProgress();
        }

        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            mDetector.onTouchEvent(ev);
            return super.onTouchEvent(ev);
        }
    }
}

 有关调用方法,我们可以自定义一个View,取名为TouchExampleView类,这里来处理触控相关的问题

public class TouchExampleView extends View {
    private Drawable mIcon; //我们以一个图片为参照物,根据手势控制
    private float mPosX;
    private float mPosY;

    private VersionedGestureDetector mDetector;
    private float mScaleFactor = 1.f; //原始缩放比例为1.0

    public TouchExampleView(Context context) {
        this(context, null, 0);
    }

    public TouchExampleView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TouchExampleView(Context context, AttributeSet attrs, int defStyle) { //实现我们自定义View的构造
        super(context, attrs, defStyle);
        mIcon = context.getResources().getDrawable(R.drawable.icon);
        mIcon.setBounds(0, 0, mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight());

        mDetector = VersionedGestureDetector.newInstance(context, new GestureCallback()); //实例化刚才的版本自适应手势控制类
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) { //重写onTouchEvent方法,使用VersionedGestureDetector类得出的数据。
        mDetector.onTouchEvent(ev);
        return true;
    }

    @Override
    public void onDraw(Canvas canvas) { //处理自定义View绘制方法
        super.onDraw(canvas);

        canvas.save();
        canvas.translate(mPosX, mPosY); //进行平移操作,根据mPosX和mPosY坐标
        canvas.scale(mScaleFactor, mScaleFactor); //进行缩放操作,参数就是刚才定义的float类型的缩放比例
        mIcon.draw(canvas); //直接绘制图片变化到画布中
        canvas.restore();
    }

    private class GestureCallback implements VersionedGestureDetector.OnGestureListener {
        public void onDrag(float dx, float dy) { //这里Android123提示大家在2.2中这个回调方法将可以支持拖拽的坐标处理
            mPosX += dx;
            mPosY += dy;
            invalidate();
        }

        public void onScale(float scaleFactor) {
            mScaleFactor *= scaleFactor; //缩放控制

            mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f)); //限制最小缩放比例为1.0最大为5.0倍数

            invalidate();
        }
    }
}

 有关调用我们的自定义的TouchExampleView可以在Activity的onCreate方法中加入以下代码,

     TouchExampleView view = new TouchExampleView(this);
     view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
      ViewGroup.LayoutParams.MATCH_PARENT));

     setContentView(view);  //替换掉原始的res.layout.main

最后Android123需要给大家说明的是使用本例子,直接使用Android 2.2的SDK创建工程,即API Level为8,发布时在androidmanifest.xml中加入uses-sdk android:minSdkVersion="3" android:targetSdkVersion="8"这句可以兼容从Android 1.5到2.2的版本,有关2.3中新增的一个可以处理5个或5个以上的多点触控增强类Android开发网将在以后的时间中介绍。

1月10日:改变世界的iPhone七岁了,你是传奇! 同洲电子推出首款手机操作系统960OS 免费授权使用 如何在Windows 8.1的IE11中打开同步选项卡? 25年老对手评价微软:换CEO可行,但是太迟了 【PPT集萃】十位一线专家分享Spark现状与未来(三) 万元奖品等你拿!2014创客118新年大Party! Firefox OS的2013回顾和2014展望 Strom8 CEO:搞好手游开发,合伙人很重要 2013年Q4全球PC出货量同比下滑6.9% 已连续下滑七个季度 一周消息树:2013年十大产品、图书、公司盘点 专访Wunderlist主设计师Jan Martin:永远不要盲目跟风流行趋势 研发周报:超实用的JavaScript技巧及最佳实践 2013最吃香的技能:Java称霸、Android势头正猛 移动周报:最火原型设计工具盘点 “京东电商云”起航,零售企业及品牌商是重点 教育乃立国之本:教育类开源项目大汇集 Hugo Barra首度谈离开谷歌后在中国工作的感受 对中国赞不绝口 母婴行业最早试水者 优谈宝宝借助轻应用全面布局移动产品线 腾讯云平台部总经理纪顺友:微云将彻底迈过文件传输的门槛 豌豆“荚”油!B轮融资1.2亿美元的豌豆荚 2013年终盘点:10款最精巧的硬件开发板 SquareWear:可替代Lilypad Arduino的开发板 开放数据:2014年最热门的竞争领域 IE11虚拟机免费面向广大开发者 九城搭建的一个以Hadoop为基础的大数据平台 Windows 8复杂性的代价到底有多大? 在发布前,第一代iPhone其实并不完善 市场占有率调查:iOS 7秒杀Android 4.4 AWS会赢、OpenStack会消亡、Connected Cars可防僵尸攻击 谷歌以32亿美金收购iPod之父的创业公司Nest 物联网时代来临 微软2014,有你期待的吗? 请问能不能在不同用户登陆的情况来决定服务A是否启动。 关于还原精灵转储后win98不能启动的问题,请指教!~ 今天,我终于听到项目经理的一句内心话,让我们作为程序员感到一阵阵的寒心 请教一下 dll调试问题 怎样得到OnLButtonDown的point在整个屏幕上的坐标啊?谢谢 递归调用FindFirstFile、FindNextFile、FindClose的问题 页面调度有关的课程设计 关于client端与server端的连接问题 请问能不能在不同用户登陆的情况来决定服务A是否启动。 Textbox如何禁止它记忆以前曾经输入过的值? 我的XP的CPU经常占用90%以上,高手指点. 安装完win2000,又安装了天网防火墙,再安装SQL server 2000,快完成时启动服务警告“无法定位程序输入点” 急招深圳周边(含深圳).Net程序员 ??qustion Laney(6吨大肥猫) 快来啊^@^ 有关struts的<html:text>标签的问题!!!!!!!!!!!!!!!!!!!!!!! 为了考试挑灯夜读,遇到一个菜问题请大家帮忙! 哪位高手帮帮我!时间紧急! 关于还原精灵转储后win98不能启动的问题,请指教!~ 有几张漂亮图片,看看你的计算机是怎么累死的 求C++算法代码。 怎么实现在IE中将查找到的关键字用红色标记指示出来? 求C++算法代码。 请问哪里可以下载Numega DevPartenr Studio 测试工具 ㊣㊣ 什么也不多说了,帮忙给解决这个问题吧, 先多谢了!! ㊣㊣ 有个小小问题 寻找监测某端口的数据流量软件 都市幽灵·里面一定有宝藏 非常奇怪:为什么超链接无效? 显示异常 下个星期开始到新公司了,请大家给点经验,好吗 急!jsp+mysql,急寻blob输出方法!!! 修改记录问题 StringGrid的自画 导出 救命呀,关于XP的激活问题. 语句 请问有什么好的串口调试工具,可以模拟串口发送数据的??????? 简单问题高分相送 MessageBox.Show 方法需要什么样的名空间 使用ghost硬盘刻录硬盘怎么区分源盘和目标盘,请大虾详细说说,在线等 概念性问题(没办法,太笨了,见笑了) vf8支持动态SQL吗? 请问:如何单独安装BDE? 因为你无权连接数据库服务器?? 大家看看一个非常专业的商贸企业管理软件,要源码好商量! 如何清除Image中的图片? 数据库查询一个奇怪问题 关于记事本程序的编写??? 揭贴后的话(告诉大家你的问题解决的怎么样) 感觉很简单,但是我就是不知如何下手 现实是此岸,理想是彼岸,中间隔着湍急的河流,行动则是架在河上的桥梁.这句话说明?1理想是对现实的超越2崇高的理想信念必须落实在行动上3追求和实现理想是一个艰苦奋斗的过程4 要正确认 此题思路?A是什么? 与象共舞 大象跳舞给人的感觉是什么 "颛顼、帝喾"这两人是什么人啊? 这两题思路是什么啊 大学对于我们的意义,请谈谈你的看法吧! 圆的英文怎么写啊“圆的”这个英文单词怎么拼啊?我要准确的! 车子被大雨浸泡了,能否获得保险理赔? 对大学社团的看法 二李复习全书第524页例2.21,为什么{X≤x}的概率是两个面积之比分母为半圆面积,分子面积是三角形BOA和扇形ABC的面积之和, 发生11·15事件,提醒我了,出现这种火灾、台风、暴雨一类的灾害后,怎么做才能快速理赔呢? 明珠散落的意思解释对了就好了~ 考研:我已经把数学书看了一遍,不过没做课后题,那我还需要看一遍李永乐复习全书吗?那660题呢?什么时候看啊? 商务英语和财经管理你们推荐哪个 对大学教学的看法?还有理想的大学教学是怎样的?大学教与学的灵魂? 五帝的颛顼的读音是什么呀? 一元二次题目当m为何值时,二次三项式2x^2 +6x-3m1在实数范围内能分解2不能分解3能分解成一个完全平方式 6题..文科学霸请进……为什么c不对 颛顼 怎么读?要拼音 句子:“突然雷声大作,先是漂下几滴雨点,接着水如柱.”哪两个字错了?并写出正确的. 大概的相近词是什么 颛顼怎么读?拼音 为什么雷声大雨就大 东阳.为什么叫东阳 为人民服务的人的事迹 突然雷声大作,先是飘下几滴雨点,接着雨如柱.有什么错别字? 浙江的东阳市有叫东阳商场的吗?想去那里进货. 成语接龙越多越好 夫赵强而燕弱...故燕王欲结于君 翻译 晶莹剔透、水生喧腾,明珠散落的意思 成语接龙:万众一心(越多越好) 在棱长为a的正方体正方体ABCD-A1B1C1D1中,A到平面BB1D1D的距离为____,AA1到平面BB1D1D的距离为_____ 耳朵用英语怎么写耳朵,眼睛,鼻子,手,嘴巴,头,脸怎么写 千变万化的成语接龙 越多越好 一元二次问题X^4-X^2-6=0 某人向东走5米,又向西走5米,那么此人实际走了多少米?他的位置是在?请帮助帮助回答,谢谢!这道题我不知道该怎么写,请来帮助我把! 珍珠泉似明珠散落 ,—————— ( 对对子 )急 宇宙没有形成的时候是什么样子的? 某人向东走了20米,又向西走了30米,实际走了多少米?这是一个关于有理数的数学问题主要是要弄清实际说的是路程还是距离 有文科学霸麽 宇宙在最早的时候是什么样子的?是不是什么都没?是不是哪个时候连空间也没?时间怎么解释 是不是要参考下《时间简史》霍金提出的解释是什么意思? 已知X十y=5⃣️Xy=2⃣️求(x-y)^2.x^4+y^4的值 Lambert1.[男子名] [英格兰人姓氏] 兰伯特.来源于日耳曼语人名,含义是“土地,领土+光明的,著名的”(land,territory+bright,famous) 2.[英格兰人姓氏] 兰伯特.职业名称,牧羊人,来源于古英语,含义是“羔 颛顼简介 若丨x-3丨+丨y-2丨=0,试求2x+y的值 Lambert1.[男子名] [英格兰人姓氏] 兰伯特.来源于日耳曼语人名,含义是“土地,领土+光明的,著名的”(land,territory+bright,famous) 2.[英格兰人姓氏] 兰伯特.职业名称,牧羊人,来源于古英语,含义是“羔 宇宙未诞生时是什么样子的?(不要特别复杂的理论) 若丨x丨=3,丨y丨=5,且丨x-y丨=-(x-y).求丨x-3丨+(y-5)²的值 Fedor可以做英文名字用吗?是英文姓还是男子名? 颛顼 介绍 已知丨x-2丨+丨y+2丨=0,求 x,y的值要用上初中因为所以的符号,具体点 什么像一颗颗明珠造句 仿写现实是此岸,理想是彼岸,中间隔着湍急的河流,行动则是架在川上的桥梁 能概括 在上的那边全诗中心 Your Personal Day of Death is... Tuesday, April 9, 2075 Seconds left to live...2,120,323,716 Delay Your Date of Death How Migraines Impact Quality of Life Gastroesophageal Reflux Disease: What You Should Know A Lack of Sleep or ADHD? 都是什么 有人说:“现实是此岸,理想是彼岸,中间隔着湍急的河流,行动则是架在河上的桥梁.”这个句子充满了哲理.请你也试着将《在山的那边》全诗的内容浓缩提炼,仿照这个句子写一句能概括全诗 颛顼介绍 Your Personal Day of Death is... Friday, August 8, 2081什么意思?Delay Your Date of Death The Phases of Migraines What to Expect When Getting an MRI Polycystic Ovary Syndrome: What You Should Know 这都啥意思? 暴雨离檐,犹如明珠散落,一地流水向低而去. 人教版语文五年级下册7单元的生字词 美众院听证窃听事件 国安局长称系分享欧洲多国遭风暴袭击 死亡人数已升至1以色列将在东耶路撒冷新建1500个犹美称法国西班牙自行实施电子窃听行动 日中学教师上课期间刻录色情片DVD向一架卡-52飞机在莫斯科坠毁 或为技调查:美国幼童使用移动设备已成为普遍美国有意叫停窃听盟国元首 部门“内讧欧洲风暴肆虐 高校推风暴命名项目收费韩外长:日本错误历史认知阻碍韩日关系日知名主播之子因盗窃被解雇 检方暂不奥巴马提名两名竞选支持者为美国驻外大韩在独岛海域清理垃圾17吨 吁居民游日土发表共同宣言 安倍决心加强战略伙意大利比萨斜塔修复见成效 12年扶正美称法国西班牙自行实施电子窃听行动 美称法国西班牙自行实施电子窃听行动 外媒:美联储资产规模恢复正常至少要到乌克兰法院裁定没收季莫申科女儿名下饭美国最新型隐身驱逐舰下水 因价格太贵欧洲多国遭风暴袭击 死亡人数已升至1今年以来,习近平关于南海都说了啥?傅崐成:南海\"仲裁结果\"不合法 日媒:82岁日本天皇有意生前退位,或一团伙“重出江湖”剧本不换专偷上海的武汉白沙洲大市场开展灾后恢复工作 力政解|人社部部长尹蔚民:年内拿出渐进政解丨人民监督员可监督检察机关立案侦政解|新版综合素质评价报告册要纳入中复制粘贴炒冷饭,编剧你这样“致青春”多谢“剁手党”!今年山东农村电商规模乌兰察布首届中国国际露营大会落幕 展生命之堤上的“火箭速度”——火箭军某海关总署发布最新进出口数据:二季度出浙江乐清推广机动车“斑马线礼让行人”物流业国际化破解“大而不强”难题 助外交部:中方采取多种有效措施保护南海东盟智库顾问:非法“仲裁”无助解决南一派胡言!仲裁庭声称“太平岛是礁”证乌兰察布首届中国国际露营大会落幕 展“奥特曼”现身长沙下面条北京急救培训进“深山”
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘