View滑动

一、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);

    }
}

  

posted @ 2016-08-01 15:08  轻云沉峰  阅读(123)  评论(0)    收藏  举报