Android开发 自定义Toast样式II 在AlertDialog基础扩展

前文,Android开发 自定义Toast样式,基本实现了自定义的Toast,但没想到客户的需求有点变态。要求提示的时候背景变灰,用户不可操作,而且提示的时间还要根据字符串长度计算,原想在Toast的基础上扩展,修改WindowManager.LayoutParams.flag,但发现Toast源代码调用了隐藏的API,我们是没法实现了。客户的要求其实就是一个AlertDialog,那就写个自定义的AlertDialog吧。因为项目中大量使用了Toast,调用方法为:


MyToast.makeText(context, "密码错误,请进SOS查看!!", Toast.LENGTH_LONG).show();

为了减少代码修改,必须把我们自定义的Toast也加上一个静态的makeText方法,和一个show()方法,以达到不用修改调用方法的目的。


package com.jtang.android.components;

import android.app.AlertDialog;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.widget.TextView;

import com.jtang.android.R;

public class MyToast{

	static AlertDialog ad;
	Context context;
	long delayMills=0;
	View view;
	Handler handler;
	public MyToast(Context context) {
		
		ad = new AlertDialog.Builder(context).create();
		this.context=context;
		handler=new Handler()
		{
			@Override
			public void handleMessage(Message msg) {
				// TODO Auto-generated method stub
				super.handleMessage(msg);
				switch(msg.what)
				{
				case 0:
					ad.dismiss();
					break;
				}
			}
			
		};
	}

	public static MyToast makeText(Context context, CharSequence text, int duration) {
		// AlertDialog ad=new AlertDialog.Builder(context).create();
		MyToast myToast = new MyToast(context);
		myToast.setMessage(text);
		return myToast;
	}
	public static MyToast makeText(Context context, int resId, int duration) {
		return makeText(context,context.getResources().getString(resId),duration);
	}
	
	public void setMessage(CharSequence message) {
		LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		view = inflate.inflate(R.layout.my_toast, null);
		TextView tv = (TextView) view.findViewById(R.id.message);
		tv.setText(message);
		//根据文本长度设置显示的时间
		delayMills=143*message.length();
	}

	public void show() {
		ad.show();
		Window window = ad.getWindow();
		window.setContentView(view);
		new Thread()
		{
			public void run()
			{
				try {
					sleep(delayMills);
					handler.sendEmptyMessage(0);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}.start();
	}

}

以上的代码还有问题,当连续调用两次时,显示的效果不是像Toast一样按顺序显示信息,而是直接再开一个对话框,并且,在第二个对话框关闭后,第一个对话框就一直留着。
下面的代码在以上基础上做了修改,增加了单例模式,完全实现Toast的效果。



package com.jtang.android.components;

import java.util.LinkedList;
import java.util.Queue;

import android.app.AlertDialog;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.widget.TextView;

import com.jtang.android.R;

public class MyToast {

	AlertDialog ad;
	Context context;
	long delayMills = 0;
	View view;
	Handler handler;
	//单例,是因为有时候会在一次提示没结束时弹出第二次提示,要实现像Toast一样,顺序提示,只能单例了
	static MyToast instance;
	//存储信息内容的列队
	Queue messages;
	TextView tv;
	CharSequence message;
	//当前是否正在显示
	boolean isShowing=false;
	public MyToast(Context context) {
		messages = new LinkedList();
		ad = new AlertDialog.Builder(context).create();
		
		this.context = context;
		LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		view = inflate.inflate(R.layout.my_toast, null);
		tv = (TextView) view.findViewById(R.id.message);
		
		final Window window = ad.getWindow();
		//setContentView之前如果不调show方法会异常
		ad.show();
		window.setContentView(view);
		ad.hide();
		handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				// TODO Auto-generated method stub
				super.handleMessage(msg);
				switch (msg.what) {
				case 0:
					setMessage(message);
					ad.show();
					break;
				case 1:
					ad.hide();
					break;
				case 2:
					ad.dismiss();
					break;
				}
			}

		};
	}

	public static MyToast makeText(Context context, CharSequence text, int duration) {
		//构建新实例
		if (instance==null) {
			instance = new MyToast(context);
		}
		//把消息添加进列队
		instance.addMessage(text);
		return instance;
	}

	public static MyToast makeText(Context context, int resId, int duration) {
		return makeText(context, context.getResources().getString(resId), duration);
	}

	public void setMessage(CharSequence message) {
		tv.setText(message);
	}

	public void addMessage(CharSequence message)
	{
		messages.offer(message);
	}
	public void show() {

		//如果在上一条没显示完的时候,再次调用show()方法,直接返回
		if(isShowing)
		{
			return;
		}
		isShowing=true;
		new Thread() {
			public void run() {
				//取出信息,循环显示
				while((message=messages.poll()) != null)
				{
					handler.sendEmptyMessage(0);
					//根据信息长度计算显示时间
					delayMills=143*message.length();
					try {
						sleep(delayMills);
						//隐藏
						handler.sendEmptyMessage(1);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
						handler.sendEmptyMessage(1);
					}
				}
				//全部显示完,dismiss对话框
				handler.sendEmptyMessage(2);
				//把当前实例设为null,下次再调用时重新构建,之所以这么干,是因为窗口会按建构的顺序显示
				//如果不重新构建,在之后创建的Dialog中如果要调用这个show方法,就会显示在之后创建的Dialog后面,谁最后创建,谁在最前。
				instance=null;
			}
		}.start();
	}


}

© 2012, 冰冻鱼. 请尊重作者劳动成果,复制转载保留本站链接! 应用开发笔记