底部弹框动画及渐变背景色

Android底部弹框动画及渐变背景色

概述

手机应用中的底部弹框经常都会用到,应该说也比较容易实现,网上有非常多的例子,不过都是视觉效果比较单一的,比如瞬间弹出、从底部慢慢升起、带半透明的背景色。如果把这些效果组合起来实现就会有些瑕疵,等下我会具体说一下我认为的瑕疵。现在来说一下实现以上几种效果的常见方法:

一、 动画效果实现方法

对于PopupWindow的动画效果,一种是用style, 一种是用代码,这两种没什么区别,只是用style的话要另写一个xml文件,稍微麻烦一点,特别是如果想封装成一个组件的话就更不方便,除了java文件还带个xml文件很不方便,所以封装成组件的话还是用代码的方式实现为好。

1、sytle方式

首先在style.xml中声明一个style,如:

<?xml version="1.0" encoding="utf-8"?>    
<resources>       
  
<style name="PopupAnimation" parent="android:Animation" mce_bogus="1">         
        <item name="android:windowEnterAnimation">@anim/popup_enter</item>    
        <item name="android:windowExitAnimation">@anim/popup_exit</item>    
    </style>    
</resources>

然后在res/anim文件夹中新增一个动画文件(如果没有anim文件夹则新建一个),如:

<?xml version="1.0" encoding="utf-8"?>        
<set xmlns:android="http://schemas.android.com/apk/res/android">    
    <scale android:fromXScale="0.6" android:toXScale="1.0" 
        android:fromYScale="0.6" android:toYScale="1.0" android:pivotX="50%" 
        android:pivotY="50%" android:duration="1000" />    
    <alpha android:interpolator="@android:anim/decelerate_interpolator" 
        android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="1000" />    
</set>

上面的是进入动画,还可以建个退出动画,如:

<?xml version="1.0" encoding="utf-8"?>    
<set xmlns:android="http://schemas.android.com/apk/res/android">    
    <scale    
        android:fromXScale="1.0" 
        android:toXScale="0.5" 
        android:fromYScale="1.0" 
        android:toYScale="0.5" 
        android:pivotX="50%" 
        android:pivotY="50%" 
        android:duration="500" />    
    <alpha    
        android:interpolator="@android:anim/accelerate_interpolator" 
        android:fromAlpha="1.0" 
        android:toAlpha="0.0" 
        android:duration="500" />    
</set>

最后使用的时候调一下这个方法

popupWindow.setAnimationStyle(R.style.PopupAnimation);

注,以上代码片断来自于 http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/0303/956.html

2、用代码的方式

先初始化一个TranslateAnimation对象,如:

// 平移动画相对于手机屏幕的底部开始,X轴不变,Y轴从1变0
TranslateAnimation animation = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0, Animation
    .RELATIVE_TO_PARENT, 0,
    Animation.RELATIVE_TO_PARENT, 1, Animation.RELATIVE_TO_PARENT, 0);
animation.setInterpolator(new AccelerateInterpolator());
animation.setDuration(300);

然后在调完show方法之后,启动动画,如:

showAtLocation(activity.getWindow().getDecorView(), Gravity.BOTTOM, 0, 0);
contentView.startAnimation(animation);

以上的contentView是popupWindow.getContentView();的返回值。

二 、背景色实现方案

1、最简单的就是contentView的layout设置高宽为match_parent,然后设置背景色。

2、就是在代码中设置popupWindow的背景色,如:

// 设置背景色
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#00112233")));

如果是瞬间弹出的话这两种方式都没什么问题,但如果加上动画效果的话就有些瑕疵了:

第一种加上动画后效果是背景色也会从屏幕底部升起,这种效果看着很别扭,感觉像在拉幕布。

第二方式加上动画效果后,屏幕瞬间变成黑色半透明,然后contentView慢慢从屏幕底部弹出,这种效果也是挺难看的。

看了一下其它应用的弹框动画,它们的效果是背景色在contentView慢慢升起的过程中从完全透明变成半透明,当contentView完全升起时背景色也达到了最终的半透明。经过一番思考,我用以下方案基本实现了这个效果:

动画这部分不用动,直接用代码实现就可以了,背景色的话我没有采用上述两种方式的任何一种。我首先想到了属性动画中的颜色渐变,用这个特性来实现背景色与弹出框的同步,就是contentView一边慢慢升起,背景色也一边从全透明开始慢慢变深,并且这个背景色是作用于整个屏幕的,不会跟着contentView往上走。如果这两个动画的时间设置为一样那基本上也就达到了我们要的效果了,不过实际效果中,触发弹框后contentView并不会马上弹出来,而是要等一会才会弹出来,这点可以通过把动画时间设置长一些就能看出来了,比如设置成3秒,你会看到前两秒都没反应,在最后一秒才能看到框从底部开始弹出(这里的一秒两秒是个大概的估计)。因此背景色的渐变最好还不要是线性的,如果是线性的话前两秒框还没弹出来背景确变黑了一点了,最好就是从看到框弹出时背景才开始慢慢变黑。这时我想到了用平方曲线(即y=x²)来控制颜色的渐变过程,最后实现下来感觉还算满意。下面就来看看具体怎么实现的。

首先,这个背景色要设置在哪个view上?contnetView肯定不行,因为contentView是会移动的,那么放在PopupWindow中那个接受setBackgroundDrawable方法里的背景色的view上?可是查了下这个view是私有的,并且也没看到有其它什么方法能拿到这个view的实例。后来想到popupwindow大多都是在Activity的基础上弹出来的,所以就想从activity入手来创建一个view,让这个view来承载背景色。最后选择了android.R.id.content这个view,它是一个FrameLayout,添加一个view就可以把activity上的内容盖住,再加上个半透明的背景色,就可以达到我们的要求了。

以下是关键代码:

 /**
 * 从底部弹出
 */
public void show() {
    if (activity != null) {
        showAtLocation(activity.getWindow().getDecorView(), Gravity.BOTTOM, 0, 0);
        contentView.startAnimation(animation);

        // 背景色渐变
        backgroundView = new FrameLayout(activity);
        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams
            .MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        backgroundView.setLayoutParams(lp);
        ViewGroup rootView = activity.findViewById(android.R.id.content);
        rootView.addView(backgroundView);
        // 从完全透明开始到半透明的灰色
        int begin = 0x00000000;
        int end = 0x4d000000;

        ValueAnimator colorAnim = ObjectAnimator.ofInt(backgroundView, "backgroundColor",
            begin, end);
        colorAnim.setDuration(300);
        colorAnim.setEvaluator(new ArgbEvaluator());
        Interpolator interpolator = new MyInterpolator();
        colorAnim.setInterpolator(interpolator);
        colorAnim.start();
    }
}

其中属性动画 colorAnim还用到一个插值器,就是控制颜色的变化过程的。

/**
 * 动画插值器
 *
 * @author Huangming 2019/3/17
 */
private class MyInterpolator implements Interpolator {
    @Override
    public float getInterpolation(float input) {
        // y=1-√1-x² 曲线,本来想直接用y=x²的,但是还是不够理想
        float y = (float) (1.0 - Math.sqrt(1 - input * input));
        // XbdLog.d("x=%s  y=%s", input, y);
        return y;
    }
}

这个插值器里面的曲线方程比较关键,如果过早地变颜色会就出现框还没弹出来,背景色就已经变了的情况。

本来想直接用y=x²的,但是还是不够理想,最后找了个这样的:y=1-√1-x²,曲线如下:

再来看下整体的效果图,这个效果是将动画时间拉长到3秒的效果,就是为了看清楚背景色的变化与弹出框的弹出时机:

最后,上源码,有兴趣的可以去下下来跑一下:

demo源码:https://github.com/MingHuang1024/HmPopupWindow




由于水平有限,如果文中存在错误之处,请大家批评指正,欢迎大家一起来分享、探讨!

博客:http://blog.csdn.net/MingHuang2017

GitHub:https://github.com/MingHuang1024

Email: MingHuang1024@foxmail.com

微信:724360018

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值