关闭

实现View滑动的七种方式记录

标签: androidview
163人阅读 评论(0) 收藏 举报
分类:

实现View滑动的七种方式记录

效果图:由于每种实现方式的效果基本上是一模一样的,所以只演示一个效果图

实现方式都是采用自定义View的方法,监听onTouchEvent方法,计算位移,然后采用不同的方式来将View进行位移

一 . layout方法

实现原理:

View在其父组件的位置是由父组件的onLayout方法确定的,其实View本身也可以通过相同的方法确定本身的位置,这个方法就是layout,参数与onLayout一样。而View当前的坐标可由getLeft,getTop,getRight,getBottom来确定,再加上偏移值即可确定滑动之后的位置。

onTouchEvent方法实现代码

private int mLastX = 0;
    private int mLastY = 0;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //记住开始时候的坐标
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //获取坐标偏移值
                int offsetX = x - mLastX;
                int offsetY = y - mLastY;
                layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
                break;
        }
        return true;
    }

二.offsetLeftAndRight()``和offsetTopAndBottom()“方法

此方法相当于对layout方法的方向上的封装,实现原理与第一种方式一样,直接贴代码:

private int mLastX = 0;
    private int mLastY = 0;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                int offsetX = x - mLastX;
                int offsetY = y - mLastY;
                offsetLeftAndRight(offsetX);
                offsetTopAndBottom(offsetY);
                break;
        }
        return true;
    }

三 .LayoutParams方法

LayoutParams保存的是View的布局参数,因此可以通过改变LayoutParams的参数来改变View的位置。原理与第一种方法一样,不同的只是对偏移量的处理,处理偏移量的代码如下:

ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) getLayoutParams();
params.leftMargin = getLeft() + offsetX;
params.topMargin = getTop() + offsetY;
setLayoutParams(params);

四.scrollTo , scrollBy方法

scrollTo()``所需要的参数是要滚动到位置的绝对坐标,scrollBy()`所需参数是与当前坐标的偏移坐标。但是这种方式作用的对象不是View`本身,而是其父组件,并且父组件移动的方式与View的方式不一样,因为当父组件移动的时候,其内部的其他View也是在一起移动的,所以想使View向右移动的话需要将父组件向左移动,上下移动也是一样的。

处理坐标偏移量的代码:

 ((View) getParent()).scrollBy(-offsetX, -offsetY);

五.Scroller方法

Scroller能实现平滑移动的效果,所以这个例子实现的是手指拖动来移动,然后松开手指的时候平滑移动到原本的位置,与scrollTo方法一样,Scroller作用的也是其父组件。

Scroller的使用步骤:

1.初始化Scroller

mScroller = new Scroller(context);

2.重写computeScroll()``方法,实现方式还是父组件的scrollTo方法,但是可以通过Scroller获取当前应该移动到的坐标点,移动之后需要调用重绘,因为computeScroll方法只会在onDraw()内被调用,当Scroller`判断移动完毕的时候就会停止移动。

@Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.computeScrollOffset()) {
            View parent = (View) getParent();
            parent.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            //通过重绘来不断调用computeScroll
            invalidate();
        }
    }

3.开启滚动:

开启滚动的方法如下:

public void startScroll(int startX , int startY , int dx , int dy , int duration);
public void startScroll(int startX , int startY , int dx , int dy );

参数分别为:当前X上的滚动值,当前Y上的滚动值,要滚动的X上的偏移值,要滚动的Y上的偏移值,滑动持续的时间。

View滚动到原本的位置的代码:

case MotionEvent.ACTION_UP:
                View parent = (View) getParent();
                mScroller.startScroll(parent.getScrollX(), parent.getScrollY() ,- parent.getScrollX(), -parent.getScrollY(),2500);
                //激活滑动操作
                invalidate();
                break;

六.属性动画

效果图:

这个不用多说,不能像之前一样随手指一动(就算可以实现我想应该没人会这样做),演示效果是点击View之后View自动平滑的向下移动。

动画xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0%"
        android:fromYDelta="0%"
        android:toXDelta="60%p"
        android:toYDelta="60%p"/>
</set>

动画的使用代码:

mView.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.trans_back);
               animation.setDuration(2500);
               mView.startAnimation(animation);
           }
       });

七.ViewDragHelper方法

ViewDragHelper在自定义ViewGroup中应用很多,功能非常强大,官方的DrawerLayoutSlidePaneLayout就主要是ViewDragHelper实现的。

本次实现的效果还是跟随手指移动,是自定义ViewGroup。步骤如下:

Activity的布局中会在这个ViewGroup中添加一个View用于演示滑动,在开始以下步骤之前进行其他处理,如View的位置和初始化等的。

1.初始化ViewDrahHelper

mHelper = ViewDragHelper.create(this, new ViewDragHelper.Callback() {
            //决定那个View参与滑动
            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                return child == mView;
            }
            //指定当滑动的坐标变化的时候要滑动的View在X坐标上应该怎么样变化
            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                return top;
            }
            //指定当滑动的坐标变化的时候要滑动的View在Y坐标上应该怎么样变化
            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                return left;
            }
        });

2.拦截事件

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mHelper.processTouchEvent(event);
        return true;
    }

3.处理computeScroll

@Override
    public void computeScroll() {
        if (mHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

完毕。

ViewGroup的完整代码

public class MethodView7 extends ViewGroup {
    private View mView;
    private ViewDragHelper mHelper;

    public MethodView7(Context context) {
        this(context, null);
    }

    public MethodView7(Context context, AttributeSet attrs) {
        super(context, attrs);
        mHelper = ViewDragHelper.create(this, new ViewDragHelper.Callback() {
            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                return child == mView;
            }

            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                return top;
            }

            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                return left;
            }
        });
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mView = getChildAt(0);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mHelper.processTouchEvent(event);
        return true;
    }

    @Override
    public void computeScroll() {
        if (mHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        mView.layout(16, 16,  216, 216);
    }
}

七种方法完毕.

Demo地址

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:98056次
    • 积分:1991
    • 等级:
    • 排名:第19661名
    • 原创:94篇
    • 转载:0篇
    • 译文:0篇
    • 评论:68条
    博客专栏
    最新评论