自定义View基础(二)View的滑动

Android 自定义View View的滑动


在移动设备上,滑动基本是基础特性。不管是用的最多的下拉刷新还是ViewPager,他们的基础都是滑动。View的滑动实现方法也是绚丽的自定义View的基础知识。

1、实现View滑动的三种方式

1.1使用ScrollTo/ScrollBy 首先我们来看一下这两个函数的源码:

public void scrollTo(int x, int y) {
        if (mScrollX != x || mScrollY != y) {
            int oldX = mScrollX;
            int oldY = mScrollY;
            //mScrollX总是等于View左边缘和View内容左边缘在水平方向的距离
            mScrollX = x;
            //mScrollY总是等于View上边缘和View内容边缘在竖直方向的距离
            mScrollY = y;
            invalidateParentCaches();
            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
            if (!awakenScrollBars()) {
                postInvalidateOnAnimation();
            }
        }
    }
    
public void scrollBy(int x, int y) {
        scrollTo(mScrollX + x, mScrollY + y);
    }

从源码可以看出,scrollBy也是调用的scrollTo方法。by是基于参数的相对滑动,而to是制定位置的决定滑动。 需要注意的是这两个方法只能改变View内容的位置而不能改变View在布局中的位置。

不同的是mScrollX当内容左边缘在View左边缘右边的时候为负值,左边为正值,同理mScrollY当内容上边缘在View上边缘上面的时候为正值,下面为正值。这就和View本身的坐标系统相反了。 比如这是一个Button填充内容是MovingButton:

改变前原View

mButton1.scrollTo(100, 0);

然后他的效果就是:

scrollTo后的View

1.2使用动画

ObjcetAnimator.ofFloat(targetView,"translationX",0,100).setDuration(100).start();

使用属性动画前:

使用属性动画前

使用属性动画后:

使用属性动画后

需要提一句的是,属性动画是3.0以后的特性,3.0以前的View动画只是对View的影像做操作,并不能真正改变View的位置参数。所以这种情况下如果有用户交互动作就不行,因为他看到的是View的影像,真正的View还停留在原本的位置,影像位置是不会响应点击操作的。

1.3 改变布局参数

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

这种方式的直接效果和上面的效果一致,但是动画有弹性缓冲动画,不像这种方式是一蹴而就的。

2、View滑动三种方式的对比

  • scrollTo/scrollBy:操作简单,但是局限明显,适合对View内容的滑动
  • 动画:操作简单,由于现在基本上都是3.0以上版本Android系统,所有可以适合几乎所有情况
  • 改变布局参数:操作稍微复杂,适用于几乎所有情况

3、弹性滑动和实现的三种方式

3.1使用Scroller 再看一遍Scroller的套路代码:

Scroller scroller = new Scroller(getContext());
    //缓慢滚动到制定位置
    private void smoothScrollTo(int destX ,int destY){
        int scrollX = getScrollX();
        int scrollY = getScrollY();
        int deltaX = destX - scrollX;
        int deltaY = destY - scrollY;
        scroller.startScroll(scrollX,scrollX,deltaX,deltaY,1000);
        invalidate();
    }

    @Override
    public void computeScroll() {
        if (scroller.computeScrollOffset()){
            scrollTo(scroller.getCurrX(),scroller.getCurrY());
            postInvalidate();
        }
    }

Scroller的源码还是很清晰的,建议大家看一看,关于这个类的理解上一篇讲过了,所有这里就不累述了。 地址:View的位置参数及其Scroller类的理解 3.2使用动画 就是属性动画的实现方式,再给大家贴出代码一边:

ObjcetAnimator.ofFloat(targetView,"translationX",0,100).setDuration(100).start();

3.3使用延时策略 延时策略有几种实现方式,可以直接有用Android的Handler机制实现的。

private static final int MESSAGE_SCROLL_TO = 1;
private static final int FRAME_COUNT = 25;
private static final int DELAYED_TIME = 50;

@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
    public void handleMessage(Message msg) {
        switch (msg.what) {
        case MESSAGE_SCROLL_TO: {
            mCount++;
            if (mCount <= FRAME_COUNT) {
                float fraction = mCount / (float) FRAME_COUNT;
                int scrollX = (int) (fraction * 100);
                mButton1.scrollTo(scrollX, 0);
                mHandler.sendEmptyMessageDelayed(MESSAGE_SCROLL_T
            }
            break;
        }
        default:
            break;
        }
    };
};

//触发延时机制
mHandler.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO, DELAYED_TIME);

也可以借助View动画API和scrollTo方法的实现方式,不过下面这种方法只是View内容的移动,如果要View的移动可能需要改变View的布局参数,这就很麻烦了。所有这里只是给出一点点思路和示意View内容弹性移动代码:

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();
mButton1.scrollTo(startX + (int) (deltaX * fraction), 0);
}
});
animator.start();

有心的同学,或者看过动画插值器原理的同学可能感觉这三种方式其实是一个原理就和插值器原理一样。很多源码我没有细究,但是现在看来他们的原理可以假定是一样的,以流逝的时间除去总的时间间隔得到一个动画距离目标完成的比例,然后根据比例真实的是动画完成的比例。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏向治洪

仿uc下部弹出菜单

先说说我怎么会无聊到这种地步去弄这个代码呢,在今年2月份的时候公司本来要做个这种弹出的菜单的,有5个按钮每个都有一个菜单,记得网上有仿UC菜单的源码,就下下来看...

24180
来自专栏Android机器圈

Android图片处理--全景查看效果

PS:Android对于图片处理这块资源还是挺多的,之前用OpenGL制作图片的全景效果,耗时耗力,而且只能点击进去后看到,但是效果是非常的号,今天所写的是编写...

24630
来自专栏Android开发指南

15.屏幕适配

41580
来自专栏Android知识点总结

Android控件之ImageView

张风捷特烈个人网站,编程笔记请访问:http://www.toly1994.com

9800
来自专栏androidBlog

你真的了解View的坐标吗?

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details/...

9820
来自专栏三好码农的三亩自留地

Android九宫格控件-可在ListView和RecyclerView中使用

熟悉Android App开发的同学,肯定都清楚,如果要显示多张图片,类似九宫格,可以用GridView或者GridLayout来做,但是如果需求要求在List...

33820
来自专栏jianhuicode

学问Chat UI(1)

前言 由于项目需要,最近开始借鉴学习下开源的Android即时通信聊天UI框架,为此结合市面上加上本项目需求列了ChatUI要实现的基本功能与扩展功能。 ? 融...

26490
来自专栏Android源码框架分析

仿淘宝、京东拖拽商品详情(可嵌套ViewPager、ListView、WebView、FragmentTabhost)实现效果图实现

23130
来自专栏androidBlog

使用CoordinatorLayout打造各种炫酷的效果

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details...

1.6K10
来自专栏玩转全栈

Android如何实现超级棒的沉浸式体验

做APP开发的过程中,有很多时候,我们需要实现沉浸式的体验。

1.6K240

扫码关注云+社区

领取腾讯云代金券