一、View基础知识
TouchEvent
getX/getY 相对当前View左上角的坐标
getRawX/getRawY 相对手机屏幕左上角的坐标
TouchSlop
系统能识别滑动的最小距离
ViewConfiguration.get(getContext()).getScaledTouchSlop()
源码在frameworks/base/core/res/res/values/config.xml中config_viewConfigurationTouchSlop作了定义
VelocityTracker
速度追踪
在onTouchEvent()中追踪当前点击事件的速度
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
velocityTracker.computeCurrentVelocity(1000);
int xVelocity = (int)velocityTracker.getXVelocity();
int yVelocity = (int)velocityTracker.getYVelocity();
获取速度需要设置时间间隔:computeCurrentVelocity();
手指从右向左滑动时,水平方向速度即为负值
1s内从左向右滑动100,那么速度就是100每秒
对象回收
velocityTracker.clear();
velocityTracker.recycle();
GestureDetector
手势检测
创建GestureDetector
GestureDetector mGestureDetector = new GestureDetector(this);
// 解决长按屏幕无法拖动
mGestureDetector.setIsLongpressEnabled(false);
接管View的onTouchEvent()
return mGestureDetector.onTouchEvent(event);
Scroll
View本身不会移动,只能移动View内容,相当于屏幕相对于View的移动
二、View滑动方式
改变布局参数(非弹性滑动)
MarginLayoutParams params = (MarginLayoutParams)mButton.getLayoutParams();
params.width += 100;
params.leftMargin += 100;
// 方法一
mButton.requestLayout();
// 方法二
mButton.setLayoutParams(params);
弹性滑动就是将一个大的滑动分成若干个小的滑动,并在一个时间段内完成
Scroller
Scroller scroller = new Scroller(mContext);
private void smoothScrollTo(int destX, int destY){
int scrollX = getScrollX();
int deltaX = destX - scrollX;
// 滑动的位置-当前位置就是1000ms内滑动的距离
mScroller.startScroll(scrollX, 0, deltaX, 0, 1000);
invalidate();
}
@Override
public void computeScroll(){
if(mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
配置滑动相关参数startScroll()
invalidate()导致View重绘,draw方法调用computeScroll(),
computeScroll()方法内部
computeScrollOffset()根据时间流逝百分比计算scrollX和scrollY值,返回true表示滑动未结束
通过scrollTo()滑动到新的位置
postInvalidate()发起新的重绘
动画的方式
Android3.0+增加了x,y,translationX,translationY几个属性,x,y表示左上角坐标,translationX,translationY表示偏移量
利用设置偏移量改变View位置
setTranslationX(translationX);
setTranslationY(translationY);
兼容3.0-,但本质仍然是View动画
ViewHelper.setTranslationX(this, translationX);
ViewHelper.setTranslationY(this, translationY);
100ms内向右移动100像素
ObjectAnimator.ofFloat(targetView, "translationX", 0, 100).setDuration(100).start();
final int startX = 0;
final int deltaX = 100;
ValueAnimator animator = ValueAnimator.ofInt(0,1).setDuration(1000);
animator.addUpdateListener(new AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator animator){
float fraction = animator.getAnimatedFraction();
mButton.scrollTo(startX + (int)(deltaX*fraction), 0);
}
});
animator.start();
动画没有作用于任何对象,只是在1000ms内完成整个过程
动画滑动示例
public class TestButton extends TextView{
private int mLastX;
private int mLastY;
public TestButton(Context context) {
this(context, null);
}
public TestButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TestButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
int mScaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
Log.d("", "滑动最小距离:"+ mScaledTouchSlop);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getRawX();
int y = (int) event.getRawY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
int deltaX = x - mLastX;
int deltaY = y - mLastY;
Log.d("","移动距离:"+deltaX + "---"+deltaY);
int translationX = (int) (getTranslationX() + deltaX);
int translationY = (int) (getTranslationY() + deltaY);
setTranslationX(translationX);
setTranslationY(translationY);
break;
case MotionEvent.ACTION_UP:
break;
}
mLastX = x;
mLastY = y;
return true;
}
}
通过Handler发送延时消息
Handler滑动示例
public class MainActivity extends AppCompatActivity {
private static final int message_scroll_to = 1;
private static final int frame_count = 30;
private int mCount = 0;
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
mCount++;
if(mCount <= frame_count){
float fraction = mCount/(float)frame_count;
int scrollX = (int) (fraction * 100);
button.scrollTo(scrollX, 0);
handler.sendEmptyMessageDelayed(message_scroll_to, 33);
}
}
};
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button);
handler.sendEmptyMessageDelayed(message_scroll_to, 33);
}
}