常见的类的介绍

1 MotionEvent 触摸事件 2 View 视图的位置信息 3 ViewConfiguration View相关设置 4 VelocityTracker 速度追踪器 5 Scroller 用来滑动的类

MotionEvent

Android API http://developer.android.com/reference/android/view/MotionEvent.html 官方的一些介绍 MotionEvent 形容触摸屏幕产生的事件( 这里用点击事件来代替),这个点击事件的对象包含一些Action 的信息和一系列的坐标值的信息,其中action的信息包含了state改变的信息,比如从move -> up,坐标的信息则包括了一些的位置和其他的属性的信息 比如说,当用户第一次触摸屏幕的时候,系统就会传递一个motionevent的信息给适当的一个view,这个信息包括一些actioncode为Action_Down, 和一系列的值其中包括可能为:x,y,压力,触摸区域的带下,时间等一些列信息 一些设备可以报告的多个多个运动轨迹,多触摸屏幕中一个运动轨迹对应一个手指,这时的手指对应的运动轨迹设为pointer,而motionevent包含所有的pointer的信息,即使的这个pointer不再移动从上次传达的信息 pointer 的数量改变只有当手指down或者up的时候改变,除非这个手势被取消cancle() 每一个pointer的都有一个ID来标示当down的事件发生后,ACTION_DOWNorACTION_POINTER_DOWN,这个ID值一直存在的,直到ACTION_UPorACTION_POINTER_UP)或者这个手势被取消 (indicatedbyACTION_CANCEL). motionevent提供的一系列的方法用来查询属性的信息,比如getX(int index),getY(int index),getAxisValue(int axis),getPointId(int indx),getToolType(int index),大多数情况下,通过接受index来得到信息,而不是pointer id,这个index 的值介于0到getpointercount(). Index 和pointer id的区别多个事件的时候,motionevent的顺序是不确定的(index),但是pointer 的id自始至终都是一样的,只要它还存在,我们可以通过getPointId(int index),获得pointer 的id值,也可以通过findPointIndex(int pointId),来获取对应的index的值。 为了提高效率,action_move的时候,提供一个批机制,就是处理单个对象包含多个运动的样本,当前的pointer可以使用getX(int index),getY(int index)获取批最前的事件 ,而使用getHistoricalX(int index)和getHistoricalY(int index)来获取批里面最早的其他的事件,举个例子
public boolean onTouchEvent(MotionEvent event) {    printMotinEvent(event);    return true;}void printMotinEvent(MotionEvent ev) {    final int historySize = ev.getHistorySize();    final int pointerCount = ev.getPointerCount();    Log.e("history", "history的数量"+historySize);    for (int h = 0; h < historySize; h++) {        for (int p = 0; p < pointerCount; p++) {            Log.e("history",                    "id:"+ev.getPointerId(p)+ ",2 x:"+ev.getHistoricalX(p, h)+",3 y:"+ev.getHistoricalY(p, h));        }    }    for (int p = 0; p < pointerCount; p++) {        Log.e("now", ev.getEventTime()+"time");        Log.e("now", "1 id:"+ev.getPointerId(p)+",2 x"+ ev.getX(p)+",3 y"+ ev.getY(p));    }}

打印的log如下:
motionevent 即传递,我们触摸屏幕所有的信息!并且一个触摸事件时由多个movetionevent的组成的, 常见的api如下 event.getAction() or event.getAction() & MotionEvent.ACTION_MASK //获取触控动作比如 ACTION_DOWN, event.getPointerCount() //获取触控点的数量,比如2则可能是两个手指同时按压屏幕 event.getPoninerId(int index)//对于每个触控的点的细节,我们可以通过一个循环执行getPointerId方法获取索引 event.getX(int index)//获取第index个触控点的x位置 event.getY(int index)//获取第index个触控点的y位置 event.getPressure(int index)//LCD可以感应出用户的手指压力,当然具体的级别由驱动和物理硬件决定的 event.getDownTime()//按下开始时间 event.getEventTime()//事件结束时间 event.getEventTime()-event.getDownTime()//总共按下时花费时间

view视图的位置信息

position的信息:以下四个信息代表相对父容器的位置 left=getLeft(); right = getRight(); up = getUp(); bottom = getBottom(); android 3.0 之后的添加的一些新的位置信息 translationX = getTranslatinX(); translationY = getTranslationY(); x = getX() y = getY() 注意前后的关系,left,right,up,bottom四个点的信息在平移的过程是不会发生改变的,translationx和translationy 默任初始为0,三者之前的关系时 getX() = getTranslationX() + getLeft() getY() = getTranslationY()+getTop(); 代码如下
tv = (TextView) findViewById(R.id.tv);btn = (Button) findViewById(R.id.btn);final ObjectAnimator translationX = ObjectAnimator.ofFloat(tv, "translationX", 0,50);btn.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        translationX.setDuration(300);        translationX.start();    }});translationX.addListener(new Animator.AnimatorListener() {    @Override    public void onAnimationStart(Animator animation) {        Log.e("TAG","start x = "+tv.getX()+",translationX = " + tv.getTranslationX() +",left = "+tv.getLeft());    }    @Override    public void onAnimationEnd(Animator animation) {        Log.e("TAG","end x = "+tv.getX()+",translationX = " + tv.getTranslationX() +",left = "+tv.getLeft());    }    @Override    public void onAnimationCancel(Animator animation) {    }    @Override    public void onAnimationRepeat(Animator animation) {    }});

打印的log如下

ViewConfiguration

包含一些方法去获取标准的常量在ui 上,比如一些时间,大小,或者距离,这是android 帮我们设定好的。 android api http://developer.android.com/reference/android/view/ViewConfiguration.html ViewConfiguration.get(Context context); 举个常用的例子,自定义一个长按的手势识别器代码如下(需要默认认为最小的滑动的距离和默认最小的进入长按状态的时间)

LongPressGestureDetector

public class LongPressGestureDetector {    private ViewConfiguration _configuration;    private int _minDistance ;    private int _delay;    private Context _context;    private OnlongPressListener _listener;    private Handler _handler ;    private Runnable _longPressRunnable;    private float _downX;    private float _downY;    private long _downTime;    public LongPressGestureDetector(Context context, OnlongPressListener listener){        _listener = listener;        _context = context;        _handler = new Handler(Looper.getMainLooper());        _configuration = ViewConfiguration.get(context);        _minDistance = _configuration.getScaledTouchSlop();        _delay = _configuration.getLongPressTimeout();        _longPressRunnable = new LongPressRunnale();    }    //这里以单指操作    public boolean onTouch(MotionEvent event){        int actionCode = event.getAction() & MotionEvent.ACTION_MASK;        switch (actionCode){            case MotionEvent.ACTION_DOWN:                _handler.removeCallbacks(_longPressRunnable);                _downX = event.getX();                _downY = event.getY();                _downTime = event.getDownTime();                Log.e("TAG",event.getEventTime()+"downtime"+event.getDownTime());                _handler.postDelayed(_longPressRunnable,_delay);            case MotionEvent.ACTION_MOVE:                int distanceX = (int) Math.abs(event.getX() - _downX);                int distanceY = (int) Math.abs(event.getY() - _downY);                if(distanceY > _minDistance || distanceX > _minDistance ){                    _handler.removeCallbacks(_longPressRunnable);                }                break;            case MotionEvent.ACTION_UP:                if(event.getEventTime() - _downTime < _delay) {                    _handler.removeCallbacks(_longPressRunnable);                }                Log.e("TAG",event.getEventTime()+"downtime"+event.getDownTime());                break;        }        return true;    }    interface OnlongPressListener{        void onLongPress();    }    class LongPressRunnale implements Runnable{        @Override        public void run() {            Log.e("TAG", "进入到了长按的状态了");            if(_listener != null){                _listener.onLongPress();            }        }    }}
这里是以单指作为操作的,如果选择用多指,我们根据每一个pointer的id来判断时否发生改变了, activity的代码

public class MainActivity extends AppCompatActivity {    private LongPressGestureDetector _longPressGestureDetector;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        _longPressGestureDetector = new LongPressGestureDetector(this,new LongPressGestureDetector.OnlongPressListener(){            @Override            public void onLongPress() {                Log.e("TAG","开始在主线程更新UI了");            }        });    }    @Override    public boolean onTouchEvent(MotionEvent event) {        return _longPressGestureDetector.onTouch(event);    }}
注意到了这里面在onTouchEvent()全部交给LongPressGestureDetector的去处理,并且在LongPressGestureDetector的ontouch()的方法里面返回了true,这样做其实不好,但是这里只是为了介绍下了ViewConfiguration的这个类,接着长按的进入长按的回调方法中,Log如下:

VelocityTracker

android api http://developer.android.com/reference/android/view/VelocityTracker.html 用来追踪触摸事件的速度的,主要是为了在filing的等手势的后面的平滑滑动,通过obtain()获取实例,在你想追踪的event的之前使用addmovement(MotionEvent event)去追踪这个event 的,紧接着调用computeCurrentVelocity(int units ),最后就可以使用getXVelocity(int pointerId ),getYVelocity(int pointId)来获取了当前的pointer的在x,y的速度

Scroller

andorid API http://developer.android.com/reference/android/widget/Scroller.html 这个用于封装了滚动的类,你可以用这个scroller收集你需要制作的动画的一个数据,其实里面只是存储着一些的关于滑动的信息,真正的滑动的实现是通 view中重写的computeScroll()的方法来实现的, 滑动的实现的原理 我们知道自定义viewgroup的dispatchdraw的方法中的调用drawChild(),drawChild()的源码如下。 protectedbooleandrawChild(Canvascanvas,Viewchild,longdrawingTime){
returnchild.draw(canvas,this,drawingTime); } 也就以为着去调用响应的child的Draw方法。从而完成整体的draw的效果,在view的中的draw的代码中可以找到computeScroll()的代码。 我们通过在computeScroll()的中使用postInvalidate()从而使整个布局在重绘,从而完成滑动的实现 结论 从滑动的原理可以看出来,滑动其实我门的draw的部分,这也就意味着的实现滑动的是内容而不是view的视图的位置,也就是意味着view 的layout的布局信息自始至终都未变过,在滑动的过程中。 常见用法 publicbooleancomputeScrollOffset() 当想要知道新的位置时,调用此函数。如果返回true,表示动画还没有结束。位置改变以提供一个新的位置。 publicvoidextendDuration(intextend) 延长滚动动画时间。 publicvoidfling(intstartX,intstartY,intvelocityX,intvelocityY,intminX,intmaxX,intminY,intmaxY) 在fling手势开始滚动。滚动的距离取决于fling的初速度。 publicvoidstartScroll(intstartX,intstartY,intdx,intdy)以提供的起始点和将要滑动的距离开始滚动。 publicinttimePassed()返回自滑动开始经过的时间 利用Scroller和VelocityTracker,我们实现一个可以在fling的时候能够具有滑动惯性。并且在滑动的时候一起跟随滑动,但是没有加外层的限制 代码如下 首先上了布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <com.example.rrtoyewx.person.FlingViewGroup        android:id="@+id/tv"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:background="@android:color/white">        <ImageView            android:layout_width="match_parent"            android:layout_height="match_parent"            android:src="@drawable/image1" />        <ImageView            android:layout_width="match_parent"            android:layout_height="match_parent"            android:src="@drawable/image2" />        <ImageView            android:layout_width="match_parent"            android:layout_height="match_parent"            android:src="@drawable/image3" />        <ImageView            android:layout_width="match_parent"            android:layout_height="match_parent"            android:src="@drawable/image4" />        <ImageView            android:layout_width="match_parent"            android:layout_height="match_parent"            android:src="@drawable/image5" />        <ImageView            android:layout_width="match_parent"            android:layout_height="match_parent"            android:src="@drawable/image6" />        <ImageView            android:layout_width="match_parent"            android:layout_height="match_parent"            android:src="@drawable/image7" />    </com.example.rrtoyewx.person.FlingViewGroup></RelativeLayout>

布局很简单就是自定义了viewgroup了,然后里面放了7张图片。

下面的放上了这个自定义viewgroup的实现

package com.example.rrtoyewx.person;import android.content.Context;import android.graphics.Point;import android.graphics.PointF;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewGroup;import android.widget.Scroller;/** * Created by Rrtoyewx on 15/11/4. */public class FlingViewGroup extends ViewGroup {    private VelocityTracker _velocityTracker;    private Scroller _scroller;    private ViewConfiguration _viewConfiguration;    private PointF _prePoint;    private PointF _tempPoint;    private PointF _curPoint;    private Point _distancePoint;    private int _touchMinDistance;    private int _maxFlingVelocity;    private int _minFlingVelocity;    public FlingViewGroup(Context context) {        super(context);    }    public FlingViewGroup(Context context, AttributeSet attrs) {        super(context, attrs);        _scroller = new Scroller(context);        _viewConfiguration = ViewConfiguration.get(context);        _touchMinDistance = _viewConfiguration.getScaledTouchSlop();        _maxFlingVelocity = _viewConfiguration.getScaledMaximumFlingVelocity();        _minFlingVelocity = _viewConfiguration.getScaledMinimumFlingVelocity();    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        int count = getChildCount();        for (int i = 0; i < count; i++) {            View child = getChildAt(i);            child.layout(l + i * (r - l), t, r + i * (r - l), b);        }    }    //这里以单指来分析即pointerIndex = 0;    @Override    public boolean onTouchEvent(MotionEvent event) {        int actionCode = event.getAction() & MotionEvent.ACTION_MASK;        if(_velocityTracker == null){            _velocityTracker = VelocityTracker.obtain();        }        _velocityTracker.addMovement(event);        switch (actionCode) {            case MotionEvent.ACTION_DOWN:                if (_scroller.isFinished()) {                    _scroller.abortAnimation();                }                _prePoint = new PointF();                _prePoint.x = event.getX(0);                _prePoint.y = event.getY(0);                break;            case MotionEvent.ACTION_MOVE:                calculateMovePoint(event);                _curPoint = _tempPoint;                if (Math.abs(_prePoint.x - _curPoint.x) > _touchMinDistance || (Math.abs(_prePoint.y - _curPoint.y) > _touchMinDistance)) {                    if (_distancePoint != null) {                        _distancePoint = null;                    }                    _distancePoint = new Point();                    _distancePoint.x = (int) (_curPoint.x - _prePoint.x);                    _distancePoint.y = (int) (_curPoint.y - _prePoint.y);                    scrollTo(-_distancePoint.x + getScrollX(), -_distancePoint.y + getScrollY());                    _prePoint = _curPoint;                }                break;            case MotionEvent.ACTION_UP:                int pointId = event.getPointerId(0);                final VelocityTracker velocityTracker = _velocityTracker;                velocityTracker.computeCurrentVelocity(1000, _maxFlingVelocity);                int xVelocity = (int) velocityTracker.getXVelocity(pointId);                int yVelocity = (int) velocityTracker.getYVelocity(pointId);                Log.e("TAG", "xVelocity : " + xVelocity + ",xVelocitY: " + yVelocity);                if(Math.abs(xVelocity)>_minFlingVelocity && Math.abs(yVelocity ) > _minFlingVelocity ){                    _scroller.fling(getScrollX(),getScrollY(), -xVelocity, -yVelocity,Integer.MIN_VALUE,Integer.MAX_VALUE,Integer.MIN_VALUE,Integer.MAX_VALUE);                    awakenScrollBars(_scroller.getDuration());                    invalidate();                }            case MotionEvent.ACTION_CANCEL:                resetState();                break;        }        return true;    }    /**     * 计算event的具体信息     * @param event     */    private void calculateMovePoint(MotionEvent event) {        _tempPoint = new PointF();        int historySize = event.getHistorySize();        for (int h = 0; h < historySize; h++) {            float historicalX = event.getHistoricalX(0, h);            _tempPoint.x += historicalX;            float historicalY = event.getHistoricalY(0, h);            _tempPoint.y += historicalY;        }        _tempPoint.x += event.getX(0);        _tempPoint.y += event.getY(0);        _tempPoint.x /= (historySize + 1);        _tempPoint.y /= (historySize + 1);    }    private void resetState() {        if (_velocityTracker != null) {            _velocityTracker.clear();            _velocityTracker.recycle();            _velocityTracker = null;        }    }    @Override    public void computeScroll() {        super.computeScroll();        if (_scroller.computeScrollOffset()) {            scrollTo(_scroller.getCurrX(), _scroller.getCurrY());            postInvalidate();        }    }    }


简单的说下的代码的 1 初始化的时候将ViewConfiguration和Scroller,并初始化一些常量, 2 onLayout()一次将孩子放在整个手机屏幕,依次往右放 3 onTouchEvent()中,处理滑动的逻辑,并过滤一些我们不要的motionevent 4 重写computeScroll(),让其能够平滑的滑动 最后附上效果图(模拟器太难滑的了,效果不佳,还请见谅),



















更多相关文章

  1. Android(安卓)签名信息读取
  2. Android查看包名和获取包名
  3. React Navigation Android(安卓)返回键事件处理
  4. Android收集崩溃信息的原理
  5. Android中的popWindow
  6. Android之防快速重复点击的全局设置
  7. android点击文本框之外的地方隐藏键盘
  8. Android获取所有安装APP信息
  9. Android拖动改变小球位置

随机推荐

  1. Win7安装php7 + apache2.4,成功启动
  2. 速率结构的数据库/算法
  3. apache+php+mysql分离搭建LAMP
  4. [开心学php100天]第五天:string函数(上)
  5. PHP CLI模式开发
  6. 海图没有显示任何东西,只是空白的html页面
  7. 关注:PHP文件目录和文件本身的操作
  8. 确定脚本所在的服务器以及PHP中的配置的
  9. APMServ 在 Win7 下出现“APMServ-Apache
  10. PHP会话不能使用JQuery Ajax?