Android实现滑动的几种方法

来源:互联网 发布:哪个淘宝课程好 编辑:程序博客网 时间:2024/09/21 09:29
下面通过一个例子来总结实现滑动的几种方式,例子的主要功能就是让我们的自定义View能够随着手指的移动而移动。
布局文件如下:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="match_parent">    <com.scu.lly.dragviewtest.view.DragView        android:layout_width="100dp"        android:layout_height="100dp" /></LinearLayout>

方式一:layout方法

在View进行绘制时,会调用onLayout()方法来设置显示的位置,因此,我们可以通过修改View的left、top、right、bottom四个属性来控制View的坐标。要控制View随手指滑动,因此需要在onTouchEvent()事件中进行滑动控制。代码如下:
public class DragView extends View{    private int mLastX;    private int mLastY;    public DragView(Context context) {        super(context);        init();    }    public DragView(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public DragView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    private void init(){        setBackgroundColor(Color.BLUE);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        int x = (int) ev.getX();        int y = (int) ev.getY();        switch (ev.getAction()){            case MotionEvent.ACTION_DOWN:                mLastX = x;                mLastY = y;                break;            case MotionEvent.ACTION_MOVE:                int offsetX = x - mLastX;                int offsetY = y - mLastY;                //调整layout的四个坐标                layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);                break;        }        return true;    }}

方式二:offsetLeftAndRight()和offsetTopAndBottom()

这两个方法其实是对上面那种layout设置方式的封装、简化,在layout中,左left、右right两个方向都是加上offsetX,上top、下bottom两个方向都是加上offsetY,为了简化设置四个方向,Android提供了offsetLeftAndRight()来代替左右方向的设置,用offsetTopAndBottom()来代替上下方向的设置。
我们只需要修改上面代码ACTION_MOVE的部分,如下:
<span style="white-space:pre"></span>case MotionEvent.ACTION_MOVE:                int offsetX = x - mLastX;                int offsetY = y - mLastY;                //调整layout的四个坐标                //layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);                //使用简写形式                offsetLeftAndRight(offsetX);                offsetTopAndBottom(offsetY);                break;

方式三:LayoutParams

LayoutParams保存了一个View的布局参数,因此我们可以通过动态改变LayoutParams中的布局参数来达到改变View的位置效果。通过getLayoutParams()方法来获取View的LayoutParams,这里获取到的LayoutParams需要根据View所在父布局的类型来设置不同的类型,比如,我们这个自定义View是放在LinearLayout中的,那么通过getLayoutParams()获取到的就是LinearLayout.LayoutParams。因此,通过getLayoutParams()获取到LayoutParams的前提就是这个View需要有一个父布局。
同样,我们只需要修改上面代码ACTION_MOVE的部分,如下:
case MotionEvent.ACTION_MOVE:    int offsetX = x - mLastX;    int offsetY = y - mLastY;    LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) getLayoutParams();    lp.leftMargin = getLeft() + offsetX;    lp.topMargin = getTop() + offsetY;    setLayoutParams(lp);    break;
可以看到,通过LayoutParams改变一个View的位置时,改变的是这个View的Margin属性,这也是为什么这种方式一定要有父布局的原因,只有有了父布局,margin属性的设置才会起作用。
对于使用LayoutParams这种方式改变View位置,如果我们不想考虑父布局的类型,还可以使用ViewGroup.MarginLayoutParams来进行设置,这样也更加方便。如下:
case MotionEvent.ACTION_MOVE:    int offsetX = x - mLastX;    int offsetY = y - mLastY;    //LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) getLayoutParams();    ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) getLayoutParams();    lp.leftMargin = getLeft() + offsetX;    lp.topMargin = getTop() + offsetY;    setLayoutParams(lp);    break;
效果是一样的。

方式四:scrollTo与scrollBy

关于scrollTo()和scrollBy()方法,我这篇文章《Android Scroller大揭秘》中有详细介绍。

使用scrollTo()和scrollBy()方法需要注意的一点是,scrollTo()和scrollBy()方法移动的是View的content,即让View的内容移动,如果在ViewGroup中使用scrollTo()和scrollBy()方法,那么移动的将是所有的子View,如果在View中使用,那么移动的将是View的内容。例如,TextView,content就是它的文本,ImageView,content就是它的drawable对象。

因此,上面例子中我们如果直接这样使用:
scrollBy(offsetX,offsetY);
发现View并没有移动,但其实是发生了移动的,只不过此时移动的是View中的内容,而我们例子中的content什么也没有。
所以,我们要想使这个View发生移动,我们就应该在View所在的ViewGroup中使用scrollBy或scrollTo方法来进行移动。同时,使用者两个方法进行移动的时候,注意此时的坐标方向与平常是相反的,具体在《Android Scroller大揭秘》有讲解。代码如下:
case MotionEvent.ACTION_MOVE:    //int offsetX = x - mLastX;    //int offsetY = y - mLastY;    //此时,计算坐标是相反的    int offsetX = mLastX - x;    int offsetY = mLastY - y;    //让View所在的ViewGroup进行移动    ((View)getParent()).scrollBy(offsetX,offsetY);     break;

方式五:Scroller

通过Scroller这个辅助类,配合scrollTo和scrollBy可以实现一些更加高级的滑动效果,关于Scroller类的具体介绍,同样在这篇文章中有详解《Android Scroller大揭秘》。

这里,我们只是结合上面这个例子实现一个简单的功能,当我们滑动完毕抬起手指后,View自动回弹到原来的位置。代码如下:
public class DragView extends View{private int mLastX;    private int mLastY;    private Scroller mScroller;    public DragView(Context context) {        super(context);        init(context);    }    public DragView(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);    }    public DragView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(context);    }    private void init(Context context){        setBackgroundColor(Color.BLUE);        mScroller = new Scroller(context);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        int x = (int) ev.getX();        int y = (int) ev.getY();        switch (ev.getAction()){            case MotionEvent.ACTION_DOWN:                mLastX = x;                mLastY = y;                break;            case MotionEvent.ACTION_MOVE:                //int offsetX = x - mLastX;                //int offsetY = y - mLastY;                //此时,计算坐标是相反的                int offsetX = mLastX - x;                int offsetY = mLastY - y;                //让View所在的ViewGroup进行移动                ((View)getParent()).scrollBy(offsetX,offsetY);                break;            case MotionEvent.ACTION_UP:                View viewGroup = (View) getParent();                mScroller.startScroll(viewGroup.getScrollX(),viewGroup.getScrollY(),-viewGroup.getScrollX(),-viewGroup.getScrollY());                //记住需要invalidate                invalidate();                break;        }    return true;}    @Override    public void computeScroll() {        super.computeScroll();        if(mScroller.computeScrollOffset()){            ((View)getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());        //记住,需要不断调用invalidate进行重绘        invalidate();        }    }}

以上五种方法就是常用的滑动View的方法。还有两种方式能够控制一个View的移动效果:属性动画和使用ViewDragHelper,对于这两种方法,大家可以查阅网上资料,就不详细介绍了。

(以上内容来源于看《Android群英传》的总结)



10 2
原创粉丝点击