[读书笔记之安卓开发艺术探索]View的事件体系前的知识准备

零碎的知识

View的位置参数

  • x,控件左上角在父容器中的x坐标像素值
  • y,控件左上角在父容器中的y坐标像素值
  • translationX,存在平移过程,控件在x轴上偏移的像素值
  • translationY,存在平移过程,空间在y轴上偏移的像素值
  • left,控件左上角在父容器中横坐标的像素值
  • right,控件左上角在父容器中纵坐标的像素值
  • top,控件右下角在父容器中横坐标的像素值
  • bottom,控件右下角在父容器中横坐标的像素值
  • scrollX,控件在x轴上滑动的长度(px)
  • scrollY,控件在y轴上滑动的长度(px)

存在如下关系如下:
x = left + translationX;
y = right = translationY;
scrollX = getScrollX;
scrollY = getScrollY;

TouchSlop

表示系统所能识别的最小滑动距离。通过以下方法获取:

ViewConfiguration.get(getContext()).getScaledTouchSlop()

VelocityTracker

用于跟踪手指在滑动过程中的速度,包括水平和竖直方向的速度。获取如下所示

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

velocityTracker.computeCurrentVelocity(1000);
float x = velocityTracker.getXVelocity();
float y = velocityTracker.getYVelocity();

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

GestureDetector

如果只是坚挺滑动相关,倾向于在onTouchEvent中实现,如果要监听双击这样的行为,就是用GestureDetector

Scroller的使用

用于实现View的弹性滑动,配合在自定义View中重写ComputeScroll方法来共同达到这一功能。比如自定义一个线性布局,调用smoothScrollBy方法实现平滑滚动,代码如下:

public class ScrollerLinearLayout extends LinearLayout {

public static final String TAG = "ScrollerLinearLayout";

private Scroller mScroller;

public ScrollerLinearLayout(Context context) {
    super(context);
    mScroller = new Scroller(context);
}

public ScrollerLinearLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    mScroller = new Scroller(context);
}

public void smoothScrollTo(int dstX,int dstY){
    int dx = dstX - mScroller.getFinalX();
    int dy = dstY - mScroller.getFinalY();
    smoothScrollBy(dx,dy);
}

public void smoothScrollBy(int dx,int dy,int duration){
    //上一次的最后位置作为本次重绘的开始位置,故调用getFinalX方法而不是getStartX方法
    mScroller.startScroll(mScroller.getFinalX(),mScroller.getFinalY(),dx,dy,duration);
    invalidate();
}

@Override
public void computeScroll() {

    if(mScroller.computeScrollOffset()){
        int currX = mScroller.getCurrX();
        int currY = mScroller.getCurrY();

        scrollTo(currX,currY);

        postInvalidate();
    }

    super.computeScroll();
}
}

View的滑动

实现方式

使用scrollTo和scrollBy

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

滑动过程中,有两个属性值:mScrollX,mScrollY
通过getScrollX和getScrollY方法分别得到
mScrollX表示View左边缘到内容左边水平方向的距离
mScrollY表示View上边缘到内容上边竖直方向的距离

因此,scrollTo和scrollBy智能改变View的内容位置而不能改变View在布局中的位置。需要注意的是,使用scrollBy滑动,如果从左到右滑动,mScrollX为负值,从上往下滑动,mScrollY为负值。(前一个值减去后一个值)

使用动画

通过动画,我们能够让一个View进行平移,而平移就是一种滑动。通过操作View的translationX和translationY属性(因此View的平移,是在其父容器中移动),补间动画或属性动画都可以实现效果。

使用动画来做View的滑动需要注意的事项
补间动画是对View的映像做操作,它并不能真正改变View的位置参数,包括宽/高(如果需要View保留最后的动画状态,fillAfter置为true),因为View对应的位置信息(top,left,right,button)并没有改变,改变的只是translationX,translationY,x,y的值,而点击事件的位置根据View的位置信息来操作。对比属性动画,它是通过改变属性形成的动画,但是属性动画也存在不足,它只适用在Android 3.0以上。

改变布局参数

改变LayoutParams。

比如如果想让一个Button右移100px

  • LayoutParams里让marginLeft参数值为100px即可。
  • 在Button左边放置一个空的View,这个空View默认宽度为0,慢慢增加View的宽度,Button根据父容器的对齐方式,挤向另一边。

涉及到的API: ViewGroup.LayoutParams,ViewGroup.MarginLayoutParams

弹性滑动

将一次大的滑动分成若干次小的滑动并在一个时间段内完成。实现方式有:Scroller;Handler&postDelay;Thread&sleep。

使用Scroller

工作机制

当我们构造一个Scroller对象并且调用startScroll方法时,Scroller内部其实什么也没做,它只是保存了我们传递的参数。invalid方法会导致View重新绘制,即调用draw方法,draw方法里会调用computeScroll方法,这个方法需要我们去重写,在该方法里,调用scroller.computeScrollOffset方法,这个方法内部有时间因子(时间插值器),得到当前滑动的currX和currY,然后通过scrollTo方法实现滑动,接着又调用postInvalide方法进行第二次重绘。第二次重绘和第一次重绘过程一样。如此循环,直到滑动结束,computeScrollOffSet返回false。

通过动画

动画具有天然的弹性滑动

借鉴Scroller机制,通过ValueAnimator的onAnimationUpdate方法里,引入时间因子(Fraction)获取到每时每刻滑动的偏移量,再配合scrollTo/scrollBy,来完成也行。

使用延时策略

通过发送一系列延时的消息从而达到一种渐进式的效果。
具体实现方法:

  • 使用Handler或View的postDelayed方法。
  • while循环加sleep
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值