corner_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#8cc3ff"/>
<corners android:radius="10dp"/>
</shape>
selector_button.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#33FFFFFF"/>
<corners android:topRightRadius="2dp" android:bottomRightRadius="2dp"/>
</shape>
</item>
<item android:drawable="@android:color/transparent"/>
</selector>
xtoast_normal.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/corner_bg">
<TextView
android:id="@+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:paddingTop="12dp"
android:paddingBottom="14dp"
/>
</LinearLayout>
xtoast_bottom.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#46ff78">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:gravity="start"
android:singleLine="true"
android:ellipsize="end"
android:paddingLeft="24dp"
android:paddingRight="8dp"
android:paddingTop="14dp"
android:paddingBottom="12dp"/>
<View
android:id="@+id/divider"
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@drawable/selector_button"
android:paddingStart="8dp"
android:paddingLeft="8dp"
android:paddingEnd="12dp"
android:paddingRight="12dp" />
</LinearLayout>
</LinearLayout>
動畫工具類AnimationUtils
public class AnimationUtils {
public static final int ANIMATION_DEFAULT = 0X000;
public static final int ANIMATION_DRAWER = 0x001;
public static final int ANIMATION_SCALE = 0x002;
public static final int ANIMATION_PULL = 0X003;
public static AnimatorSet getShowAnimation(XToast xToast, int animationType){
switch (animationType){
case ANIMATION_DRAWER:
AnimatorSet drawerSet = new AnimatorSet();
drawerSet.playTogether(
ObjectAnimator.ofFloat(xToast.getView(), "translationY", -xToast.getView().getMeasuredHeight(), 0),
ObjectAnimator.ofFloat(xToast.getView(), "alpha", 0, 1)
);
drawerSet.setDuration(500);
return drawerSet;
case ANIMATION_SCALE:
AnimatorSet scaleSet = new AnimatorSet();
scaleSet.playTogether(
ObjectAnimator.ofFloat(xToast.getView(), "scaleX", 0, 1),
ObjectAnimator.ofFloat(xToast.getView(), "scaleY", 0, 1)
);
scaleSet.setDuration(500);
return scaleSet;
case ANIMATION_PULL:
AnimatorSet pullSet = new AnimatorSet();
pullSet.playTogether(
ObjectAnimator.ofFloat(xToast.getView(), "translationY", xToast.getView().getMeasuredHeight(), 0),
ObjectAnimator.ofFloat(xToast.getView(), "alpha", 0, 1)
);
pullSet.setDuration(500);
return pullSet;
default:
AnimatorSet defaultSet = new AnimatorSet();
defaultSet.play(ObjectAnimator.ofFloat(xToast.getView(), "alpha", 0, 1));
defaultSet.setDuration(500);
return defaultSet;
}
}
public static AnimatorSet getHideAnimation(XToast xToast,int animationType){
switch (animationType){
case ANIMATION_DRAWER:
AnimatorSet drawerSet = new AnimatorSet();
drawerSet.playTogether(
ObjectAnimator.ofFloat(xToast.getView(), "translationY", 0,-xToast.getView().getMeasuredHeight()),
ObjectAnimator.ofFloat(xToast.getView(), "alpha", 1, 0)
);
drawerSet.setDuration(500);
return drawerSet;
case ANIMATION_SCALE:
AnimatorSet scaleSet = new AnimatorSet();
scaleSet.playTogether(
ObjectAnimator.ofFloat(xToast.getView(),"scaleX",1,0),
ObjectAnimator.ofFloat(xToast.getView(),"scaleY",1,0)
);
scaleSet.setDuration(500);
return scaleSet;
case ANIMATION_PULL:
AnimatorSet pullSet = new AnimatorSet();
pullSet.playTogether(
ObjectAnimator.ofFloat(xToast.getView(),"translationY",0,xToast.getView().getMeasuredHeight()),
ObjectAnimator.ofFloat(xToast.getView(),"alpha",1,0)
);
pullSet.setDuration(500);
return pullSet;
default:
AnimatorSet defaultSet = new AnimatorSet();
defaultSet.play(ObjectAnimator.ofFloat(xToast.getView(), "alpha", 1, 0));
defaultSet.setDuration(500);
return defaultSet;
}
}
}
Toast類
public class XToast {
//general attributes:
private Context mContext;
private View mView;
private ViewGroup mViewGroup;
private ViewGroup mViewRoot;
private LayoutInflater mInflater;
private TextView mTextView;
private int mTextColor = Color.WHITE;
private int mTextSize = 20;
private String message;
private int mType = XTOAST_TYPE_NORMAL;
private AnimatorSet mShowAnimatorSet;
private AnimatorSet mHideAnimatorSet;
private int mShowAnimationType;
private int mHideAnimationType;
private int mDuration;
private int mBackgroundColor;
private OnDisappearListener mOnDisappearListener;
private XToastHandler mXToastHandler;
//normal type attributes:
private GradientDrawable mToastBackgound;
//bottom type attributes:
private Button mButton;
private String mButtonText;
private int mButtonTextSize = 20;
private int mButtonTextColor = Color.WHITE;
private OnButtonClickListener mOnClickListener;
public static final int XTOAST_DURATION_LONG = 3500;
public static final int XTOAST_DURATION_SHORT = 2000;
public static final int XTOAST_DURATION_SPECIAL = 5000;
public static final int XTOAST_TYPE_NORMAL = 1;
public static final int XTOAST_TYPE_BOTTOM = 2;
public interface OnDisappearListener{
void onDisappear(XToast xToast);
}
public interface OnButtonClickListener{
void click(XToast xToast);
}
public XToast(Context context)
{
this.mContext = context;
this.mInflater = LayoutInflater.from(context);
}
public XToast(Context context,String message,int type)
{
this.mContext = context;
this.message = message;
this.mType = type;
this.mInflater = LayoutInflater.from(context);
}
public static XToast create(Context context){
return new XToast(context);
}
//create a normal XToast
public static XToast create(Context context,String message){
return new XToast(context,message,XTOAST_TYPE_NORMAL);
}
public static XToast create(Context context,String message,int type){
return new XToast(context,message,type);
}
public XToast setType(int type){
this.mType = type;
return this;
}
public XToast setText(int resId){
this.message = mContext.getString(resId);
return this;
}
public XToast setText(String message){
this.message = message;
return this;
}
public String getText(){
return this.message;
}
public XToast setTextColor(int color){
mTextColor = color;
return this;
}
public XToast setTextSize(int size){
mTextSize = size;
return this;
}
public XToast setBackgroundColor(int color){
this.mBackgroundColor = color;
return this;
}
public XToast setView(View view){
this.mView = view;
return this;
}
public View getView(){
return this.mView;
}
public ViewGroup getViewGroup(){
return this.mViewGroup;
}
public ViewGroup getViewRoot(){
return this.mViewRoot;
}
public XToast setDuration(int duration){
this.mDuration = duration;
return this;
}
public int getDuration(){
return this.mDuration;
}
public XToast setAnimation(int animationType){
this.mShowAnimationType = animationType;
this.mHideAnimationType = animationType;
return this;
}
public XToast setShowAnimation(int animationType){
this.mShowAnimationType = animationType;
return this;
}
public AnimatorSet getShowAnimatorSet(){
return this.mShowAnimatorSet;
}
public XToast setHideAnimation(int animationType){
this.mHideAnimationType = animationType;
return this;
}
public AnimatorSet getHideAnimatorSet(){
return this.mHideAnimatorSet;
}
public XToast setOnDisappearListener(OnDisappearListener onDisappearListener){
this.mOnDisappearListener = onDisappearListener;
return this;
}
public OnDisappearListener getOnDisappearListener(){
return this.mOnDisappearListener;
}
public XToast setButtonText(String message){
mButtonText = message;
return this;
}
public XToast setButtonTextColor(int color){
mButtonTextColor = color;
return this;
}
public XToast setButtonTextSize(int size){
mButtonTextSize = size;
return this;
}
public XToast setButtonOnClickListener(OnButtonClickListener listener){
mOnClickListener = listener;
return this;
}
public boolean isShowing() {
return mView != null && mView.isShown();
}
private void dismiss(){
mXToastHandler.hideToast(this);
}
private void initViews() {
mViewRoot = (ViewGroup) ((Activity)mContext).findViewById(android.R.id.content);
switch (mType){
case XTOAST_TYPE_NORMAL:
initNormalViews();
break;
case XTOAST_TYPE_BOTTOM:
initBottomViews();
break;
default:
break;
}
//對mView的大小進行測量
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec((1<<30) -1, View.MeasureSpec.AT_MOST);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec((1<<30) -1,View.MeasureSpec.AT_MOST);
mView.measure(widthMeasureSpec,heightMeasureSpec);
}
private void initNormalViews(){
mViewGroup = new LinearLayout(mContext);
FrameLayout.LayoutParams mViewGroupParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
mViewGroupParams.gravity = Gravity.BOTTOM | Gravity.CENTER;
mViewGroupParams.bottomMargin = 200;
mViewGroup.setLayoutParams(mViewGroupParams);
mViewRoot.addView(mViewGroup);
//如果用戶沒有使用自己的View,那麼使用默認的mView
if(mView == null){
mView = mInflater.inflate(R.layout.xtoast_normal,mViewGroup,false);
mToastBackgound = (GradientDrawable) mView.getBackground();
mTextView = (TextView) mView.findViewById(R.id.message);
mTextView.setTextColor(mTextColor);
mTextView.setTextSize(mTextSize);
mTextView.setText(message);
if(mBackgroundColor != 0){
mToastBackgound.setColor(mBackgroundColor);
}
}
}
private void initBottomViews(){
mViewGroup = new LinearLayout(mContext);
FrameLayout.LayoutParams mViewGroupParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
mViewGroupParams.gravity = Gravity.BOTTOM;
mViewGroup.setLayoutParams(mViewGroupParams);
mViewRoot.addView(mViewGroup);
mView = mInflater.inflate(R.layout.xtoast_bottom, mViewGroup, false);
mView.setBackgroundColor(mBackgroundColor != 0 ? mBackgroundColor : 0xFF2F5DFF);
mTextView = (TextView) mView.findViewById(R.id.message);
mTextView.setTextColor(mTextColor);
mTextView.setTextSize(mTextSize);
mTextView.setText(message);
mButton = (Button) mView.findViewById(R.id.button);
mButton.setTextSize(mButtonTextSize);
mButton.setTextColor(mButtonTextColor);
mButton.setText(mButtonText);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
mOnClickListener.click(XToast.this);
}
});
//set the appropriate animation
mShowAnimationType = AnimationUtils.ANIMATION_PULL;
mHideAnimationType = AnimationUtils.ANIMATION_PULL;
//set the show duration.
setDuration(XTOAST_DURATION_SPECIAL);
}
public void show(){
//準備工作
initViews();
if(this.mShowAnimationType == 0)
this.mShowAnimatorSet = AnimationUtils.getShowAnimation(this,AnimationUtils.ANIMATION_DEFAULT);
else
this.mShowAnimatorSet = AnimationUtils.getShowAnimation(this,mShowAnimationType);
if(this.mHideAnimationType == 0)
this.mHideAnimatorSet = AnimationUtils.getHideAnimation(this, AnimationUtils.ANIMATION_DEFAULT);
else
this.mHideAnimatorSet = AnimationUtils.getHideAnimation(this,mHideAnimationType);
if(mDuration == 0)
mDuration = XTOAST_DURATION_SHORT;
mXToastHandler = XToastHandler.getInstance();
mXToastHandler.add(this);
}
}
public class XToastHandler extends Handler {
private static XToastHandler mToastHandler;
private final Queue<XToast> mQueue;
private final static int SHOW_TOAST = 0x123;
private final static int HIDE_TOAST = 0x456;
private final static int SHOWNEXT_TOAST = 0X789;
private XToastHandler(Looper looper)
{
super(looper);
mQueue = new LinkedList<>();
}
public synchronized static XToastHandler getInstance()
{
if(mToastHandler != null)
return mToastHandler;
else{
mToastHandler = new XToastHandler(Looper.getMainLooper());
return mToastHandler;
}
}
/**
* 該方法把XToast添加到消息隊列中
* @param xToast
*/
public void add(XToast xToast)
{
mQueue.offer(xToast);
showNextToast();
}
public void showNextToast()
{
if(mQueue.isEmpty()) return;
//獲取隊列頭部的XToast
XToast xToast = mQueue.peek();
if(!xToast.isShowing()){
Message message = Message.obtain();
message.what = SHOW_TOAST;
message.obj = xToast;
sendMessage(message);
}
}
@Override
public void handleMessage(Message msg) {
XToast xToast = (XToast) msg.obj;
switch (msg.what)
{
case SHOW_TOAST:
showToast(xToast);
break;
case HIDE_TOAST:
hideToast(xToast);
break;
case SHOWNEXT_TOAST:
showNextToast();
break;
}
}
public void hideToast(final XToast xToast) {
if(!xToast.isShowing()){
mQueue.remove(xToast);
return;
}
if(!mQueue.contains(xToast))
return;
AnimatorSet set = xToast.getHideAnimatorSet();
set.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
//如果動畫結束了,界面中移除mView
xToast.getViewRoot().removeView(xToast.getViewGroup());
if (xToast.getOnDisappearListener() != null){
xToast.getOnDisappearListener().onDisappear(xToast);
}
sendEmptyMessage(SHOWNEXT_TOAST);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
set.start();
mQueue.poll();
}
private void showToast(XToast xToast) {
//如果當前有XToast正在展示,直接返回
if(xToast.isShowing()) return;
//把mView添加到界面中,實現Toast效果
xToast.getViewGroup().addView(xToast.getView());
//獲取動畫效果
AnimatorSet set = xToast.getShowAnimatorSet();
set.start();
Message message = Message.obtain();
message.what = HIDE_TOAST;
message.obj = xToast;
sendMessageDelayed(message,xToast.getDuration());
}
}
使用方式
XToast.create(this).setText("hello world:)
.setAnimation(AnimationUtils.ANIMATION_DRAWER)
.setDuration(XToast.XTOAST_DURATION_SHORT)
.show();