Activity过渡动画

简介: 看了下5.0的过渡动画,效果确实蛮炫的,可惜我是4.4.2的,哎,享受不了啊,没钱买手机,穷啊 后来在格瓦拉app里面发现了这种过渡动画,4.4.2的也支持,那时候感觉,这么牛×啊(其实以下的都能支持),但是一直没见着好的源码看看,直到我看到了别人仿的一个知乎日报app,里面发现有这个功能,我就把他提取了出来,加上了自己所理解的一些注释,如有其它见解的,可以留言哦废话

看了下5.0的过渡动画,效果确实蛮炫的,可惜我是4.4.2的,哎,享受不了啊,没钱买手机,穷啊
后来在格瓦拉app里面发现了这种过渡动画,4.4.2的也支持,那时候感觉,这么牛×啊(其实以下的都能支持),但是一直没见着好的源码看看,直到我看到了别人仿的一个知乎日报app,里面发现有这个功能,我就把他提取了出来,加上了自己所理解的一些注释,如有其它见解的,可以留言哦

  • 废话不多说,老规矩,先上效果图
    这里写图片描述

效果是真的蛮不错的,思路其实挺简单的,就是在第二个Activity界面上面再添加了一层动画效果的View,动画结束后就隐藏他,然后显示Activity界面

  • MainActivity.java
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void next(View v) {
        int location[] = new int[2];
        v.getLocationOnScreen(location);//将当前控件的坐标值赋给数组
        location[0]+=v.getWidth()/2;//获取横坐标控件的中心位置
        Intent intent=new Intent(this,SecondActivity.class);
        intent.putExtra("location", location);
        startActivity(intent);
        //关闭Activity启动的动画,目的是为了显示自己的动画
        overridePendingTransition(0, 0);
    }

    public void next1(View v) {
        int location[] = new int[2];
        v.getLocationOnScreen(location);
        location[0]+=v.getWidth()/2;
        Intent intent=new Intent(this,SecondActivity.class);
        intent.putExtra("location", location);
        startActivity(intent);
        overridePendingTransition(0, 0);
    }

activity_main.xml的文件就不写了,就是两个button,添加了两个onClick,一个next,一个next1。

  • SecondActivity.java
public class SecondActivity extends Activity implements OnStateChangeListener {
    private RevealBackgroundView revealBackgroundView;
    private LinearLayout linea;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        linea = (LinearLayout) findViewById(R.id.linea);
        revealBackgroundView = (RevealBackgroundView) findViewById(R.id.RevealBackgroundView);
        setupRevealBackground(savedInstanceState);
    }

    private void setupRevealBackground(Bundle savedInstanceState) {
        revealBackgroundView.setOnStateChangeListener(this);
        //初始化时,当前的savedInstanceState为空
        if (savedInstanceState == null) {
            final int[] startLocation = getIntent()
                    .getIntArrayExtra("location");
            // 初始化控件时的监听
            revealBackgroundView.getViewTreeObserver().addOnPreDrawListener(
                    new OnPreDrawListener() {
                        @Override
                        public boolean onPreDraw() {
                                        revealBackgroundView.getViewTreeObserver().removeOnPreDrawListener(this);
                            // 设置单击坐标点的半径
                            revealBackgroundView.setCurrentRadius(50);
                            // 设置绘制填充画笔的颜色
                            revealBackgroundView.setFillPaintColor(0xff34A67B);
                            // 开启动画
                            revealBackgroundView.startFromLocation(startLocation);
                            return true;
                        }
                    });
        } else {
            // 完成动画
            revealBackgroundView.setToFinishedFrame();
        }
    }

    @Override
    public void onStateChange(int state) {
        // 如果当前状态完成,就显示底部布局,隐藏RevealBackgroundView
        if (RevealBackgroundView.STATE_FINISHED == state) {
            linea.setVisibility(View.VISIBLE);
            revealBackgroundView.setVisibility(View.GONE);
        }
    }
}
  • activity_second.xml
<?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:orientation="vertical" >

    <com.example.anim.RevealBackgroundView
        android:id="@+id/RevealBackgroundView "
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <LinearLayout
        android:id="@+id/linea"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:visibility="gone" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="我是第二个页面"
            android:textSize="50px" />
    </LinearLayout>

</RelativeLayout>

重头戏View来了

  • RevealBackgroundView.java

public class RevealBackgroundView extends View {
    public static final int STATE_NOT_STARTED = 0;// 没有开始状态
    public static final int STATE_FILL_STARTED = 1;// 填充满状态
    public static final int STATE_FINISHED = 2;// 填充完成状态

    // 在动画开始的时候速率比较慢,后面持续增加
    private static final Interpolator INTERPOLATOR = new AccelerateInterpolator();
    private static final int FILL_TIME = 600;// 动画时间600毫秒

    private int state = STATE_NOT_STARTED;// 默认状态

    private Paint fillPaint;// 画笔
    private int currentRadius;// 半径
    ObjectAnimator revealAnimator;

    private int startLocationX;// 控件的x坐标值
    private int startLocationY;// 控件的Y坐标值

    private OnStateChangeListener onStateChangeListener;

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

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

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

    private void init() {
        fillPaint = new Paint();
        fillPaint.setStyle(Paint.Style.FILL);
        fillPaint.setColor(Color.WHITE);
    }

    // 设置画笔的颜色
    public void setFillPaintColor(int color) {
        fillPaint.setColor(color);
    }

    //开启动画
    public void startFromLocation(int[] tapLocationOnScreen) {
        changeState(STATE_FILL_STARTED);

        startLocationX = tapLocationOnScreen[0];//传递过来view的x的RELATIVE_TO_SELF坐标值
        startLocationY = tapLocationOnScreen[1];//传递过来view的y的RELATIVE_TO_SELF坐标值
        // 动画标记为当前的半径currentRadius,值为RevealBackgroundView的0--width+height
        revealAnimator = ObjectAnimator.ofInt(this, "currentRadius", 0,
                getWidth() + getHeight()).setDuration(FILL_TIME);
        revealAnimator.setInterpolator(INTERPOLATOR);
        // 动画监听器
        revealAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                // 在动画结束的时候调用该方法
                changeState(STATE_FINISHED);
            }
        });
        revealAnimator.start();
    }

    // 当回调为true时,调用该方法,重新绘制当前界面
    public void setToFinishedFrame() {
        changeState(STATE_FINISHED);
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // 在动画完成后直接画整个界面,不在让他继续扩散
        if (state == STATE_FINISHED) {
            canvas.drawRect(0, 0, getWidth(), getHeight(), fillPaint);
        } else {
            // 绘制点击控件位置扩散的圆圈
            canvas.drawCircle(startLocationX, startLocationY, currentRadius,
                    fillPaint);
        }
    }

    // 判断当前的状态
    private void changeState(int state) {
        if (this.state == state) {
            return;
        }
        this.state = state;
        // 将当前状态不停的回调,回调时判断一下当前是否完成,是的话就显示底部布局
        if (onStateChangeListener != null) {
            onStateChangeListener.onStateChange(state);
        }
    }

    // 设置圆圈的半径时,重新调用onDraw,重新画圆
    public void setCurrentRadius(int radius) {
        this.currentRadius = radius;
        invalidate();
    }

    public void setOnStateChangeListener(
            OnStateChangeListener onStateChangeListener) {
        this.onStateChangeListener = onStateChangeListener;
    }

    public static interface OnStateChangeListener {
        void onStateChange(int state);
    }
}

整个效果都是RevealBackgroundView来支持,代码也不是太多,很棒吧^-^


题外话,2016/3/12要去润创驾校体检,15号考科目一,在此记录一下,good idea

目录
相关文章
|
11月前
|
SQL XML Java
mybatis实现动态sql
MyBatis的动态SQL功能为开发人员提供了强大的工具来应对复杂的查询需求。通过使用 `<if>`、`<choose>`、`<foreach>`等标签,可以根据不同的条件动态生成SQL语句,从而提高代码的灵活性和可维护性。本文详细介绍了动态SQL的基本用法和实际应用示例,希望对您在实际项目中使用MyBatis有所帮助。
618 11
|
缓存 图形学 C++
Unreal学习笔记2-绘制简单三角形
Unreal学习笔记2-绘制简单三角形
196 0
|
存储 安全 Windows
电脑桌面文件不见了怎么恢复?8个方法帮你解决问题
电脑桌面文件突然不见了凭空消失了怎么恢复?电脑桌面文件日常使用电脑时,很多用户喜欢将重要文件、快捷方式存放在桌面上,以方便快速访问。然而,有时我们会突然发现桌面上的文件不见了。桌面文件消失可能有多种原因,例如误删除、系统更新、设置变更等。今天给大家介绍一些桌面文件丢失的常见的原因以及如何找回丢失的文件。
|
安全
深入理解Qt多线程编程:QThread、QTimer与QAudioOutput的内在联系__Qt 事件循环(三)
深入理解Qt多线程编程:QThread、QTimer与QAudioOutput的内在联系__Qt 事件循环
442 0
|
存储 API 数据安全/隐私保护
​邮箱收不到验证码邮件是什么原因
在互联网应用中,未收到验证码邮件常令人困扰。原因包括邮件误入垃圾箱、邮箱设置不当、发件服务器故障、地址输入错误及ISP拦截。解决策略有检查垃圾邮件、清理邮箱、修正设置、确认地址准确及更换邮箱服务。推荐使用AOKSend提升邮件送达率,其优势在于高送达率、实时监测与易集成,通过注册、获取API、配置SMTP及测试,可有效解决验证码邮件送达问题,优化用户体验。
|
Unix Linux 开发者
在Linux中,什么是GPL、GNU,自由由软件?
在Linux中,什么是GPL、GNU,自由由软件?
|
网络安全
为KALI进行换元更新
为KALI进行更新 由于kali的软件仓库在国外,更新很慢,我们需要将kali的软件源更换为国内的软件源,推荐中科大的源 编辑 /etc/apt/sources.list 文件, 在文件最前面添加以下条目: ``` deb https://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib deb-src https://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib ``` 更改完 sources.list 文件后请运行 sudo apt-get u
485 0
为KALI进行换元更新
|
测试技术 项目管理
版本制交付和迭代交付,傻傻分不清楚
最近与云效的客户共创交流中,不少企业问及迭代和版本,我如何选?
1601 0
|
自然语言处理 运维 搜索推荐
内容社区行业搜索最佳实践
社区内容通常包括UGC和PGC。由于关键词和内容多样性丰富、用词规范程度参差不齐,搜索引擎需要对关键词和内容进行智能语义分析,识别出用户真正的查询意图,找到最全面最相关的结果满足用户需求。本文将详细介绍如何通过“开放搜索(OpenSearch)内容增强版”在社区论坛场景的应用,提升用户搜索体验,带来更多的业务转化
1174 0
|
编解码 安全 机器人
【Android从零单排系列一】《Android系统发展史》
本文系统介绍了Android系统的由来、发展历史,各版本发展演变过程及特性。
1149 0
【Android从零单排系列一】《Android系统发展史》