打造一个属于记几的自定义Toast

好久不更,强更。

作为Android开发人员,Toast对我们来说应该是老朋友了。Toast能在一个可视的界面给用户一些短暂的反馈,并且反馈完成后会自动消失。在APP开发过程中,Toast真的是一个不可或缺的角色。

提到Toast,很多童鞋信手拈来,三下五除二就撸出一个Toast,并展现在界面。

Toast.makeText(getApplicationContext(), 
"你觉得我美吗?n(*≧▽≦*)n", 
Toast.LENGTH_LONG).show();

这是Toast的一个基本使用了,这样能快速的创建一个Toast并且将它显示在界面上,但是。。。
但是这样创建的Toast的外观和手机系统主题有关,像我司这部测试机,4.4的系统,然后,你看到的Toast是酱紫的。┑( ̄Д  ̄)┍

呵呵哒

并且这样还有一个问题,就是Toast的位置永远都是在同一个地方的。这对于程序猿来说,就感觉太死了,一点都不灵活。那么,我们如何打造一个属于记几的自定义Toast呢?

查看Toast的API,发现有这么多的方法可以供我们使用。

返回值 方法名
void cancel()
如果视图正在显示,关闭视图。如果视图尚未显示,则不显示
int getDuration()
返回持续时间
int getGravity()
返回视图在屏幕中显示的位置
float getHorizontalMargin()
返回水平边距
float getVerticalMargin()
返回垂直边距
View getView()
返回视图
int getXOffset()
返回应用于Gravity的X方向上的偏移量,以像素为单位
int getYOffset()
返回应用于Gravity的Y方向上的偏移量,以像素为单位
static
Toast
makeText(Context context,CharSequence text,int duration)
创建一个包含文字的标准的Toast并返回
void setDuration(int duration)
设置视图显示时长
void setGravity(int gravity,int xOffset,int yOffset)
设置Toast在显示屏中的位置
void setMargin(float horizontalMargin,float verticalMargin)
设置视图的边距
void setText(int resId)
更新已makeText()方式创建的一个已存在的Toast的文字
void setText(CharSequence)
更新已makeText()方式创建的一个已存在的Toast的文字
void setView()
设置要显示的视图
void show()
返回视图在屏幕中显示的位置
int getGravity()
显示指定持续时长的视图

既然有了这些方法,我们就可以开始订制属于我们记几的Toast了。前几天在使用某个APP(忘记是哪个APP了)的时候看到一个比较有意思的显示方式。当我刷新的时候,APP弹出一个Toast显示正在刷新,然后刷新完成就告诉我刷新完成。我大致还原出来了,不过和原版还是有出入,以后优化吧。

Toast.gif

OK,那我们现在来实现上面的那个效果。我们从上面给出的方法可以看到,Toast有个setView()的方法,这个方法可以让我们传入自己的view。那现在,我们创建一个名字叫custom_toast的布局文件。

custom_toast.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/custom_toast"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/shape_corner_orange"
    android:orientation="horizontal"
    android:padding="8dp">

    <ImageView
        android:id="@+id/image_icon"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:padding="10dp"
        android:layout_gravity="center"
        android:src="@drawable/ic_check_white"
        android:visibility="gone" />

    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_gravity="center" />

    <TextView
        android:id="@+id/text_showText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="This is a custom toast!"
        android:textColor="@android:color/white"
        android:textSize="18sp" />

</LinearLayout>

布局文件有三个子控件,ImageView、ProgressBar和TextView。ImageView用来显示刷新完成后显示的icon,ProgressBar用于显示刷新时的显示旋转动态,最后TextView是用来显示我们的文本信息。这里需要注意,我们需要给根布局写一个id。

有了布局文件,我们就可以将我们的布局展示到Toast上。

mToastView = getLayoutInflater().inflate(R.layout.custom_toast,
        (ViewGroup) findViewById(R.id.custom_toast));
        mText = (TextView) mToastView.findViewById(R.id.text_showText);
        mPro = (ProgressBar) mToastView.findViewById(R.id.progressBar);
        mImg = (ImageView) mToastView.findViewById(R.id.image_icon);

        mToast = new Toast(getApplicationContext());
        mToast.setDuration(Toast.LENGTH_LONG);
        mToast.setView(mToastView);

通常情况下,我们加载一个布局大多都会这样写:

view = getLayoutInflater().inflate(R.layout.custom_toast, null);

但是,这里需要注意,我们不能这样写,这里我们需要用xml和根布局的ID来加载布局。到此,我们调用show()方法,我们的自定义Toast就能在屏幕上显示出来了。但是,现在Toast的时长是Toast.LENGTH_LONG。如果我们想要实现加载完毕后再消失,这明显是不能符合我们的需求的。咦上面不是有一个setDuration()方法吗,我们设置想要的时长就好啦,机智!O(∩_∩)O~

But!!!

坑爹1
坑爹2

看到了吗?

并不行!!!

setDuration()只接受两个值,一个是Toast.LENGTH_LONG,另外一个是Toast.LENGTH_SHORT。那没办法了,只能想其他的办法了。我们发现,当对同一个Toast实例调用show()方法时,它能一直显示,那好,我们就从这里下手了。

这里我们用到Timer来实现我们的功能。

                //设置显示位置为上方并且水平居中,然后偏移量为actionBar的高度加30
 mToast.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, getSupportActionBar().getHeight() + 30);
                mText.setText("Refreshing...");
                mPro.setVisibility(View.VISIBLE);
                mImg.setVisibility(View.GONE);

                //计时器,用于显示一个自定义时长的Toast
                final Timer timer = new Timer();
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        mToast.show();
                    }
                }, 0, 3000);
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        timer.cancel();
                        mHandler.sendEmptyMessage(0);
                    }
                }, 5000);

当要显示Toast的时候,我们新建一个定时器,这个定时器执行了两个任务,一个任务时控制Toast能持续的显示,另外一个任务是为了模拟网络加载,加载5s钟后即加载完成。然后发送消息通知加载完成,更新Toast视图。

这里给大家提个醒,Toast的创建方式有两种,一种是同个makeText()的方式来创建,另一种是通过构造函数也就是new的方式来创建,如果不需要用到setView()的话,官方推荐使用通过makeText()方法来创建一个Toast,因为通过构造函数的方法来创建,返回的Toast,是一个没有具体视图的Toast,如果直接使用的话会报错。

到这里我们的实现就算完成了。贴一下完整代码。

Activity.java
package com.kenny.mycustom;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import java.util.Timer;
import java.util.TimerTask;

public class SecondActivity extends BaseActivity {
    private static final String TAG = SecondActivity.class.getSimpleName();
    private Toast mToast;
    private Button btn;
    private View mToastView;
    private TextView mText;
    private ProgressBar mPro;
    private ImageView mImg;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            mText.setText("Finished!");
            mImg.setVisibility(View.VISIBLE);
            mPro.setVisibility(View.GONE);
            mToast.setDuration(Toast.LENGTH_LONG);
            mToast.show();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        btn = (Button) findViewById(R.id.btn);
        mToastView = getLayoutInflater().inflate(R.layout.custom_toast, (ViewGroup) findViewById(R.id.custom_toast));
        mText = (TextView) mToastView.findViewById(R.id.text_showText);
        mPro = (ProgressBar) mToastView.findViewById(R.id.progressBar);
        mImg = (ImageView) mToastView.findViewById(R.id.image_icon);

        mToast = new Toast(getApplicationContext());
        mToast.setDuration(Toast.LENGTH_LONG);
        mToast.setView(mToastView);


        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //设置显示位置为上方并且水平居中,然后偏移量为actionBar的高度加30
                mToast.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, getSupportActionBar().getHeight() + 30);
                mText.setText("Refreshing...");
                mPro.setVisibility(View.VISIBLE);
                mImg.setVisibility(View.GONE);

                //计时器,用于显示一个自定义时长的Toast
                final Timer timer = new Timer();
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        mToast.show();
                    }
                }, 0, 3000);
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        timer.cancel();
                        mHandler.sendEmptyMessage(0);
                    }
                }, 5000);
            }
        });

    }


}

感谢

http://www.jianshu.com/p/73b8b4768cf0

后记

1、这里自定义Toast起一个抛砖引玉的作用,相信大家以后可以根据自己的需求做出更有意思,更有创意,更炫酷的Toast。
2、代码逻辑并没有经过很缜密的思考,指在做一个例子便于讲解,有错漏之处,恳请谅解。
3、写这篇简书的原因主要是沉淀一下自己的学习知识。
4、既然都看到这了,留个脚印,给个like呗。(。・∀・)ノ゙嗨

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容