Button in custom Android Toast?

不羁岁月 提交于 2019-11-27 04:13:25

A toast can not be clicked. It is not possible to capture a click inside a toast message. You will need to build a dialog for that. Look at Creating Dialogs for more info.

The API on the Toast class state that a toast will never receive the focus and because a toast is not a view there is no onClick message. I would assume that therefore childs of a Toast can not be clicked as well.

A toast cant contain a button. Except that the gmail app and the gallery app in jelly beans have a semi toast that contains a button, here is how Google did it

https://gist.github.com/benvd/4090998

I guess this answers your question.

Snippet shows implementation of custom Toast that:

  • Have similar interface as original Toast class
  • Can be used as Dialog (have clickable buttons like Gmail app)
  • Have possibility to set length in millis
  • Have possibility to set show and cancel animation
  • Lives only with initialized Activity

Current Limitations:

  • No screen orientation change are supported

Usage:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //...

    View toastView = new View(getBaseContext());
    //init your toast view

    ActivityToast toast = new ActivityToast(this, toastView);

    //set toast Gravity ( Gravity.BOTTOM | Gravity.FILL_HORIZONTAL by default)
    toast.setGravity(Gravity.CENTER);

    toast.setLength(10000); //set toast show duration to 10 seconds (2 seconds by default)

    Animation showAnim; // init animation
    Animation.AnimationListener showAnimListener; //init anim listener
    toast.setShowAnimation(showAnim);
    toast.setShowAnimationListener(showAnimListener);

    Animation cancelAnim; // init animation
    Animation.AnimationListener cancelAnimListener; //init anim listener
    toast.setCancelAnimation(showAnim);
    toast.setCancelAnimationListener(showAnimListener);

    toast.show(); //show toast view
    toast.isShowing(); // check if toast is showing now
    toast.cancel(); //cancel toast view

    toast.getView(); //get toast view to update it or to do something ..
}

Sources

import android.app.Activity;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.FrameLayout;

public class ActivityToast {

    public static final long LENGTH_SHORT = 2000;
    public static final long LENGTH_LONG = 3000;
    public static final int DEFAULT_ANIMATION_DURATION = 400;

    private final Activity mActivity;
    private FrameLayout.LayoutParams mLayoutParams;

    private Handler mHandler = new Handler();

    private ViewGroup mParent;
    private FrameLayout mToastHolder;
    private View mToastView;

    private Animation mShowAnimation;
    private Animation mCancelAnimation;

    private long mLength = LENGTH_SHORT;

    private Animation.AnimationListener mShowAnimationListener;
    private Animation.AnimationListener mCancelAnimationListener;

    private boolean mIsAnimationRunning;
    private boolean mIsShown;

    /**
     * @param activity Toast will be shown at top of the widow of this Activity
     */
    public ActivityToast(@NonNull Activity activity, View toastView) {
        mActivity = activity;

        mParent = (ViewGroup) activity.getWindow().getDecorView();
        mToastHolder = new FrameLayout(activity.getBaseContext());
        mLayoutParams = new FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT,
                Gravity.BOTTOM | Gravity.FILL_HORIZONTAL
        );
        mToastHolder.setLayoutParams(mLayoutParams);

        mShowAnimation = new AlphaAnimation(0.0f, 1.0f);
        mShowAnimation.setDuration(DEFAULT_ANIMATION_DURATION);
        mShowAnimation.setAnimationListener(mHiddenShowListener);

        mCancelAnimation = new AlphaAnimation(1.0f, 0.0f);
        mCancelAnimation.setDuration(DEFAULT_ANIMATION_DURATION);
        mCancelAnimation.setAnimationListener(mHiddenCancelListener);

        mToastView = toastView;
        mToastHolder.addView(mToastView);

        mToastHolder.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                    cancel();
                }
                return false;
            }
        });
    }

    public void show() {
        if (!isShowing()) {
            mParent.addView(mToastHolder);
            mIsShown = true;

            if (mShowAnimation != null) {
                mToastHolder.startAnimation(mShowAnimation);
            } else {
                mHandler.postDelayed(mCancelTask, mLength);
            }
        }
    }

    public void cancel() {
        if (isShowing() && !mIsAnimationRunning) {
            if (mCancelAnimation != null) {
                mToastHolder.startAnimation(mCancelAnimation);
            } else {
                mParent.removeView(mToastHolder);
                mHandler.removeCallbacks(mCancelTask);
                mIsShown = false;
            }
        }
    }

    public boolean isShowing() {
        return mIsShown;
    }

    /**
     * Pay attention that Action bars is the part of Activity window
     *
     * @param gravity Position of view in Activity window
     */

    public void setGravity(int gravity) {
        mLayoutParams.gravity = gravity;

        if (isShowing()) {
            mToastHolder.requestLayout();
        }
    }

    public void setShowAnimation(Animation showAnimation) {
        mShowAnimation = showAnimation;
    }

    public void setCancelAnimation(Animation cancelAnimation) {
        mCancelAnimation = cancelAnimation;
    }

    /**
     * @param cancelAnimationListener cancel toast animation. Note: you should use this instead of
     *                                Animation.setOnAnimationListener();
     */
    public void setCancelAnimationListener(Animation.AnimationListener cancelAnimationListener) {
        mCancelAnimationListener = cancelAnimationListener;
    }

    /**
     * @param showAnimationListener show toast animation. Note: you should use this instead of
     *                              Animation.setOnAnimationListener();
     */
    public void setShowAnimationListener(Animation.AnimationListener showAnimationListener) {
        mShowAnimationListener = showAnimationListener;
    }

    public void setLength(long length) {
        mLength = length;
    }

    public View getView() {
        return mToastView;
    }

    private Runnable mCancelTask = new Runnable() {
        @Override
        public void run() {
            cancel();
        }
    };

    private Animation.AnimationListener mHiddenShowListener = new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
            if (mShowAnimationListener != null) {
                mShowAnimationListener.onAnimationStart(animation);
            }

            mIsAnimationRunning = true;
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            mHandler.postDelayed(mCancelTask, mLength);

            if (mShowAnimationListener != null) {
                mShowAnimationListener.onAnimationEnd(animation);
            }

            mIsAnimationRunning = false;
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
            if (mShowAnimationListener != null) {
                mShowAnimationListener.onAnimationRepeat(animation);
            }
        }
    };

    private Animation.AnimationListener mHiddenCancelListener = new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
            if (mCancelAnimationListener != null) {
                mCancelAnimationListener.onAnimationStart(animation);
            }

            mIsAnimationRunning = true;
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            mParent.removeView(mToastHolder);
            mHandler.removeCallbacks(mCancelTask);

            if (mCancelAnimationListener != null) {
                mCancelAnimationListener.onAnimationEnd(animation);
            }

            mIsAnimationRunning = false;
            mIsShown = false;
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
            if (mCancelAnimationListener != null) {
                mCancelAnimationListener.onAnimationRepeat(animation);
            }
        }
    };
}

My original post on github
Post that shows implementation of custom layout in this post

A custom view passed to a toast can contain anything; however, toasts cannot receive any touch events so no components that use touch events will work in a stock toast (buttons, radiobuttons, etc.). The only choice you have is to create a custom view with a button in it and add it to your layout. There are many examples of how to do this and a few libraries you can check out to see how other people are doing it.

UndoBar
MessageBar
Nurik's UndoBar

Of course you are also welcome to use the SuperToasts library I put together however it might be a little overkill for one usage. The way that I do it is outlined in the SuperActivityToast class.

You should use a Snackbar. It is in the latest android support library(at time of answer) and is compatible with older api levels. It is much easier to implement than a Dialog or custom View and has the ability to have a button unlike a Toast.

  1. Download Android Support Library from Extras in the SDK Manager(revision 22.2.1 or later).
  2. In the build.gradle add this to the class dependencies: com.android.support:design:22.2.0.
  3. Implement:

    Snackbar.make(this.findViewById(android.R.id.content), "Toast Message", Snackbar.LENGTH_LONG) .setAction("Click here to activate action", onClickListener) .setActionTextColor(Color.RED) .show;

And that is it. No github projects and implementation is very similiar to Toast. I used it in one of my projects and it works great.

You can try SuperToast in this case. It can create toast with button. It has custom duration feature, colourful background, colourful fonts, custom fonts, animated effect. Hope u will enjoy it

Use an alertbox, if you want to add a button :-). Here are some examples Dialog boxes in Android

Martijn de Langh

Creating a system overlay window (always on top)

This is suggesting that it can be done, I also need buttons in a toast so I still have to make my own implementation. If I find more I will add it to my post

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!