天天看点

Android自定义Toast一、引言二、原理三、参考资料:

一、引言

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

首先一下效果如何:

Android自定义Toast一、引言二、原理三、参考资料:

二、原理

自定义的原理也很简单,就是给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