简单实现android炫酷注册页面动画

来源:互联网 发布:杭州电信网络缴费地点 编辑:程序博客网 时间:2024/05/19 16:21

最近比较闲,再加上以前懒惰的习惯,决定尽量保持几天一篇博客,这次简单实现一下这个效果.其实主要是在网上看到了一篇博客,里面的效果比较炫,只是我觉得那个之前那个博客的动画有些地方的衔接没有做好,并且没有真正还原原设计,所以这里重新写了一下,简单的实现.原博客地址:http://www.jianshu.com/p/3ff40a06bef6,可以看看之前的实现效果以及原设计的效果。
录制效果有点渣.轻喷!
这里写图片描述
接上个gif图:
这里写图片描述
接下来就开始一步一步分析吧.
首先就是一个比较简单过场动画,具体什么是过场动画我就不多说了,不懂的详细了解一下我这里不讲原因,只讲讲如何实现。这里有2个activtiy,主要的东西其实都在第二个activity里.第一个页面就一个texteview不多说,详细说说第二个activity吧。
http://androidwing.net/index.php/172 这一篇我觉得很不错,大家可以看看。
既然是要实现过场动画,那首先第二个activity就要设置这样的属性

<item name="android:windowIsTranslucent">true</item><item name="android:windowBackground">@android:color/transparent</item>

其中SIGNUP这个TextView是一个共享元素,在2个activity中具有一样的属性.在跳转到第二个activity之前.我们需要穿一些第一个activity中Textview的属性值过去.如下图:

public void singUp(View view){        //获取view在屏幕中的位置以及宽高做为参数传到第二个activity        int[] location = new int[2];        view.getLocationOnScreen(location);        Intent intent = new Intent(this, HomeActivity.class);        intent.putExtra("left", location[0]);        intent.putExtra("top", location[1]);        intent.putExtra("width", view.getWidth());        intent.putExtra("height", view.getHeight());        startActivity(intent);        overridePendingTransition(0, 0);    }

记住一点要调用overridePendingTransition(0, 0),关闭系统默认的跳转动画。
在第二个activity中接受到这些参数.

tv_sign_up.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {            @Override            public void onGlobalLayout() {                layout_sign_up.getViewTreeObserver().removeOnGlobalLayoutListener(this);                startRevel();            }        });

由于第二个acitivity中还有个success和一个下划线line.所以这里我把他们放在一个布局里了.

<RelativeLayout        android:id="@+id/layout_sign_up"        android:layout_width="100dp"        android:layout_height="wrap_content"        android:layout_centerInParent="true">        <TextView            android:id="@+id/tv_sign_up"            android:layout_width="100dp"            android:layout_height="30dp"            android:layout_marginBottom="20dp"            android:gravity="center"            android:text="@string/sign_up"            android:textColor="@android:color/white" />        <TextView            android:id="@+id/tv_success"            android:layout_width="100dp"            android:layout_height="30dp"            android:layout_marginBottom="20dp"            android:gravity="center"            android:text="@string/success"            android:textColor="@android:color/white"            android:visibility="invisible" />        <View            android:id="@+id/line_view"            android:layout_width="match_parent"            android:layout_height="1dp"            android:layout_marginTop="35dp"            android:background="@android:color/white"            android:visibility="gone" />    </RelativeLayout>

好了,写好了最基本的东西就开始实现动画了。
第一步,获取到上一个activity传过来的参数,然后计算出上一个activity中textview的位置及大小(如果大小不一样大需要缩放一下)。

//拿到上一个activity中textview的属性        Intent intent = getIntent();        int left = intent.getIntExtra("left", 0);        int top = intent.getIntExtra("top", 0);        int width = intent.getIntExtra("width", 0);        int height =intent.getIntExtra("height", 0);        //获取到当前控件的属性        int[] location = new int[2];        layout_sign_up.getLocationOnScreen(location);        int curX = location[0];        int curY = location[1];        //计算出差值        int transX = left - curX;        int transY = top - curY;        //把当前的控件先移动到上一个activity中textview所处的位置        layout_sign_up.setX(layout_sign_up.getX() + transX);        layout_sign_up.setY(layout_sign_up.getY() + transY);

然后就可以实现圆弧的扩散动画和textview的平移回原位的动画了.
这里圆弧的实现我们适用一个第三方的库,在gradle添加如下依赖:

compile('com.github.ozodrukh:CircularReveal:2.0.1@aar') {        transitive = true;    }

具体使用:

        int cx = left + width / 2;        int cy = top - height / 2;        float radius = (float) Math.hypot(reveal_layout.getWidth(), reveal_layout.getHeight());        Animator animator;        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){            animator = ViewAnimationUtils.createCircularReveal(reveal_layout, cx, cy, 0, radius);            animator.setDuration(700);            animator.addListener(new AnimatorListenerAdapter() {                @Override                public void onAnimationStart(Animator animation) {                    reveal_layout.setVisibility(View.VISIBLE);                }            });            animator.start();        }

首先cx,cy是计算出当前矩形的中心点.(从中心点开始扩散),radius是计算出最终扩散的圆弧半径。由于是整个屏幕所以这里其实就是勾股定理的公式。
效果如下:
这里写图片描述

ViewAnimationUtils.createCircularReveal(reveal_layout, cx, cy, 0, radius);

这里的几个参数其实就很简单了. 参数的意思依次是要控散的控件(不知道描述清楚没有),扩散中心的x坐标,扩散中心的y坐标,刚开始扩散的圆弧半径,最终扩散的圆弧的半径.(如果不熟悉的可以下载源码更改一下参数看看效果就知道了,很简单的.)这里平移和扩散动画是一起执行的,平移动画如下:

        Point start = new Point(layout_sign_up.getX(), layout_sign_up.getY());        Point end = new Point(curX, curY - getStatusBarHeight(this));        ValueAnimator animator1 = ValueAnimator.ofObject(new PointEvaluator(), start, end);        animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                Point curPoint = (Point) animation.getAnimatedValue();                layout_sign_up.setX(curPoint.getX());                layout_sign_up.setY(curPoint.getY());            }        });        animator1.setDuration(700);        animator1.start();

多说一句,这里我使用view.getLocationOnScreen这个方法,不知道为什么获取的位置有误,没有算上标题栏.所以导致平移的位置没有回到中心,所以我减去了标题栏的高度.curY - getStatusBarHeight(this),让其又往上平移了一段距离。效果如下:
这里写图片描述
组合在一起就是如下效果了:
这里写图片描述
接下来就是实现后面的效果了:文字进入和离开的动画,以及line线的缩放动画:

final ObjectAnimator lineAnim = ObjectAnimator.ofFloat(line, "ScaleX", 0f, 0.6f, 0.9f, 1f);        lineAnim.setDuration(1500);        lineAnim.setInterpolator(new DecelerateInterpolator());        line.setPivotX(0);

这里利用setPivotX(0)方法把线条执行动画的起始点改为0,动画将以该坐标为中线开始缩放,(默认为view的中线点),这样扩大动画只会向一个方向发生,即可实现线条延长效果。动画播放数值”0, 0.6f, 0.9f, 1.0f”并不是等差排列,还是越来越小,这样即可实现减速效果。
线条效果如下:可以看到最后一点是以很慢的速度完成的。
这里写图片描述
接下来是文字的进入和离开的动画了.都是比较简单的平移和透明度渐变动画,只不过组合再了一起.

//success进入    private void successEnter() {        if(tv_success.getVisibility() != View.VISIBLE){            tv_success.setVisibility(View.VISIBLE);        }        //得到success的宽度,然后设置起始位置以及终点位置        ObjectAnimator sucessTran = ObjectAnimator.ofFloat(tv_success, "TranslationX", -measuredWidth*1.2f, -measuredWidth*0.2f, 0f);        //透明度渐变从0-1        ObjectAnimator sucessAlpha = ObjectAnimator.ofFloat(tv_success, "Alpha", 0.1f, 0.8f, 1f);        //此处同理        ObjectAnimator signupTran = ObjectAnimator.ofFloat(tv_sign_up, "TranslationX", 0, measuredWidth*0.7f, measuredWidth* 1.5f);        signupTran.setInterpolator(new AccelerateInterpolator());        ObjectAnimator signupAplha = ObjectAnimator.ofFloat(tv_sign_up, "Alpha", 1.0f, 1.0f, 0.4f, 0f);        AnimatorSet set = new AnimatorSet();        set.setDuration(1000);        set.playTogether(sucessTran, sucessAlpha, signupTran, signupAplha);        set.start();        set.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationEnd(Animator animation) {                super.onAnimationEnd(animation);                handler.sendEmptyMessageDelayed(0, 800);            }        });    } private void singupEnter() {        ObjectAnimator signupTran = ObjectAnimator.ofFloat(tv_sign_up, "TranslationX", -measuredWidth*1.2f, -measuredWidth*0.2f, 0f);        ObjectAnimator signupAplha = ObjectAnimator.ofFloat(tv_sign_up, "Alpha", 0.1f, 0.8f, 1f);        ObjectAnimator successTran = ObjectAnimator.ofFloat(tv_success, "TranslationX", 0, measuredWidth*0.7f, measuredWidth* 1.5f);        successTran.setInterpolator(new AccelerateInterpolator());        ObjectAnimator successAlpha = ObjectAnimator.ofFloat(tv_success, "Alpha", 1.0f, 1.0f, 0.4f, 0f);        AnimatorSet set = new AnimatorSet();        set.setDuration(1000);        set.playTogether(signupTran, signupAplha, successTran, successAlpha);        set.start();        set.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationEnd(Animator animation) {                super.onAnimationEnd(animation);                handler.sendEmptyMessageDelayed(0, 1000);            }        });    }

上面的2个动画都是很简单的动画,这里就不多说了.以下是动画循环:

 int index = 0;    private void loopAnim() {        if(index % 2 == 0){            successEnter();        }else{            singupEnter();        }        index++;    }    private Handler handler = new Handler(){        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            //此处模拟网络请求,5次之后执行最后一个背景收起的动画            if(index >= 5){                enterHome();            }else {                loopAnim();            }        }    };

剩下 最后的背景收起动画我同样使用了属性动画,代码如下:

private void enterHome() {        im.setVisibility(View.VISIBLE);        rl_title.setVisibility(View.VISIBLE);        scale_layout.setVisibility(View.VISIBLE);        reveal_layout.setVisibility(View.GONE);        layout_sign_up.setVisibility(View.GONE);        ValueAnimator valueAnimator = ValueAnimator.ofInt(scale_layout.getHeight(), 0);        valueAnimator.setInterpolator(new DecelerateInterpolator());        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()        {            @Override            public void onAnimationUpdate(ValueAnimator animation)            {                scale_layout.getLayoutParams().height = (int) animation.getAnimatedValue();                scale_layout.requestLayout();            }        });        AnimatorSet animatorSet = new AnimatorSet();        animatorSet.playTogether(valueAnimator,                ObjectAnimator.ofFloat(iv_me, "Alpha", 0.1f, 1.0f),                ObjectAnimator.ofFloat(iv_menu, "Alpha", 0.1f, 1.0f));        animatorSet.setDuration(1200);        animatorSet.start();    }

在属性动画中,我监听了addUpdateListener,这里的animation参数可以获取到当前改变的值:
animation.getAnimatedValue();当然变化的范围就是从layout的高度减小到0,所以这里我拿到改变的值,直接设置给layout的布局参数中的height相当于动态的改编其高度.(这个技巧其实很实用,我写的第一篇博客也实用到这个技巧)。最后就是对title的2个view进行透明度的渐变:

其实在平常的看到的很多例子里,有些看上去很炫的效果其实都是一些比较基本的东西组合起来的.我们平常写代码也是一样,都是用最基本的东西通过对代码不同的组合,以此来实现不同的需求,动画也是一样,最重要的就是要分析出来每个动画都是由什么方式实现的,最后加以组合。源码在这里:
https://github.com/wxkkwxxx/MyAnim

0 0
原创粉丝点击