系统自带的Toast有时候不能满足我们的需求,现在提供一个可以快速替代Toast的方案。
项目地址:
源码:
用法:
详情看附件。
项目地址:
源码:
/* * Copyright 2012 Evgeny Shishkin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.devspark.appmsg.sample; import java.util.LinkedList; import java.util.Queue; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.AnimationUtils; /** * @author Evgeny Shishkin */ class MsgManager extends Handler { private static final int MESSAGE_DISPLAY = 0xc2007; private static final int MESSAGE_ADD_VIEW = 0xc20074dd; private static final int MESSAGE_REMOVE = 0xc2007de1; private static MsgManager mInstance; private Queue<AppMsg> msgQueue; private Animation inAnimation, outAnimation; private MsgManager() { msgQueue = new LinkedList<AppMsg>(); } /** * @return The currently used instance of the {@link MsgManager}. */ static synchronized MsgManager getInstance() { if (mInstance == null) { mInstance = new MsgManager(); } return mInstance; } /** * Inserts a {@link AppMsg} to be displayed. * * @param appMsg */ void add(AppMsg appMsg) { msgQueue.add(appMsg); if (inAnimation == null) { inAnimation = AnimationUtils.loadAnimation(appMsg.getActivity(), android.R.anim.fade_in); } if (outAnimation == null) { outAnimation = AnimationUtils.loadAnimation(appMsg.getActivity(), android.R.anim.fade_out); } displayMsg(); } /** * Removes all {@link AppMsg} from the queue. */ void clearMsg(AppMsg appMsg) { if(msgQueue.contains(appMsg)){ // Avoid the message from being removed twice. removeMessages(MESSAGE_REMOVE); msgQueue.remove(appMsg); removeMsg(appMsg); } } /** * Removes all {@link AppMsg} from the queue. */ void clearAllMsg() { if (msgQueue != null) { msgQueue.clear(); } removeMessages(MESSAGE_DISPLAY); removeMessages(MESSAGE_ADD_VIEW); removeMessages(MESSAGE_REMOVE); } /** * Displays the next {@link AppMsg} within the queue. */ private void displayMsg() { if (msgQueue.isEmpty()) { return; } // First peek whether the AppMsg is being displayed. final AppMsg appMsg = msgQueue.peek(); // If the activity is null we throw away the AppMsg. if (appMsg.getActivity() == null) { msgQueue.poll(); } final Message msg; if (!appMsg.isShowing()) { // Display the AppMsg msg = obtainMessage(MESSAGE_ADD_VIEW); msg.obj = appMsg; sendMessage(msg); } else { msg = obtainMessage(MESSAGE_DISPLAY); sendMessageDelayed(msg, appMsg.getDuration() + inAnimation.getDuration() + outAnimation.getDuration()); } } /** * Removes the {@link AppMsg}'s view after it's display duration. * * @param appMsg The {@link AppMsg} added to a {@link ViewGroup} and should be removed.s */ private void removeMsg(final AppMsg appMsg) { ViewGroup parent = ((ViewGroup) appMsg.getView().getParent()); if (parent != null) { outAnimation.setAnimationListener(new OutAnimationListener(appMsg)); appMsg.getView().startAnimation(outAnimation); // Remove the AppMsg from the queue. msgQueue.poll(); if (appMsg.isFloating()) { // Remove the AppMsg from the view's parent. parent.removeView(appMsg.getView()); } else { appMsg.getView().setVisibility(View.INVISIBLE); } Message msg = obtainMessage(MESSAGE_DISPLAY); sendMessage(msg); } } private void addMsgToView(AppMsg appMsg) { View view = appMsg.getView(); if (view.getParent() == null) { appMsg.getActivity().addContentView( view, appMsg.getLayoutParams()); } view.startAnimation(inAnimation); if (view.getVisibility() != View.VISIBLE) { view.setVisibility(View.VISIBLE); } final Message msg = obtainMessage(MESSAGE_REMOVE); msg.obj = appMsg; sendMessageDelayed(msg, appMsg.getDuration()); } @Override public void handleMessage(Message msg) { final AppMsg appMsg; switch (msg.what) { case MESSAGE_DISPLAY: displayMsg(); break; case MESSAGE_ADD_VIEW: appMsg = (AppMsg) msg.obj; addMsgToView(appMsg); break; case MESSAGE_REMOVE: appMsg = (AppMsg) msg.obj; removeMsg(appMsg); break; default: super.handleMessage(msg); break; } } private static class OutAnimationListener implements Animation.AnimationListener { private AppMsg appMsg; private OutAnimationListener(AppMsg appMsg) { this.appMsg = appMsg; } @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { if (!appMsg.isFloating()) { appMsg.getView().setVisibility(View.GONE); } } @Override public void onAnimationRepeat(Animation animation) { } } }
/* * Copyright 2012 Evgeny Shishkin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.devspark.appmsg.sample; import android.app.Activity; import android.content.Context; import android.content.res.Resources; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.widget.FrameLayout; import android.widget.TextView; /** * In-layout notifications. Based on {@link android.widget.Toast} notifications * and article by Cyril Mottier (http://android.cyrilmottier.com/?p=773). * * @author e.shishkin */ public class AppMsg { /** * Show the view or text notification for a short period of time. This time * could be user-definable. This is the default. * * @see #setDuration */ public static final int LENGTH_SHORT = 3000; /** * Show the view or text notification for a long period of time. This time * could be user-definable. * * @see #setDuration */ public static final int LENGTH_LONG = 5000; /** * Show the text notification for a long period of time with a negative style. */ public static final Style STYLE_ALERT = new Style(LENGTH_LONG, R.color.alert); /** * Show the text notification for a short period of time with a positive style. */ public static final Style STYLE_CONFIRM = new Style(LENGTH_SHORT, R.color.confirm); /** * Show the text notification for a short period of time with a neutral style. */ public static final Style STYLE_INFO = new Style(LENGTH_SHORT, R.color.info); private final Activity mContext; private int mDuration = LENGTH_SHORT; private View mView; private LayoutParams mLayoutParams; private boolean mFloating; /** * Construct an empty AppMsg object. You must call {@link #setView} before * you can call {@link #show}. * * @param context The context to use. Usually your * {@link android.app.Activity} object. */ public AppMsg(Activity context) { mContext = context; } /** * Make a {@link AppMsg} that just contains a text view. * * @param context The context to use. Usually your * {@link android.app.Activity} object. * @param text The text to show. Can be formatted text. * @param style The style with a background and a duration. */ public static AppMsg makeText(Activity context, CharSequence text, Style style) { return makeText(context, text, style, R.layout.app_msg); } /** * @author mengguoqiang 扩展支持设置字体大小 * Make a {@link AppMsg} that just contains a text view. * * @param context The context to use. Usually your * {@link android.app.Activity} object. * @param text The text to show. Can be formatted text. * @param style The style with a background and a duration. */ public static AppMsg makeText(Activity context, CharSequence text, Style style, float textSize) { return makeText(context, text, style, R.layout.app_msg, textSize); } /** * Make a {@link AppMsg} with a custom layout. The layout must have a {@link TextView} com id {@link android.R.id.message} * * @param context The context to use. Usually your * {@link android.app.Activity} object. * @param text The text to show. Can be formatted text. * @param style The style with a background and a duration. */ public static AppMsg makeText(Activity context, CharSequence text, Style style, int layoutId) { LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View v = inflate.inflate(layoutId, null); return makeText(context, text, style, v, true); } /** * @author mengguoqiang 扩展支持字体大小 * Make a {@link AppMsg} with a custom layout. The layout must have a {@link TextView} com id {@link android.R.id.message} * * @param context The context to use. Usually your * {@link android.app.Activity} object. * @param text The text to show. Can be formatted text. * @param style The style with a background and a duration. */ public static AppMsg makeText(Activity context, CharSequence text, Style style, int layoutId, float textSize) { LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View v = inflate.inflate(layoutId, null); return makeText(context, text, style, v, true, textSize); } /** * Make a non-floating {@link AppMsg} with a custom view presented inside the layout. * It can be used to create non-floating notifications if floating is false. * * @param context The context to use. Usually your * {@link android.app.Activity} object. * @param customView * View to be used. * @param text The text to show. Can be formatted text. * @param style The style with a background and a duration. */ public static AppMsg makeText(Activity context, CharSequence text, Style style, View customView) { return makeText(context, text, style, customView, false); } /** * Make a {@link AppMsg} with a custom view. It can be used to create non-floating notifications if floating is false. * * @param context The context to use. Usually your * {@link android.app.Activity} object. * @param view * View to be used. * @param text The text to show. Can be formatted text. * @param style The style with a background and a duration. * @param floating true if it'll float. */ private static AppMsg makeText(Activity context, CharSequence text, Style style, View view, boolean floating) { return makeText(context, text, style, view, floating, 0); } /** * * @author mengguoqiang 扩展支持设置字体大小 * Make a {@link AppMsg} with a custom view. It can be used to create non-floating notifications if floating is false. * * @param context The context to use. Usually your * {@link android.app.Activity} object. * @param view * View to be used. * @param text The text to show. Can be formatted text. * @param style The style with a background and a duration. * @param floating true if it'll float. */ private static AppMsg makeText(Activity context, CharSequence text, Style style, View view, boolean floating, float textSize) { AppMsg result = new AppMsg(context); view.setBackgroundResource(style.background); TextView tv = (TextView) view.findViewById(android.R.id.message); if(textSize > 0) tv.setTextSize(textSize); tv.setText(text); result.mView = view; result.mDuration = style.duration; result.mFloating = floating; return result; } /** * Make a {@link AppMsg} with a custom view. It can be used to create non-floating notifications if floating is false. * * @param context The context to use. Usually your * {@link android.app.Activity} object. * @param resId The resource id of the string resource to use. Can be * formatted text. * @param style The style with a background and a duration. * @param floating true if it'll float. */ public static AppMsg makeText(Activity context, int resId, Style style, View customView, boolean floating) { return makeText(context, context.getResources().getText(resId), style, customView, floating); } /** * Make a {@link AppMsg} that just contains a text view with the text from a * resource. * * @param context The context to use. Usually your * {@link android.app.Activity} object. * @param resId The resource id of the string resource to use. Can be * formatted text. * @param style The style with a background and a duration. * @throws Resources.NotFoundException if the resource can't be found. */ public static AppMsg makeText(Activity context, int resId, Style style) throws Resources.NotFoundException { return makeText(context, context.getResources().getText(resId), style); } /** * Make a {@link AppMsg} with a custom layout using the text from a * resource. The layout must have a {@link TextView} com id {@link android.R.id.message} * * @param context The context to use. Usually your * {@link android.app.Activity} object. * @param resId The resource id of the string resource to use. Can be * formatted text. * @param style The style with a background and a duration. * @throws Resources.NotFoundException if the resource can't be found. */ public static AppMsg makeText(Activity context, int resId, Style style, int layoutId) throws Resources.NotFoundException { return makeText(context, context.getResources().getText(resId), style, layoutId); } /** * Show the view for the specified duration. */ public void show() { MsgManager manager = MsgManager.getInstance(); manager.add(this); } /** * @return <code>true</code> if the {@link AppMsg} is being displayed, else <code>false</code>. */ public boolean isShowing() { if (mFloating) { return mView != null && mView.getParent() != null; } else { return mView.getVisibility() == View.VISIBLE; } } /** * Close the view if it's showing, or don't show it if it isn't showing yet. * You do not normally have to call this. Normally view will disappear on its own * after the appropriate duration. */ public void cancel() { MsgManager.getInstance().clearMsg(this); } /** * Cancels all queued {@link AppMsg}s. If there is a {@link AppMsg} * displayed currently, it will be the last one displayed. */ public static void cancelAll() { MsgManager.getInstance().clearAllMsg(); } /** * Return the activity. */ public Activity getActivity() { return mContext; } /** * Set the view to show. * * @see #getView */ public void setView(View view) { mView = view; } /** * Return the view. * * @see #setView */ public View getView() { return mView; } /** * Set how long to show the view for. * * @see #LENGTH_SHORT * @see #LENGTH_LONG */ public void setDuration(int duration) { mDuration = duration; } /** * Return the duration. * * @see #setDuration */ public int getDuration() { return mDuration; } /** * Update the text in a AppMsg that was previously created using one of the makeText() methods. * * @param resId The new text for the AppMsg. */ public void setText(int resId) { setText(mContext.getText(resId)); } /** * Update the text in a AppMsg that was previously created using one of the makeText() methods. * * @param s The new text for the AppMsg. */ public void setText(CharSequence s) { if (mView == null) { throw new RuntimeException("This AppMsg was not created with AppMsg.makeText()"); } TextView tv = (TextView) mView.findViewById(android.R.id.message); if (tv == null) { throw new RuntimeException("This AppMsg was not created with AppMsg.makeText()"); } tv.setText(s); } /** * Gets the crouton's layout parameters, constructing a default if necessary. * * @return the layout parameters */ public LayoutParams getLayoutParams() { if (mLayoutParams == null) { mLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); } return mLayoutParams; } /** * Sets the layout parameters which will be used to display the crouton. * * @param layoutParams The layout parameters to use. * @return <code>this</code>, for chaining. */ public AppMsg setLayoutParams(LayoutParams layoutParams) { mLayoutParams = layoutParams; return this; } /** * Constructs and sets the layout parameters to have some gravity. * * @param gravity the gravity of the Crouton * @return <code>this</code>, for chaining. * @see android.view.Gravity */ public AppMsg setLayoutGravity(int gravity) { mLayoutParams = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, gravity); return this; } /** * Return the value of floating. * * @see #setFloating(boolean) */ public boolean isFloating() { return mFloating; } /** * Sets the value of floating. * * @param mFloating */ public void setFloating(boolean mFloating) { this.mFloating = mFloating; } /** * The style for a {@link AppMsg}. * * @author e.shishkin */ public static class Style { private final int duration; private final int background; /** * Construct an {@link AppMsg.Style} object. * * @param duration How long to display the message. Either * {@link #LENGTH_SHORT} or {@link #LENGTH_LONG} * @param resId resource for AppMsg background */ public Style(int duration, int resId) { this.duration = duration; this.background = resId; } /** * Return the duration in milliseconds. */ public int getDuration() { return duration; } /** * Return the resource id of background. */ public int getBackground() { return background; } @Override public boolean equals(Object o) { if (!(o instanceof AppMsg.Style)) { return false; } Style style = (Style) o; return style.duration == duration && style.background == background; } } }
用法:
/* * Copyright 2012 Evgeny Shishkin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.devspark.appmsg.sample; import android.app.Activity; import android.os.Bundle; import android.view.Gravity; import android.view.View; import android.widget.Button; import android.widget.CheckBox; /** * Sample of AppMsg library. * * @author Evgeny Shishkin * SherlockActivity */ public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } /** * Button onClick listener. * * @param v */ public void showAppMsg(View v) { final CharSequence msg = ((Button) v).getText(); final AppMsg.Style style; switch (v.getId()) { case R.id.alert: style = AppMsg.STYLE_ALERT; break; case R.id.confirm: style = AppMsg.STYLE_CONFIRM; break; case R.id.info: style = AppMsg.STYLE_INFO; break; case R.id.custom: style = new AppMsg.Style(AppMsg.LENGTH_SHORT, R.color.custom); break; default: return; } // create {@link AppMsg} with specify type AppMsg appMsg = AppMsg.makeText(this, msg, style); if (((CheckBox) (findViewById(R.id.bottom))).isChecked()) { appMsg.setLayoutGravity(Gravity.BOTTOM); } appMsg.show(); } }
详情看附件。