View

什么是View

        View是Android中所有控件的基类,view本身可以是单控件也可以是由多控件组成的控件

 

View的位置参数:

View

View自身提供的获取坐标的方法:

getTop():获取view自身的顶边到其父布局顶边的距离。

getLeft():获取view自身的左边到其父布局左边的距离。

getRight():获取view自身的右边到其父布局左边的距离。

getBottom():获取view自身的底边到其父布局顶边的距离。

 

MotionEvent

手指接触屏幕锁产生的事件,常用的如下:

ACTION_DOWN——手指刚接触屏幕

ACTION_MOVE——手指在屏幕上移动

ACTION_UP——手指从屏幕上松开的一瞬间

 

MotionEvent提供的方法:

getX() :获取点击事件距离控件左边的距离,即视图坐标。

getY() :获取点击事件距离控件顶边的距离,即视图坐标。

getRawX():获取点击事件距离整个屏幕左边的距离,即绝对坐标。

getRawY():获取点击事件距离整个屏幕顶边的距离,即绝对坐标。

View

 

 

TouchSlop

        根据方法注释理解这个touchSlop是一个滑动距离值的常量,也就是说当我们手触摸在屏幕上滑动时,如果滑动距离没有超过touchSlop值的话 ,android系统本身是不会认为我们在屏幕上做了手势滑动,因此只有当我们在屏幕上的滑动距离超过touchSlop值时,android系统本身才会认为我们做了滑动操作并去响应触摸事件,不过要注意的是不同的设备,touchSlop的值可能是不同的,一切以上述的函数获取为准

 

VelocityTracker

VelocityTracker是个速度跟踪类,用于跟踪手指滑动的速度,包括x轴方向和y轴方向的速度。

使用过程:在view的onTouchEvent方法中追踪当前单击事件的速度

VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);

当我们想知道当前的滑动速度时,可以采用如下方式来获取当前的速度:

velocityTracker.computeCurrentVelocity(1000);
int xVelocity = (int) velocityTracker.getXVelocity();
int yVelocity = (int) velocityTracker.getYVelocity();

如果不需要使用它时,需要调用clear方法来重置并回收内存: 

velocityTracker.clear();
velocityTracker.recycle();

        computeCurrentVelocity (int units),基于当前我们所收集到的点计算当前的速率,当我们确定要获得速率信息的时候,在调用该方法,因为使用它需要消耗很大的性能。

        参数:units  我们想要指定的得到的速度单位,如果值为1,代表1毫秒运动了多少像素。如果值为1000,代表1秒内运动了多少像素。这个方法还有一个重载函数 computeCurrentVelocity (int units, float maxVelocity), 跟上面一样也就是多了一个参数。

        参数:maxVelocity  该方法所能得到的最大速度,这个速度必须和你指定的units使用同样的单位,而且必须是整数.也就是,你指定一个速度的最大值,如果计算超过这个最大值,就使用这个最大值,否则,使用计算的的结果,

        这个最大速度可以通过ViewConfiguration.get(context).getScaledMaximumFlingVelocity()方式获取。

       getXVelocity()和getYVelocity() ,这两个很简单,获得横向和竖向的速率。前提是一定要先调用computeCurrentVelocity (int units)函数计算当前速度!

 

        速度的计算公式,可以用下列公式来表示,所以说速度可以时负数:

        速度 = (终点位置 - 起点位置) / 时间段

 

 

GestureDetector

        手势监听类,用于辅助检测用户的单击、滑动、长按、双击等行为

      使用:先创建一个GestureDetector对象并实现OnGestureListener接口,根据需要还可以实现OnDoubleTapListener从而能够监听双击行为:

GestureDetector gestureDetector = new GestureDetector(this);
//解决长按屏幕后无法拖动的现象
gestureDetector.setIsLongpressEnabled(false);

        接着,接管目标View的onTouchEvent方法,在需要等待监听的View中的onTouchEvent方法中添加如下实现:

boolean consume = gestureDetector.onTouchEvent(event);
return consume;

 

OnGestureListener中的接口:

// 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发
public boolean onDown(MotionEvent arg0) {
    Log.i("MyGesture", "onDown");
    Toast.makeText(this, "onDown", Toast.LENGTH_SHORT).show();
    return true;
}

/*
 * 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发
 * 注意和onDown()的区别,强调的是没有松开或者拖动的状态
 */
public void onShowPress(MotionEvent e) {
    Log.i("MyGesture", "onShowPress");
    Toast.makeText(this, "onShowPress", Toast.LENGTH_SHORT).show();
}

// 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发
// 非常快的点击Touchup:onDown>onSingleTapUp>onSingleTapConfirmed 
// 稍微慢点的点击Touchup:onDown>onShowPress>onSingleTapUp>onSingleTapConfirmed
public boolean onSingleTapUp(MotionEvent e) {
    Log.i("MyGesture", "onSingleTapUp");
    Toast.makeText(this, "onSingleTapUp", Toast.LENGTH_SHORT).show();
    return true;
}

// 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发
// 参数一:第一个MotionEvent
// 参数二:最后一个MotionEvent
// 参数三:velocityX  X轴上的移动速度,像素/秒
// 参数四:velocityY  Y轴上的移动速度,像素/秒
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
    Log.i("MyGesture", "onFling");
    Toast.makeText(this, "onFling", Toast.LENGTH_LONG).show();
    return true;
}

// 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发
// 滑屏:手指触动屏幕后,稍微滑动后立即松开onDown-->onScroll-->onScroll-->onScroll-->onFling
// 拖动: onDown-->onScroll-->onScroll-->onFiling
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    Log.i("MyGesture", "onScroll");
    Toast.makeText(this, "onScroll", Toast.LENGTH_LONG).show();
    return true;
}

// 用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发
//触发顺序:onDown->onShowPress->onLongPress
public void onLongPress(MotionEvent e) {
    Log.i("MyGesture", "onLongPress");
    Toast.makeText(this, "onLongPress", Toast.LENGTH_LONG).show();
}

 

GestureDetector.OnDoubleTapListener中的接口:

// 单击时发出通知。
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
    return false;
}

// 发生双击时通知。
@Override
public boolean onDoubleTap(MotionEvent e) {
    return false;
}

//当发生双击手势中的事件(包括向下,向上和向上事件)时通知。
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
    return false;
}

google官方api:

https://developer.android.com/reference/android/view/GestureDetector.OnDoubleTapListener

 

Scroller

        弹性滑动对象,用来实现View的弹性滑动,Scroller本身无法让view弹性滑动,它需要和view的computeScroll方法配合使用才能共同完成这个功能。

 

 

 

 

View的滑动

实现view滑动的三种方式:

  1. 通过view本身提供的scrollTo/scrollBy方式来实现
  2. 通过动画给view施加平移效果来实现
  3. 通过改变view的LayoutParams使用view重新布局从而实现滑动

 

使用ScrollTo/ScrollBy

        scrollTo跟scrollBy其移动的本质都是View/ViewGroup中的内容,并且移动的过程都是瞬间完成的    

        scrollTo喝scrollBy都是View中的方法,不是Scroller中的方法,但是控制View的平滑移动与Scroller类密不可分。

        scrollTo() : **指是的移动的绝对位置,如果位置没有变化,多次调用则不会起作用。

        scrollBy() : **其本质依然是调用的scrollTo(),指的的移动当前位置的相对距离(每次都是先将当前的位置和设置的距离相加之和调用scrollTo(),这样如果你多次调用,你就会发现其每次都会移动一段距离,这是和scrollTo()的本质区别)

/**
 * Set the scrolled position of your view. This will cause a call to
 * {@link #onScrollChanged(int, int, int, int)} and the view will be
 * invalidated.
 * @param x the x position to scroll to
 * @param y the y position to scroll to
 */
public void scrollTo(int x, int y) {
    if (mScrollX != x || mScrollY != y) {
        int oldX = mScrollX;
        int oldY = mScrollY;
        mScrollX = x;
        mScrollY = y;
        invalidateParentCaches();
        onScrollChanged(mScrollX, mScrollY, oldX, oldY);
        if (!awakenScrollBars()) {
            postInvalidateOnAnimation();
        }
    }
}

/**
 * Move the scrolled position of your view. This will cause a call to
 * {@link #onScrollChanged(int, int, int, int)} and the view will be
 * invalidated.
 * @param x the amount of pixels to scroll by horizontally
 * @param y the amount of pixels to scroll by vertically
 */
public void scrollBy(int x, int y) {
    scrollTo(mScrollX + x, mScrollY + y);
}

        scrollBy实际上也是调用了scrollTo方法,它实现了基于当前位置的相对滑动,而scrollTo则实现了基于所传递参数的绝对滑动

        view如果从左向右滑动,那么mScrollX为负值,否则为正值;如果从上往下滑动,那么mScrollY为负值,否则为正值      

    View

使用动画

        通过动画可以让一个view进行平移,平移也可以说是一种滑动,使用动画来移动view,主要是操作view的translationX和translationY属性,既可以采用传统的view动画,也可以使用属性动画

改变布局参数

        如果想给button向右移动,只需要将这个button的LayoutParams里的marginLeft参数的值增加100px即可

ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) button.getLayoutParams();
params.width += 100;
params.leftMargin += 100;
button.setLayoutParams(params);

 

三种滑动方式的对比:

  • scrollTo/scrollBy:操作简单,适合对View内容的滑动;
  • 动画:错做简单,主要适用于没有交互的View和实现复杂的动画效果;
  • 改变布局参数:操作稍微复杂,适用于有交互的View

转载于:https://my.oschina.net/u/3705875/blog/1788946