Android UI-移动和滑动效果(二)

概述

上一篇博客中,我们讲了View移动动画各个方法的不同原理。那么这一篇具体讲下移动和滑动效果的具体实现。
这篇中主要简介五中主要的实现移动和滑动效果的方法。1、通过LayoutParams方法2、通过scrollTo和scrollBy方法3、通过Scroller方法4、通过属性动画

LayoutParams

LayoutParams中保存了View的布局参数,所以可以直接通过修改LayoutParams来修改位置参数,从而达到改变View位置的效果。在这里要注意的是,一般我们会拿到View的父控件类型相对应的LayoutParams来进行设置(如RelativeLayout.LayoutParams),不然运行时会产生异常。只要谁知Margin的话,也可以拿MarginLayoutParams,而不用去管父控件的类型。下面就用代码来尝试一下。
布局,只是一个简单的RelativeLayout中有一个View:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary_1">

    <View
        android:id="@+id/view_layoutparams"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:background="@color/colorAccent_1" />
</RelativeLayout>

代码,在代码中动态设置View的margin值:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_layout_params);
        View view_layoutparams =  findViewById(R.id.view_layoutparams);
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view_layoutparams.getLayoutParams();
        params.leftMargin= view_layoutparams.getLeft()+100;
        view_layoutparams.setLayoutParams(params);
        view_layoutparams.requestLayout();
    }

效果如下:


image.png

可以看到,我们设置了marginLeft,然后界面就向右移动了100px的距离。同样我们可以通过MarginLayoutParams;来完成这件事情:

ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view_layoutparams.getLayoutParams();
        params.leftMargin= view_layoutparams.getLeft()+100;
        view_layoutparams.setLayoutParams(params);
        view_layoutparams.requestLayout();

到这里大家应该可以发现,其实MarginLayoutParams应该是RelativeLayout.LayoutParams等具体控件所对应的LayoutParams的父类。

ScrollTo和ScrollBy

scrollTo和scrollBy的原理前面一篇博客已经讲到过了。这里我们直接用代码来做演示。
布局和LayoutParams的代码没有区别。看下Activity中的代码,非常简单,只有一行:

((View)view_layoutparams.getParent()).scrollBy(-100,-100);

上篇讲到,scrollTo和scrollBy方法只能改变View中的内容的位置。所以我们先拿到了父控件,然后对父控件进行scroll操作。
讲到这里,我们发现我们讲的都是静态设置控件的位置,然而我们需要的是能够动态滑动的效果。街小区的Scroller这个类,能够很好地帮忙解决这个问题。

Scroller

使用Scroller能够实现平滑的滑动效果,而不会像直接使用LayoutParams和ScrollTo那么突兀。其实Scroller和ScrollTo有着非常大的联系。那么我们就看下代码上怎么实现。由于Scroller需要结合computeScroll使用,所以我们先自定义一个View:

public class ScrollerView extends View {

    public ScrollerView(Context context) {
        super(context);
        init(context);
    }

    public ScrollerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public ScrollerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    Context mContext;
    //定义一个Scroller
    private Scroller mScroller;

    private void init(Context context) {
        mContext = context;
        mScroller = new Scroller(mContext);
    }
    //写一个public的调用方法
    public void startScroll(int startX,int startY,int dx,int dy,int duaration){
        mScroller.startScroll(startX,startY,dx,dy,duaration);
    }

    // 继承computeScroll方法,实现滑动的功能
    @Override
    public void computeScroll() {
        //这个方法计算当前的位置,并判断是否已经执行完毕,如果完毕则返回false
        if(mScroller.computeScrollOffset()){
            // 具体做动画的地方
            ((View)getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
            //这句代码一定要加,不然无法实现滑动的效果
            postInvalidate();;
        }
    }
}

在Activity中执行

ScrollerView view_scroller = (ScrollerView) findViewById(R.id.view_scroller);
        view_scroller.startScroll(0, 0, -1000, 0, 6000);

来看下具体的效果

1.gif

具体的Scoller的执行原理网上已经有很多的博客解释过,这里不再详细讲解,只是简单介绍下原理。我们只看下computeScrollOffset中的一句代码:

int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);

看到这句代码,相信大家已经猜到了计算当前位置的方式,就是通过当前的时间减去开始的时间,再除以我们设置的duration时间。这样就可以计算出当前的位置所在,那么还有一个问题,如何定时或者不定时更新界面呢,这就是postInvalidate这个方法的威力了。在调用postInvalidate方法的过程中,会导致View的重回,重绘时会调用comoputeScroll方法,这样我们就又回到方法中,根据当前的时间重新计算位置,然后执行滑动操作。非常巧妙的一个方法。
既然ScrollTo可以,那么我们也来试一下LayoutParams来执行滑动。
修改一下代码:

        if (mScroller.computeScrollOffset()) {
            //((View)getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
            ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) getLayoutParams();
            params.leftMargin = mScroller.getCurrX();
            setLayoutParams(params);
            postInvalidate();
        }

也可以实现同样的效果,但是两种实现方式的原理稍微有点不一样,ScrollTo是改变了mScrollX和mScrollY的值,而LayoutParams是改变了整体的布局参数。

属性动画

属性动画的原理和简单的实现上篇博客已经讲过,这里来具体看下代码:

View view_animation = findViewById(R.id.view_animation);
ObjectAnimator.ofFloat(view_animation, "translationX", 0, 1000).setDuration(6000).start();

效果如下:


GIF.gif

这种方式非常简单,只要一行代码就可以实现。也可以使用ValueAnimation来做动画,下面是一个具体的例子,这里ValueAnimator只是计算了fraction,没有执行具体的动画。查看源码可以知道,这个过程是用handler来执行的。

ValueAnimator animator = ValueAnimator.ofInt(0, 1).setDuration(6000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
            float f = animation.getAnimatedFraction();
        ((View) view_animation.getParent()).scrollTo(-(int) (f * 1000), 0);
    }
});
animator.start();

总结

这篇是对上篇原理篇的补充,两篇合起来讲了Android的位置属性,并介绍了简单的滑动效果的处理。后续会减少更加 深入的动画和UI实现过程。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,448评论 25 707
  • 内容是博主照着书敲出来的,博主码字挺辛苦的,转载请注明出处,后序内容陆续会码出。 当了解了Android坐标系和触...
    Blankj阅读 6,626评论 3 61
  • 什么是View View 是 Android 中所有控件的基类。 View的位置参数 View 的位置由它的四个顶...
    acc8226阅读 1,149评论 0 7
  • 导语 滑动算是Android比较常用的效果了,滑动的操作具有很好的用户体验性。 主要内容 滑动效果是如何产生的 实...
    一个有故事的程序员阅读 6,432评论 3 11
  • 在晚霞褪去的时候 我会将思念点燃 熊熊之火献祭着黑夜 烈焰将我的爱沸腾 熬煮着我的浓情 也许我的生命 在今晚耗竭 ...
    潜水的鸟阅读 238评论 0 3