首页 > 代码库 > Android自己定义Toast

Android自己定义Toast

一、引言

在开发的过程中你会发现Android自身的Toast提示有很多限制,比方我想自己定义Toast的动画、自己定义一个美观的View显示在Toast中、很多其它的是让Toast显示指定的时长等等。

首先一下效果怎样:

技术分享


二、原理

自己定义的原理也非常easy,就是给WindowManager加入View和删除View,只是须要设置WindowManager.LayoutParams和View的样式。使其看起来和Android系统的Toast看起来非常相像。

详细代码例如以下:

/**
 * Custom Toast
 * 
 * @author Lucky
 * 
 */
public class ToastHelper {
	public static final int LENGTH_LONG = 3500;
	public static final int LENGTH_SHORT = 2000;
	private WindowManager mWindowManager;
	private WindowManager.LayoutParams mWindowParams;
	private View toastView;
	private Context mContext;
	private Handler mHandler;
	private String mToastContent = "";
	private int duration = 0;
	private int animStyleId = android.R.style.Animation_Toast;

	private final Runnable timerRunnable = new Runnable() {

		@Override
		public void run() {
			removeView();
		}
	};

	private ToastHelper(Context context) {
		// Notice: we should get application context
		// otherwise we will get error
		// "Activity has leaked window that was originally added"
		Context ctx = context.getApplicationContext();
		if (ctx == null) {
			ctx = context;
		}
		this.mContext = ctx;
		mWindowManager = (WindowManager) mContext
				.getSystemService(Context.WINDOW_SERVICE);
		init();
	}

	private void init() {
		mWindowParams = new WindowManager.LayoutParams();
		mWindowParams.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
				| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
				| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
		mWindowParams.alpha = 1.0f;
		mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
		mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
		mWindowParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
		mWindowParams.format = PixelFormat.TRANSLUCENT;
		mWindowParams.type = WindowManager.LayoutParams.TYPE_TOAST;
		mWindowParams.setTitle("ToastHelper");
		mWindowParams.packageName = mContext.getPackageName();
		mWindowParams.windowAnimations = animStyleId;// TODO
		mWindowParams.y = mContext.getResources().getDisplayMetrics().widthPixels / 5;
	}

	@SuppressWarnings("deprecation")
	@SuppressLint("NewApi")
	private View getDefaultToastView() {

		TextView view = new TextView(mContext);
		view.setText(mToastContent);
		view.setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
		view.setFocusable(false);
		view.setClickable(false);
		view.setFocusableInTouchMode(false);
		view.setTextColor(android.graphics.Color.WHITE);
		Drawable drawable = mContext.getResources().getDrawable(
				android.R.drawable.toast_frame);

		if (Build.VERSION.SDK_INT < 16) {
			view.setBackgroundDrawable(drawable);
		} else {
			view.setBackground(drawable);
		}
		return view;
	}

	public void show() {
		removeView();
		if (toastView == null) {
			toastView = getDefaultToastView();
		}
		mWindowParams.gravity = android.support.v4.view.GravityCompat
				.getAbsoluteGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM,
						android.support.v4.view.ViewCompat
								.getLayoutDirection(toastView));
		removeView();
		mWindowManager.addView(toastView, mWindowParams);
		if (mHandler == null) {
			mHandler = new Handler();
		}
		mHandler.postDelayed(timerRunnable, duration);
	}

	public void removeView() {
		if (toastView != null && toastView.getParent() != null) {
			mWindowManager.removeView(toastView);
			mHandler.removeCallbacks(timerRunnable);
		}
	}

	/**
	 * @param context
	 * @param content
	 * @param duration
	 * @return
	 */
	public static ToastHelper makeText(Context context, String content,
			int duration) {
		ToastHelper helper = new ToastHelper(context);
		helper.setDuration(duration);
		helper.setContent(content);
		return helper;
	}

	/**
	 * @param context
	 * @param strId
	 * @param duration
	 * @return
	 */
	public static ToastHelper makeText(Context context, int strId, int duration) {
		ToastHelper helper = new ToastHelper(context);
		helper.setDuration(duration);
		helper.setContent(context.getString(strId));
		return helper;
	}

	public ToastHelper setContent(String content) {
		this.mToastContent = content;
		return this;
	}

	public ToastHelper setDuration(int duration) {
		this.duration = duration;
		return this;
	}

	public ToastHelper setAnimation(int animStyleId) {
		this.animStyleId = animStyleId;
		mWindowParams.windowAnimations = this.animStyleId;
		return this;
	}

	/**
	 * custom view
	 * 
	 * @param view
	 */
	public ToastHelper setView(View view) {
		this.toastView = view;
		return this;
	}
}

另外分享一个自己定义的Anim:

1.显示Toast的动画:

<?xml version="1.0" encoding="utf-8"?

> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:fillAfter="true" > <alpha android:fromAlpha="0.0" android:toAlpha="1.0" /> <translate android:fromYDelta="20%" android:toYDelta="0%" /> <scale android:fromXScale="0.5" android:fromYScale="0.5" android:pivotX="50%" android:pivotY="50%" android:toXScale="1.0" android:toYScale="1.0" /> </set>


2.退出Toast的动画:

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fillAfter="true" >

    <alpha
        android:fromAlpha="1.0"
        android:toAlpha="0.0" />

    <translate
        android:fromYDelta="0%"
        android:toYDelta="20%" />

</set>


给WIndowManager中的View加入动画须要定义一个style,例如以下:

    <style name="PopToast">
        <item name="@android:windowEnterAnimation">@anim/anim_toast_enter</item>
        <item name="@android:windowExitAnimation">@anim/anim_toast_exit</item>
    </style>

最后能够依照例如以下的方式去使用:

ToastHelper
					.makeText(this, "hello world 你好。哈拉雷速度发说得对",
							ToastHelper.LENGTH_SHORT)
					.setAnimation(R.style.PopToast).show();


三、參考资料:

SuperToast: https://github.com/JohnPersano/SuperToasts

Android自己定义Toast