View的滑动

在熟悉了View的基础知识之后,下面看一下 View 的滑动。

在 Android 设备中,滑动是必不可少的部分;因为手机屏幕是有限的,如果想呈现更多的内容,需要通过滑动来实现显示和隐藏一些内容,因此掌握基础的滑动是很有必要的。(部分内容摘自Android开发艺术探索)

我们实现滑动效果有三种常用的方式:第一种是通过 View 自身的 scrollTo/scrollBy 方法实现滑动效果;第二种是通过动画 ( 如: 补间动画) 来实现动画的效果;第三种是通过改变 View 的 LayoutParams 使 View 重新布局来实现滑动。

 

1. 使用 scrollTo/scrollBy 方法

为了实现 View 的滑动,View 提供了两个专门的方法,要想了解这两个方法,必不可少的要看它的源码:

12407    /**
12408     * Set the scrolled position of your view. This will cause a call to
12409     * {@link #onScrollChanged(int, int, int, int)} and the view will be
12410     * invalidated.
12411     * @param x the x position to scroll to
12412     * @param y the y position to scroll to
12413     */
12414    public void scrollTo(int x, int y) {
12415        if (mScrollX != x || mScrollY != y) {
12416            int oldX = mScrollX;
12417            int oldY = mScrollY;
12418            mScrollX = x;
12419            mScrollY = y;
12420            invalidateParentCaches();
12421            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
12422            if (!awakenScrollBars()) {
12423                postInvalidateOnAnimation();
12424            }
12425        }
12426    }
12427
12428    /**
12429     * Move the scrolled position of your view. This will cause a call to
12430     * {@link #onScrollChanged(int, int, int, int)} and the view will be
12431     * invalidated.
12432     * @param x the amount of pixels to scroll by horizontally
12433     * @param y the amount of pixels to scroll by vertically
12434     */
12435    public void scrollBy(int x, int y) {
12436        scrollTo(mScrollX + x, mScrollY + y);
12437    }

不难看出 scrollBy 方法内执行了 scrollTo 方法,来看一下这两个方法。

scrollTo/scrollBy 方法只能改变 View 内容的位置而不能改变 View 在布局中的位置。

 

先看两个方法内需要传的两个参数:

第一个参数 x :当前位置横向移动的距离,为正值向左运动,为负值向右运动。

第二个参数 y :当前位置纵向移动的距离,为正值向上运动,为负值向下运动。

 

两个方法中的 mScrollX 和 mScrollY 又是什么呢?

mScrollX :水平滚动视图内容的偏移量,以像素为单位,为正值向左运动,为负值向右运动。

mScrollY :竖直滚动视图内容的偏移量,以像素为单位,为正值向上运动,为负值向下运动。

 

那么在滑动过程中,mScrollX 和 mScrollY 这两个值是如何变化的呢?

mScrollX :总是等于 View 左边缘和 View 内容左边缘在水平方向的距离。

mScrollY :总是等于 View 上边缘和 View 内容上边缘在竖直方向的距离。

 

拿 View 初始坐标为 (0,0) 来说,从而更好的理解 mScrollX 和 mScrollY 值的变化;

如果 View 由左向右移动 100 个像素:View 左边缘初始值为 0,移动 100 像素后,View 左边缘值变为 100;mScrollX 为 -100;

如果 View 由上向下移动 100 个像素:View 上边缘初始值为 0,移动 100 像素后,View 上边缘值变为 100;mScrollY 为 -100;

具体看下图:

查看源图像

 

理解了这其中的参数后,那么 scrollTo 和 scrollBy 方法,有什么区别呢?

scrollTo :让 View 相对于初始的位置滚动某段距离;

scrollBy :让 View 相对于当前的位置滚动某段距离;

这么说不容易明白,下面是写了一个 Demo 的效果图,可以更好的理解这两个方法,代码就不给出了:

mScrollX 和 mScrollY滑动就介绍到这里。

 

2.  使用动画

下面介绍另一种能够让 View 进行移动的方法:使用动画。

相信动画都不陌生:逐帧动画、补间动画和属性动画。

如果还不了解可以先看下:补间动画的使用逐帧动画与属性动画的使用

 

下面通过补间动画来实现一下 View 的移动,先看下效果图:

上面动画有些卡顿,实际是没有卡顿的。来看下是如何实现的,首先定义了动画:

<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:fromXDelta="0"
    android:fromYDelta="0"
    android:toXDelta="300"
    android:toYDelta="300" />
    <!-- 位移 -->
    <!--
     fromXDelta:动画起始位置的X坐标
     toXDelta:动画起结束位置的X坐标
     fromYDelta:动画起始位置的Y坐标
     toYDelta:动画结束位置的Y坐标
     -->

 

然后使用动画就可以了:

public class RJPActivity extends Activity {
    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.item_rjp);
        textView = findViewById(R.id.textView);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Animation animation = AnimationUtils.loadAnimation(RJPActivity.this,
                        R.anim.translate);
                //保证动画运动之后停留在此处
                animation.setFillAfter(true);
                view.startAnimation(animation);
            }
        });
    }
}

实现之后,要注意几个问题,我们为了保证动画在运动之后 View 停留在此处,需要将动画的 FillAfter 属性设置为 true ;

补间动画只是对 View 影像操作,View 的实际位置并没有改变,这样就会导致这个 View 的点击事件在移动后失效;所以 Android 为我们提供了另外一个动画:属性动画;属性动画可以解决上面的问题。

属性动画的位移就不再给出示例了,想了解的可以自己试一试。

 

3. 改变布局参数

这个就很好理解了,比如我想将一个 Button 向右平移 100 px,那么只要将这个 Button 的 LayoutParams 的 marginLeft 参数值增加 100 px 即可。

还有另外一种方法,在 Button 左侧放一个空的 View ,将此 View 的宽度设置为 0 ,当我们向右移动 Button 时,只需要重新设置 View 的宽度即可。先看一下效果图:

实现也很简单,只需要在相应的地方加入下面代码即可:

ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) button.getLayoutParams();
params.leftMargin += 100;
button.requestLayout();
//或 button.setLayoutParams(params);

 

4. View 跟手滑动

View 跟随手滑动,先看效果图:

下面来看一下是如何达到效果的,下面是 Activity 的核心代码:

public class RJPActivity extends Activity implements View.OnTouchListener {
    private Button button;
    private int lastX, lastY;//停下来的坐标
    private int moveX, moveY;//手指移动的像素
    private int getX, getY;//最终控件距离父布局左边距离和右边距离
    private LinearLayout.LayoutParams layoutParams;//获取到父布局

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.item_rjp);
        button = findViewById(R.id.button);
        button.setOnTouchListener(this);
        layoutParams = (LinearLayout.LayoutParams) button.getLayoutParams();

    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //手指按下坐标
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                //手指移动的像素
                moveX = (int) event.getRawX() - lastX;
                moveY = (int) event.getRawY() - lastY;
                //最终控件距离父布局左边距离和右边距离
                getX = view.getLeft() + moveX;
                getY = view.getTop() + moveY;
                //设置据左边/上边的距离
                layoutParams.leftMargin = getX;
                layoutParams.topMargin = getY;
                view.setLayoutParams(layoutParams);
                //停下来的坐标
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_UP:
                break;
            default:
                break;
        }
        //更新视图
        view.invalidate();
        return true;
    }
}

布局文件很简单,里面只有一个 Button 就不再给出了。上面注释写的很清楚,不再分析步骤了。

下面来简单的分析一下上面的代码中的一些方法 :

getRawX/getRawY :获取手指当前的坐标;
getLeft/getTop :视图相对于父布局左/上坐标;

这里不要与 getX/getY 方法搞混了,getX/getY 方法是获取的视图的坐标。

 

到这里对 View 的滑动讲解就结束了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值