Android Application级别自定义Toast

在Android开发过程中,有时会需要一些消息提示,大多数情况可以用dialog来做,但有些消息不需要用户去点击取消并且不能对用户体验产生影响的提示,就需要toast来做了。但可惜的是,toast是系统级的,凡是涉及到系统的又会涉及到其他APP,有些定制系统可以对App的消息通知进行设置,一旦禁止了APP的通知toast则不会显示。而且在Android 7以后toast还需要申请权限麻烦死了有木有,劳资就想安安静静的提示一下有这么麻烦吗!所以,本人特地研究了下能在Application级别不受限制提示的toast。

先看效果:

效果很简单,就是一个头部即现即隐的提示,外加过渡动画。其实自定义系统级的toast也能实现这种效果,但之前已经说了系统级的toast有限制。


话不多说,现在介绍下这是如何实现的吧!

首先申明这是基于WindowManager产生的view,本人看了系统级toast的源码好像也是基于WindowManager的。WindowManager是个神奇的东西,在这就不多做介绍了,我们只需要知道activity.getWindowManager().addView(layout, params)可以给整个Activity界面添加一个view层,这一层可以不影响activity的操作。竟然有这个功能瞬间涨姿势了有不有!细心人的应该察觉到了这和FrameLayout挺像,其实Activity的root就是一个FrameLayout。

好了,既然Activity有这个功能,那tosat做起来就有头绪了。

先实现java类代码(个人爱好,喜欢先主后次):

/**
 * App级toast
 */
public class AppToast
{
    private Activity activity;

    private ViewGroup layout;
    private ViewGroup content;
    private TextView textView;

    private Animation startAnimation;
    private Animation centerAnimation;
    private Animation endAnimation;

    private DelayTask task;
    private boolean isShow;

    private LayoutParams params;

    /**
     * APP级别Toast
     */
    public AppToast(Activity activity)
    {
        this.activity = activity;

        layout = (ViewGroup) LayoutInflater.from(activity).inflate(R.layout.toast, null);
        content = (ViewGroup) layout.getChildAt(0);
        textView = (TextView) content.getChildAt(0);
        params = new LayoutParams();
        params.height = LayoutParams.WRAP_CONTENT;
        params.width = LayoutParams.MATCH_PARENT;
        params.gravity = Gravity.TOP;
        params.type = LayoutParams.TYPE_APPLICATION;
        params.format = PixelFormat.TRANSLUCENT;
        params.flags = LayoutParams.FLAG_KEEP_SCREEN_ON | LayoutParams.FLAG_NOT_FOCUSABLE |
                LayoutParams.FLAG_NOT_TOUCHABLE;
        activity.getWindowManager().addView(layout, params);
        layout.setVisibility(View.GONE);

        // 开始动画
        startAnimation = new AlphaAnimation(0, 1);
        startAnimation.setDuration(500);

        // 中间动画
        centerAnimation = new AlphaAnimation(0.92f, 1);
        centerAnimation.setDuration(500);

        // 结束动画
        endAnimation = new AlphaAnimation(1, 0);
        endAnimation.setDuration(500);
        endAnimation.setInterpolator(new AccelerateInterpolator());

        // 结束动画监听
        endAnimation.setAnimationListener(new Animation.AnimationListener()
        {
            @Override
            public void onAnimationStart(Animation animation)
            {
            }

            @Override
            public void onAnimationEnd(Animation animation)
            {
                layout.setVisibility(View.GONE);
            }

            @Override
            public void onAnimationRepeat(Animation animation)
            {
            }
        });
    }

    /**
     * 显示Toast
     */
    public void show(String s)
    {
        show(s, 1500);
    }

    /**
     * 显示Toast
     */
    public void show(String s, int delay)
    {
        textView.setText(s);
        start();
        if (task != null)
        {
            task.stop();
        }
        task = new DelayTask(delay)
        {
            @Override
            public void logic()
            {
                end();
            }
        };
        task.start();
    }

    /**
     * 开始
     */
    private void start()
    {
        if (!isShow)
        {
            layout.setVisibility(View.VISIBLE);
            content.startAnimation(startAnimation);
            isShow = true;
        } else
        {
            content.startAnimation(centerAnimation);
        }
    }

    /**
     * 结束
     */
    private void end()
    {
        content.startAnimation(endAnimation);
        isShow = false;
    }
}
先在构造方法 AppToast(Activity activity)中加载自定义toast的布局以及初始化params参数。然后添加各个过程所需的动画。这其中有个重点,就是params.type = LayoutParams.TYPE_APPLICATION,记住一定要是TYPE_APPLICATION,而不是 TYPE_TOAST,TYPE_TOAST会在Android 7上被莫名其妙的限制。

有些人可能会注意到除了开始动画和结束动画,为什么还有个中间动画?其实这是为了多重toast提示做的一个辨别机制,我们在用系统级toast的时候有些人应该能感受到toast并不是重叠显示,但也不是直接替换内容,而是在替换内容的时候微微的闪一下表示内容变更了,所以在这里就用了一个中间动画来执行那“闪一下”的效果。

关于其中用到的一个延时器类DelayTask,这是本人为了方便自行设计的一个工具类,其效果就是延时执行一段UI逻辑,其代码如下:

/**
 * 延时器类
 *
 * @author zls
 *
 * @version 1.0
 *
 * @time 2015-12-27下午7:52:10
 */
public abstract class DelayTask
{
	protected Thread thread;
	private boolean isRun;

	/**
	 * 延时器
	 */
	public DelayTask(final long delay)
	{
		thread = new Thread()
		{
			@Override
			public void run()
			{
				try
				{
					sleep(delay);
					if(isRun)
					{
						mHandler.sendEmptyMessage(0);
					}
				} catch (Exception e)
				{
				}
			}
		};
	}

	protected Handler mHandler = new Handler()
	{
		@Override
		public void handleMessage(Message msg)
		{
			logic();
		}
	};

	/** 开始执行 */
	public void start()
	{
		isRun = true;
		thread.start();
	}

	/** 停止执行 */
	public void stop()
	{
		isRun = false;
	}

	/** 执行逻辑 */
	public abstract void logic();
}
有兴趣的朋友可以借鉴下,觉得这么设计不太好的也可以用你们自己设计的延时器来用。

现在上toast的布局代码(水一下):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:paddingTop="5dp"
    android:paddingLeft="15dp"
    android:paddingRight="15dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/toast_shape"
        android:fitsSystemWindows="true"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="20dp"
            android:gravity="center"
            android:text="默认提示"
            android:textColor="#fff"
            android:textSize="15sp"/>
    </LinearLayout>

</LinearLayout>
测试Activity的代码:

public class MainActivity extends AppCompatActivity
{
    private AppToast toast;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);

        toast = new AppToast(this);
    }

    public void ok(View v)
    {
        toast.show("这是Toast测试!" + Math.random());
    }
}

 

Demo下载

就此结束,希望能帮到需要此功能的朋友。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值