上述该图中四个参数left、top、bottom、right参数可以通过以下几个函数来获得:getLeft、getTop、getbottom、getRight。需要注意的是上述几个参数是相对于父容器的,例如:
这张图中去获取textView的四个参数,那么这四个参数是相对于RelativeLayout,而不是相对于LinearLayout的。
从Android3.0增加了几个参数:x、y、translationX、translationY,其中x和y是view左上角的坐标,而translationX和translationY是view左上角相对于父容器的偏移量,这几个参数也是相对于父容器的坐标,这几个参数分别有get\set方法,换算关系如下:
x = translationX + left;
y = translationY + top;
这里需要注意的是left和top表示的是原始左上角的位置信息,其值并不会改变,view平移时发生改变的是x、y、translationX、translationY。所以如果你的view位置不动的话,getX和getLeft的值是一样的。
另外:
width = right - left;
height = bottom - top;
手指触摸屏幕后产生一系列事件中,典型的事件类型有以下几种:
有的时候,我们需要监听view上的触摸事件,包括点击、快速滑动、长按、拖动等,有些人喜欢在onTouchEvent根据点击事件来判断,撰写比较麻烦,可以使用GestureDectector来监听,根据需要还可以实现onDoubleTapListener从而能够监听双击行为:
GestureDetector mGestureDetector = new GestureDetector(this);
mGestureDetector.setIsLongPressEnabled(false);
然后接管目标View的onTouchEvent方法,在onTouchEvent中添加如下实现:
boolean consume = mGestureDetector.onTouchEvent(event);
return consume;
例如触屏事件触发onDown函数,长按事件触发onLongPress函数等,具体可以查看onGestureListener和onDoubleTapListener接口。
1、onSingleTapUp、onSingleTapConfirmed
用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发
这个事件执行的顺序是onDown-》onShowPress-》onSingleTapUp
区别:
点击一下非常快的(不滑动)Touchup:onDown->onSingleTapUp->onSingleTapConfirmed
点击一下稍微慢点的(不滑 动)Touchup:onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed
2、onShowPress:用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发。它与onDown()的区别,强调的是没有松开或者拖动的状态
3、onDown:是由一个MotionEventACTION_DOWN触发的,但是他没有任何限制,也就是说当用户点击的时候,首先MotionEventACTION_DOWN,onDown就会执行,如果在按下的瞬间没有松开或者是拖动的时候onShowPress就会执行,如果是按下的时间超过瞬间(这块我也不太清楚瞬间的时间差是多少,一般情况下都会执行onShowPress),拖动了,就不执行onShowPress。
4、onLongPress:用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发,这个事件执行的顺序是onDown-》onShowPress-》onLongPress
5、onFling:用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE,1个ACTION_UP触发
6、onScroll:Touch了 滑动时触发。 等其他触碰事件。
有以下几种方式可以实现view的滑动,分别是:
下面一一说明。
先看下scrollTo和scrollBy的源码:
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();
}
}
}
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
可以看到scrollBy其实也是调用了scrollTo,区别就是scrollBy是根据相对位置移动,而scrollTo是移动到指定的位置,与原来位置没什么关系。
不过这两个方法移动的是view中的内容,而不是view。举个例子,如果是textview的话,那么滑动的是控件中的文字,而textview本身并不会移动。scrollTo很简单,就不多说了。那来解释下scrollBy中的变量mScrollX和mScrollY。
mScrollX和mScrollY记录的是当前view内容所处的位置(移动后所处的位置,一开始为0),这两个值分别有正值和负值。
mScrollX = view.left - viewcontent.left;
mScrollY = view.top - viewcontent.top;
这里的view.left指的是该view的左边框。viewcontent就指的是view内容的左边框。
看个例子就是移动TextView中的内容:
第二种使用动画的方法,分补间动画(Tween Animation)、帧动画(Frame Animation)和属性动画(Property Animation),如果采用补间动画的是,使用TranslationAnimation,它虽然改变了view的位置,但是对于view来说,点击事件有效区域还是在原来的地方,而不是跟随view一起移动,很不方便,这是因为它只是改变了view对象绘制的位置,而没有改变view对象本身。google意识到这个问题,就出了属性动画,通过修改view的属性。
如果要采用属性动画的话,为了兼容3.0以下的版本(因为3.0以下的版本不支持属性动画),需要采用开源动画库nineoldandroids(http://nineoldandroids.com)。但是虽然使用了开源动画库,属性动画的本质依旧是补间动画,所以一些点击事件还是无效,这还是有解决办法的。比如一个按钮向右移动10像素后,停留在移动后的位置,可以在移动位置事先放一个按钮(隐藏状态),然后当动画结束后,将原来的按钮隐藏,将实现安放好的按钮显示出来,狸猫换太子!
或者我们可以通过ValueAnimator,看下面的一段代码:
final int startX = 0, deltaX =100;
ValueAnimator animator = ValueAnimator.ofInt(0,1).setDuration(1000);
animator.addUpdateListener(new AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator animator){
float fraction = animator.getAnimationFraction();
mButton.scrollTo(startX + (int)(deltaX * fraction),0);
}
});
animator.start();
我们使用的ValueAnimator并没有直接作用于button上面,只是在动画的每一帧到达时获取动画完成的比例,根据这个比例算出移动的距离。
第三种方法就是动态改变view的layoutparams,这个很简单,像那种下拉刷新的listview,就是通过动态改变header的高度来实现的。这里不再赘述。
扩展:刚刚提到scrollTo和scrollBy,这个的确起到了滑动的效果,但是如何达到连续滑动的效果呢?
除了使用刚刚的ValueAnimator,还可以采用延时策略,它的核心思想就是通过发送一系列延时消息从而达到一种渐进式的效果,具体来说可以使用Handler或View的postDelayed方法,也可以使用线程的sleep方法。对于postDelayed方法来说,我们可以通过他来延时发送一个消息,在消息中实现对view的移动,如果接连不断的话,可以达到连续滑动到效果。对于sleep方法来说,在while循环中不断的滑动view和sleep,就可以实现弹性滑动的效果。