Android Toast进阶——自定义Toast

进阶目标

上一篇博客我们学习了Toast的源码,了解了Toast从显示到消失的全过程,学习链接:Android Toast源码分析 。俗话说的好,学以致用。我们学习Toast源码不是用来炫技的,而是用来了解Toast原理,从而真正解决我们问题的。下面我就提两个业务中可能遇到的跟Toast相关的真实问题,看看学习了Toast源码之后,该如何解决这些问题。两个问题是:

  1. 如何自定义Toast的显示时间。
  2. 如何修改Toast的出现动画。

接下来,我们分别讲解阅读了Toast源码之后,如何解决这两个业务中真实遇到的问题。

控制Toast显示时间

通过对Toast源码的学习,我们知道Toast的显示和消失是NotificationManagerService调用TN类的show和hide方法实现的,而Toast的显示时间的长短则跟Handler发送消息的延迟时间相关。具体源码如下:

    private void scheduleTimeoutLocked(ToastRecord r)
    {
        mHandler.removeCallbacksAndMessages(r);
        Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
        long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
        mHandler.sendMessageDelayed(m, delay);
    }

之前Toast源码里也讲过,为什么Toast的桌面显示时间只能是2s和3.5s,关键就是在于long delay变量的延迟时间只能是2s和3.5s。因此,如果你是Android操作系统的开发人员,你可以直接修改Android Framework层的NotificationManagerService类代码,将LONG_DELAY和SHORT_DELAY改成你想要的时间间隔。但是,这种做法的弊端很明显。首先,你可能只是一个小小的应用层开发工程师,只能改动应用层代码。其次,就算修改NotificationManagerService,也只能改动LONG_DELAY和SHORT_DELAY两个变量,无法做到随意修改显示时间。

弊端这么多,那我们应用层开发工程师该怎么办呢?答案也很简单,仿照Toast源码,我们自己造个轮子,自定义一个Toast,这样我们肯定就可以控制Toast的显示时间了。通过源码我们知道,Toast是基于WindowManager来显示的,那我们完全可以撸一个自定义Toast出来,源码如下:

import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Message;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;

public class ToastCustom {
	private static final int MESSAGE_TIMEOUT = 2;
	private WindowManager wdm;
	private double time;
	private View mView;
	private WindowManager.LayoutParams params;
	private WorkerHandler mHandler;

	private ToastCustom(Context context, String text, double time) {
		wdm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		mHandler = new WorkerHandler();

		Toast toast = Toast.makeText(context, text, Toast.LENGTH_LONG);
		mView = toast.getView();

		params = new WindowManager.LayoutParams();
		params.height = WindowManager.LayoutParams.WRAP_CONTENT;
		params.width = WindowManager.LayoutParams.WRAP_CONTENT;
		params.format = PixelFormat.TRANSLUCENT;
		params.windowAnimations = toast.getView().getAnimation().INFINITE;
		params.type = WindowManager.LayoutParams.TYPE_TOAST;
		params.setTitle("Toast");
		params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
		params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
				| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
				| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

		this.time = time;
	}

	public static ToastCustom makeText(Context context, String text, double time) {
		ToastCustom toastCustom = new ToastCustom(context, text, time);
		return toastCustom;
	}

	public void show() {
		wdm.addView(mView, params);
		mHandler.sendEmptyMessageDelayed(MESSAGE_TIMEOUT, (long) (time * 1000));
	}

	public void cancel() {
		wdm.removeView(mView);
	}

	private class WorkerHandler extends Handler {
        @Override
        public void handleMessage(Message msg)
        {
            switch (msg.what)
            {
                case MESSAGE_TIMEOUT:
                	cancel();
                    break;
            }
        }
	}
}

原理很简单,利用WindowManager来显示Toast,然后利用Handler机制发送延迟消息控制WindowManager再将Toast删除。需要注意一点:这里自定义Toast的Handler用的也是主线程的Looper,子线程调用该自定义Toast需要增加Looper.prepare()和Looper.loop()代码。

修改Toast呈现动画

Android原生的Toast类并没有提供给我们设置动画效果的接口,每个Android原生的Toast的动画效果都是在TN类中定义好的com.android.internal.R.style.Animation_Toast,因此,如果你想要修改Android Toast的动画效果,还是需要自己撸一个Toast,修改一下params.windowAnimations变量的内容即可。接下来,让我们先自定义一个动画效果。

在style.xml文件中定义一个新的style,xml内容如下:

    <style name="custom_toast_anim_view">
        <item name="@android:windowEnterAnimation">@anim/enter_anim</item>
        <item name="@android:windowExitAnimation">@anim/exit_anim</item>
    </style>

然后在anim文件夹下面增加两个动画效果文件,分别为enter_anim.xml和exit_anim.xml。

enter_anim.xml:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="1"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="0"
        android:toYDelta="80" />

    <translate
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="0"
        android:toYDelta="-100"
        android:duration="300"
        android:fillAfter="true"
        android:interpolator="@android:anim/decelerate_interpolator"/>

    <alpha
        android:duration="100"
        android:fromAlpha="0"
        android:toAlpha="1" />

    <translate
        android:duration="80"
        android:fillAfter="true"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:startOffset="300"
        android:toXDelta="0"
        android:toYDelta="20" />

</set>

exit_anim.xml:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <alpha
        android:duration="800"
        android:fromAlpha="1"
        android:toAlpha="0" />

</set>

然后,修改一下自定义Toast代码中的params.windowAnimations变量即可:

		params.windowAnimations = com.example.photocrop.R.style.custom_toast_anim_view;
时间: 2024-08-24 10:14:03

Android Toast进阶——自定义Toast的相关文章

Android带图片的Toast(自定义Toast)

使用Android默认的Toast Toast简介: Toast是一个简单的消息显示框,能够短暂的出现在屏幕的某个位置,显示提示消息. 默认的位置是屏幕的下方正中,一般Toast的使用如下: Toast.makeText(this,"1222222",Toast.LENGTH_SHORT).show(); Toast是static修饰的静态类,意味着可以直接使用,所以可以不用创建对象直接调用makeText方法, 该方法需要传入三个参数: /** * Make a standard t

推荐扔物线的HenCoder Android 开发进阶系列 后期接着更新

官网地址:http://hencoder.com/ 我来做一次辛勤的搬运工 HenCoder:给高级 Android 工程师的进阶手册 HenCoder Android 开发进阶: 自定义 View 1-1 绘制基础 HenCoder Android 开发进阶: 自定义 View 1-2 Paint 详解

Android之十一Toast 自定义Toast的实现方法,及其说明

Android Toast 自定义Toast的实现方法,及其说明 Android Toast用于在手机屏幕上向用户显示一条信息,一段时间后信息会自动消失.信息可以是简单的文本,也可以是复杂的图片及其他内容(显示一个view).  1.简单用法 Toast.makeText(midlet.getApplicationContext(), "用户名不能为空", Toast.LENGTH_LONG).show(); 2.自定义显示位置效果 代码 toast = Toast.makeText(

android 自定义Toast显示风格

1.创建一个自己想要显示Toast风格的XML如下代码(toast_xml.xml): [html] view plaincopyprint? <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match

Android自定义Toast

场景 Toast作为一个基本的界面提醒方式,使用还是比较广,但是介于默认样式比较难看外加有些特殊要求,比如需要在Toast的界面上做事件处理啥的,所以衍生出了Toast的自定义样式 默认样式 1 Toast tempToast = Toast.makeText(getApplicationContext(), "默认的Toast样式", 2 Toast.LENGTH_LONG); 3 //可以设置位置 4 //tempToast.setGravity(Gravity.BOTTOM |

Android学习笔记之自定义Toast

(1)布局文件layout <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" and

android自定义Toast之-弹出消息

实现方法: 1.new 一个Toast实例toast. 2.自定义一个显示的View实例view . 3.把toast.setView(view),toast.setDuration(Toast.LENGTH_LONG)设置显消息示时间 4.避免操作有误一直重复弹出消息处理,定义一个Toast的全局变量避免重复实例化进行控制 下面是代码 package com.android.hexiang.otptoken; import android.view.Gravity; import androi

[Android]自定义Toast

Toast,在Android开发中常常会遇到,但是,我们总是会遇到一个问题,那便是当我们使用按钮监听弹出Toast的时候,假如不断点击按钮,将会不断地弹出Toast,而这一篇文章便是为了解决这个问题而编写的. 同时,为了节约app资源和方便使用,便使用单例模式来实现自定义Toast. (1)建立MyToast类,并且定义以下成员变量,以及部分更改器: private static final Object SYNC_LOCK = new Object(); private static Toas

朝花夕拾-android 自定义toast

在一个只有你而且还未知的世界中,不去探索未知,死守一处,你到底在守什么呢? 作为一个目前的android程序员,可能过去写着delphi的代码,可能未来回去搭建服务器.不管怎样,你现在是一名安卓程序员,是该告别eclipse的时候了. 今天早上开机,android studio 都更新到0.9.9了,大家都说他的强大.可能用惯了大刀长矛的武林高手并不习惯使用火枪洋炮,但是还是得用吧. 所以,自定义toast的Demo 源码位置:http://git.oschina.net/zj2012zy/An