1. 程式人生 > >Android Toast使用的簡單小結

Android Toast使用的簡單小結

老規矩,先上效果圖吧

主要實現了幾種常用的方式:

1.最基本的Toast

系統自帶Toast採用的是佇列的方式, 等當前Toast消失後, 下一個Toast才能顯示出來;原因是Toast的管理是在佇列中,點選一次,就會產生一個新的Toast,要等這個佇列中的Toast處理完,這個顯示Toast的任務才算結束。 so~ 我們可以把Toast改成單例模式,沒有Toast再新建它,這樣也就解決了連續點選Toast,一直在顯示的問題。

2.自定義位置的Toast

3.自定義佈局(帶圖片)的Toast

4.自定義帶動畫效果的Toast控制元件

OK,下面上程式碼

程式碼實現:

先上Activity的程式碼

public class ToastActivity extends BaseTitleActivity {

    @BindView(R.id.btn_basic_toast)
    Button basicToast;
    @BindView(R.id.btn_basic_toast2)
    Button basicToast2;
    @BindView(R.id.btn_custom_location)
    Button customLocation;
    @BindView(R.id.btn_custom_picture)
    Button customPicture;
    @BindView(R.id.btn_custom_smile)
    Button customSmile;
    @BindView(R.id.btn_custom_smile2)
    Button customSmile2;

//    private static CustomToast customToastView;


    public static void newInstance(Context context){

        Intent intent = new Intent(context, ToastActivity.class);
        context.startActivity(intent);
    }

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

    @Override
    public int getResourcesId() {
        return R.layout.activity_toast;
    }

    @Override
    public void initView() {

    }

    @Override
    public void initData() {

    }

    @Override
    public int getTitleText() {
        return R.string.play_toast;
    }

    @OnClick( {R.id.btn_basic_toast, R.id.btn_custom_location, R.id.btn_custom_picture, R.id.btn_custom_smile, R.id.btn_custom_smile2,
                R.id.btn_basic_toast2} )
    public void onViewClick(View v){

        switch (v.getId()){

            /*  最基本的Toast,解決了原生Toast不能快速更新的問題 */
            case R.id.btn_basic_toast:
                ToastUtils.showToast(this, "這是最基本的Toast");
                break;
            case R.id.btn_basic_toast2:
                ToastUtils.showToast(this, "===已更新===");
                break;

            /* 自定義位置的Toast
             * 相對於Gravity.LEFT位置, x方向上的偏移量, y方向上的偏移量 */
            case R.id.btn_custom_location:
                Toast toast = Toast.makeText(ToastActivity.this, "自定義位置的Toast", Toast.LENGTH_SHORT);
                toast.setGravity(Gravity.LEFT,0, 0);
                toast.show();
                break;

            /* 帶圖片的Toast,自定義佈局
             * 參考 Toast.makeText() 方法 */
            case R.id.btn_custom_picture:
                Toast result = new Toast(this);
                View toastView = LayoutInflater.from(this).inflate(R.layout.toast_custom, null);
                ImageView img = (ImageView) toastView.findViewById(R.id.iv_img);
                TextView msg = (TextView) toastView.findViewById(R.id.tv_msg);
                img.setImageResource(R.mipmap.jyfr_icon_mpossh3x);
                msg.setText(R.string.picture_toast);

                result.setView(toastView);
                result.setGravity(Gravity.BOTTOM, 0 , 0);
                result.setDuration(Toast.LENGTH_SHORT);
                result.show();
                break;

            /* 自定義Toast控制元件,帶個動畫效果
             * 解決了原生Toast不能快速更新的問題
             * 但是並沒有擺脫原生Toast顯示方法的呼叫 */
            case R.id.btn_custom_smile:
                ToastUtils.showToast(this, "在看我", true);
                break;
            case R.id.btn_custom_smile2:
                ToastUtils.showToast(this, "==還在看我==", true);
                break;

            default:
                break;
        }
    }
}

對應的佈局程式碼較為簡單,就不貼了

下面是第四種效果實現的佈局

<?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:padding="10dp"
    android:background="@drawable/shape_background_toast">

    <ImageView
        android:id="@+id/iv_img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:scaleType="center"
        android:visibility="visible"/>

    <com.example.xuetaotao.helloworld.widget.CustomToast
        android:id="@+id/smileView"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_margin="10dp"
        android:layout_gravity="center" />

    <TextView
        android:id="@+id/tv_msg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text=""
        android:textSize="18sp"
        android:textColor="@color/common_blue"/>

</LinearLayout>

接著是自定義控制元件部分的程式碼

public class CustomToast extends View {

    /**
     * 初始化一些變數
     * 實現3個建構函式
     * 初始化畫筆引數和矩形引數
     * 設定畫筆的引數及矩形的引數
     * 重寫onMeasure:onMeasure()方法中主要負責測量,決定控制元件本身或其子控制元件所佔的寬高
     * 重寫onDraw:onDraw()方法負責繪製,即如果我們希望得到的效果在Android原生控制元件中沒有現成的支援,那麼我們就需要自己繪製我們的自定義控制元件的顯示效果。
     * 自定義View中的動畫效果實現
     */
    private Toast toast;
    private Context context;

    RectF rectF = new RectF();  //矩形,設定Toast佈局時使用
    ValueAnimator valueAnimator;    //屬性動畫
    private Paint paint;    //自定義View的畫筆

    float mAnimatedValue = 0f;
    private float mWidth = 0f;  //view的寬
    private float mPadding = 0f;    //view的內邊距
    private float endAngle = 0f;    //圓弧結束的度數

    private float mEyeWidth = 0f;   //笑臉的眼睛半徑
    private boolean isSmileLeft = false;
    private boolean isSmileRight = false;

    public CustomToast(Context context){
        super(context);
        this.context = context;
    }

    public CustomToast(Context context, AttributeSet attrs){
        super(context, attrs);
        this.context = context;
    }

    public CustomToast(Context context, AttributeSet attrs, int defStyleAttr){
        super(context, attrs, defStyleAttr);
        this.context = context;
    }

    private void initPaint(){
        paint = new Paint();
        paint.setAntiAlias(true);   //抗鋸齒
        paint.setStyle(Paint.Style.STROKE); //畫筆的樣式:空心
        paint.setColor(Color.parseColor("#5cb85c"));    //繪製的顏色
        paint.setStrokeWidth(dip2px(2));    //設定筆刷的粗細
    }

    private void initRect(){
        rectF = new RectF(mPadding, mPadding, mWidth-mPadding, mWidth-mPadding);
    }

    //dip轉px。為了支援多解析度手機
    public int dip2px(float dpValue){
        final float scale = getContext().getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        initPaint();
        initRect();
        mWidth = getMeasuredWidth();    //view的寬度
        mPadding = dip2px(10);
        mEyeWidth = dip2px(3);
    }

    //每次觸摸了自定義View/ViewGroup時都會觸發onDraw()方法
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawArc(rectF, 180, endAngle, false, paint );    //畫微笑圓弧
        paint.setStyle(Paint.Style.FILL);   //畫筆的樣式:實心
        if (isSmileLeft){
            canvas.drawCircle(mPadding+mEyeWidth+mEyeWidth/2, mWidth/3, mEyeWidth, paint);  //繪製圓圈
        }
        if (isSmileRight){
            canvas.drawCircle(mWidth-mPadding-mEyeWidth-mEyeWidth/2, mWidth/3, mEyeWidth, paint);
        }
    }

    //開啟動畫
    public void startAnimator(boolean playAnimate){
        if (playAnimate){
            stopAnimator();
            startViewAnim(0f, 1f, 2000);
        }
    }

    //停止動畫
    public void stopAnimator(){
        if (valueAnimator != null){
            clearAnimation();
            isSmileLeft = false;
            isSmileRight = false;
            mAnimatedValue = 0f;
            valueAnimator.end();
        }
    }

    /**
     * 開始動畫
     * @param start 起始值
     * @param end   結束值
     * @param time  動畫的時間
     * @return
     */
    public ValueAnimator startViewAnim(float start, float end, long time){

        valueAnimator = ValueAnimator.ofFloat(start, end);  //設定 ValueAnimator 的起始值和結束值
        valueAnimator.setDuration(time);    //設定動畫時間
        valueAnimator.setInterpolator(new LinearInterpolator());    //設定補間器,控制動畫的變化速率
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {    //設定監聽器。監聽動畫值的變化,做出相應方式
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mAnimatedValue = (float) valueAnimator.getAnimatedValue();
                if (mAnimatedValue < 0.5){
                    isSmileLeft = false;
                    isSmileRight = false;
                    endAngle = -360 * (mAnimatedValue);
                } else if (mAnimatedValue > 0.55 && mAnimatedValue < 0.7){
                    endAngle = -180;
                    isSmileLeft = true;
                    isSmileRight = false;
                } else{
                    endAngle = -180;
                    isSmileLeft = true;
                    isSmileRight = true;
                }
                postInvalidate();      //重繪
            }
        });

        if (!valueAnimator.isRunning()){
            valueAnimator.start();
        }
        return valueAnimator;
    }

    /**
     * 本質上還是依賴Android原生Toast的顯示方法來進行顯示,
     * 只是引入了自定義的佈局,添加了自定義動畫
     */
    public void show(String message, boolean playAnimate){

        /* 解決多次點選Toast一直提示不消失問題 */
        if (toast == null){
            toast = new Toast(context);
        }
        View customToastView = LayoutInflater.from(context).inflate(R.layout.toast_custom, null);
        TextView msg2 = (TextView) customToastView.findViewById(R.id.tv_msg);
        msg2.setText(message);
        msg2.setBackgroundResource(R.drawable.shape_text_toast);
        msg2.setTextColor(Color.parseColor("#ffffff"));

        ImageView img2 = (ImageView) customToastView.findViewById(R.id.iv_img);
        img2.setImageResource(R.mipmap.jyfr_icon_mpossh3x);
//        img2.setVisibility(View.GONE);

        CustomToast customToast = (CustomToast) customToastView.findViewById(R.id.smileView);
        customToast.startAnimator(playAnimate);

        toast.setView(customToastView);
        toast.setGravity(Gravity.BOTTOM, 0 , 0);
        toast.setDuration(Toast.LENGTH_SHORT);
        toast.show();
    }

}

最後把效果一和四共用到的工具類貼上來,主要是為了解決連續點選Toast,一直在顯示的問題。補充一點:效果四仍然是基於系統原生Toast的顯示方法來顯示的,所以那個連續點選一直顯示的問題還是存在的,後面再試試不用這種方式吧。

public class ToastUtils {

    private static Toast toast;

    private static CustomToast customToast;

    /**
     * 自定義CustomToast的顯示
     * @param context   上下文
     * @param message   提示內容
     * @param playAnimate   是否顯示動畫  true,顯示     false,不顯示
     */
    public static void showToast(Context context, String message, boolean playAnimate){

        if (customToast == null){
            customToast = new CustomToast(context);
        }
        customToast.show(message, playAnimate);
    }


    /**
     * Android原生Toast的顯示,主要解決點多少就提示多少次的問題
     */
    public static void showToast(Context context, String content){

        if (toast == null){
            toast = Toast.makeText(context, content, Toast.LENGTH_SHORT);
        } else {
            toast.setText(content);
        }
        toast.show();
    }

}

OK,完成,新手入門學習報到~

最後附上兩篇大佬的文章:

自定義View—自定義屬性及引用

Toast的高階自定義方式-循序漸進帶你瞭解toast