您的位置:首页 > 移动开发 > Android开发

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

2017-03-13 13:46 519 查看
最近比较闲,再加上以前懒惰的习惯,决定尽量保持几天一篇博客,这次简单实现一下这个效果.其实主要是在网上看到了一篇博客,里面的效果比较炫,只是我觉得那个之前那个博客的动画有些地方的衔接没有做好,并且没有真正还原原设计,所以这里重新写了一下,简单的实现.原博客地址: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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: