![](http://upload-images.jianshu.io/upload_images/828721-e0fc168c7e6ce054.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

之前写过一篇没时间解释了,快使用Snackbar!——Android Snackbar花式使用指南。Toast的自定义使用原理与其类似。

1.Toast源码分析

老规矩,我们先去看Toast的源码。

Toast有两种显示布局方式,一种最常见调用Toast.makeText(),看源码是这样写的

`<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Toast <span class="hljs-title">makeText</span>(<span class="hljs-params">Context context, CharSequence text, @Duration <span class="hljs-keyword">int</span> duration</span>) </span>{
Toast result = <span class="hljs-keyword">new</span> Toast(context);

LayoutInflater inflate = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflate.inflate(com.android.<span class="hljs-keyword">internal</span>.R.layout.transient_notification, <span class="hljs-keyword">null</span>);
TextView tv = (TextView)v.findViewById(com.android.<span class="hljs-keyword">internal</span>.R.id.message);
tv.setText(text);

result.mNextView = v;
result.mDuration = duration;

<span class="hljs-keyword">return</span> result;
}`

transient_notification这个布局文件代码是这样的

`<span class="hljs-tag"><<span class="hljs-title">LinearLayout</span> <span class="hljs-attribute">xmlns:android</span>=<span class="hljs-value">"http://schemas.android.com/apk/res/android"</span>
<span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span>
<span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"match_parent"</span>
<span class="hljs-attribute">android:orientation</span>=<span class="hljs-value">"vertical"</span>
<span class="hljs-attribute">android:background</span>=<span class="hljs-value">"?android:attr/toastFrameBackground"</span>></span>

<span class="hljs-tag"><<span class="hljs-title">TextView</span>
<span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@android:id/message"</span>
<span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"wrap_content"</span>
<span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span>
<span class="hljs-attribute">android:layout_weight</span>=<span class="hljs-value">"1"</span>
<span class="hljs-attribute">android:layout_gravity</span>=<span class="hljs-value">"center_horizontal"</span>
<span class="hljs-attribute">android:textAppearance</span>=<span class="hljs-value">"@style/TextAppearance.Toast"</span>
<span class="hljs-attribute">android:textColor</span>=<span class="hljs-value">"@color/bright_foreground_dark"</span>
<span class="hljs-attribute">android:shadowColor</span>=<span class="hljs-value">"#BB000000"</span>
<span class="hljs-attribute">android:shadowRadius</span>=<span class="hljs-value">"2.75"</span>
/></span>

<span class="hljs-tag"></<span class="hljs-title">LinearLayout</span>></span>`

那么我们想要修改Toast的文字消息样式,其实就是修改Toast根布局和message这个TextView。

Toast的另外一种显示模式就是自定义布局显示。这个方法不调用Toast.makeText()方法,而是new一个Toast对象,然后调用setView()方法。当然自定义布局就不会加载transient_notification布局了。

2.实现花式Toast

先给大家看下我封装的工具类ToastUtil。

`<span class="hljs-keyword">import</span> android.content.Context;
<span class="hljs-keyword">import</span> android.view.View;
<span class="hljs-keyword">import</span> android.widget.LinearLayout;
<span class="hljs-keyword">import</span> android.widget.TextView;
<span class="hljs-keyword">import</span> android.widget.Toast;

<span class="hljs-comment">/**
 * Created by 赵晨璞 on 2016/8/11.
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ToastUtil</span> </span>{

<span class="hljs-keyword">private</span>  Toast toast;
<span class="hljs-keyword">private</span> LinearLayout toastView;

<span class="hljs-comment">/**
 * 修改原布局的Toast
 */</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ToastUtil</span><span class="hljs-params">()</span> </span>{

}

<span class="hljs-comment">/**
 * 完全自定义布局Toast
 * <span class="hljs-doctag">@param</span> context
 * <span class="hljs-doctag">@param</span> view
 */</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ToastUtil</span><span class="hljs-params">(Context context, View view,<span class="hljs-keyword">int</span> duration)</span></span>{
    toast=<span class="hljs-keyword">new</span> Toast(context);
    toast.setView(view);
    toast.setDuration(duration);
}

<span class="hljs-comment">/**
 * 向Toast中添加自定义view
 * <span class="hljs-doctag">@param</span> view
 * <span class="hljs-doctag">@param</span> postion
 * <span class="hljs-doctag">@return</span>
 */</span>
<span class="hljs-function"><span class="hljs-keyword">public</span>  ToastUtil <span class="hljs-title">addView</span><span class="hljs-params">(View view,<span class="hljs-keyword">int</span> postion)</span> </span>{
    toastView = (LinearLayout) toast.getView();
    toastView.addView(view, postion);

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
}

<span class="hljs-comment">/**
 * 设置Toast字体及背景颜色
 * <span class="hljs-doctag">@param</span> messageColor
 * <span class="hljs-doctag">@param</span> backgroundColor
 * <span class="hljs-doctag">@return</span>
 */</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> ToastUtil <span class="hljs-title">setToastColor</span><span class="hljs-params">(<span class="hljs-keyword">int</span> messageColor, <span class="hljs-keyword">int</span> backgroundColor)</span> </span>{
    View view = toast.getView();
    <span class="hljs-keyword">if</span>(view!=<span class="hljs-keyword">null</span>){
       TextView message=((TextView) view.findViewById(android.R.id.message));
        message.setBackgroundColor(backgroundColor);
        message.setTextColor(messageColor);
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
}

<span class="hljs-comment">/**
 * 设置Toast字体及背景
 * <span class="hljs-doctag">@param</span> messageColor
 * <span class="hljs-doctag">@param</span> background
 * <span class="hljs-doctag">@return</span>
 */</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> ToastUtil <span class="hljs-title">setToastBackground</span><span class="hljs-params">(<span class="hljs-keyword">int</span> messageColor, <span class="hljs-keyword">int</span> background)</span> </span>{
    View view = toast.getView();
    <span class="hljs-keyword">if</span>(view!=<span class="hljs-keyword">null</span>){
        TextView message=((TextView) view.findViewById(android.R.id.message));
        message.setBackgroundResource(background);
        message.setTextColor(messageColor);
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
}

<span class="hljs-comment">/**
 * 短时间显示Toast
 */</span>
<span class="hljs-function"><span class="hljs-keyword">public</span>  ToastUtil <span class="hljs-title">Short</span><span class="hljs-params">(Context context, CharSequence message)</span></span>{
    <span class="hljs-keyword">if</span>(toast==<span class="hljs-keyword">null</span>||(toastView!=<span class="hljs-keyword">null</span>&&toastView.getChildCount()><span class="hljs-number">1</span>)){
        toast= Toast.makeText(context, message, Toast.LENGTH_SHORT);
        toastView=<span class="hljs-keyword">null</span>;
    }<span class="hljs-keyword">else</span>{
        toast.setText(message);
        toast.setDuration(Toast.LENGTH_SHORT);
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
}

<span class="hljs-comment">/**
 * 短时间显示Toast
 */</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> ToastUtil <span class="hljs-title">Short</span><span class="hljs-params">(Context context, <span class="hljs-keyword">int</span> message)</span> </span>{
    <span class="hljs-keyword">if</span>(toast==<span class="hljs-keyword">null</span>||(toastView!=<span class="hljs-keyword">null</span>&&toastView.getChildCount()><span class="hljs-number">1</span>)){
        toast= Toast.makeText(context, message, Toast.LENGTH_SHORT);
        toastView=<span class="hljs-keyword">null</span>;
    }<span class="hljs-keyword">else</span>{
        toast.setText(message);
        toast.setDuration(Toast.LENGTH_SHORT);
    }
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
}

<span class="hljs-comment">/**
 * 长时间显示Toast
 */</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> ToastUtil <span class="hljs-title">Long</span><span class="hljs-params">(Context context, CharSequence message)</span></span>{
    <span class="hljs-keyword">if</span>(toast==<span class="hljs-keyword">null</span>||(toastView!=<span class="hljs-keyword">null</span>&&toastView.getChildCount()><span class="hljs-number">1</span>)){
        toast= Toast.makeText(context, message, Toast.LENGTH_LONG);
        toastView=<span class="hljs-keyword">null</span>;
    }<span class="hljs-keyword">else</span>{
        toast.setText(message);
        toast.setDuration(Toast.LENGTH_LONG);
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
}

<span class="hljs-comment">/**
 * 长时间显示Toast
 *
 * <span class="hljs-doctag">@param</span> context
 * <span class="hljs-doctag">@param</span> message
 */</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> ToastUtil <span class="hljs-title">Long</span><span class="hljs-params">(Context context, <span class="hljs-keyword">int</span> message)</span> </span>{
    <span class="hljs-keyword">if</span>(toast==<span class="hljs-keyword">null</span>||(toastView!=<span class="hljs-keyword">null</span>&&toastView.getChildCount()><span class="hljs-number">1</span>)){
        toast= Toast.makeText(context, message, Toast.LENGTH_LONG);
        toastView=<span class="hljs-keyword">null</span>;
    }<span class="hljs-keyword">else</span>{
        toast.setText(message);
        toast.setDuration(Toast.LENGTH_LONG);
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
}

<span class="hljs-comment">/**
 * 自定义显示Toast时间
 *
 * <span class="hljs-doctag">@param</span> context
 * <span class="hljs-doctag">@param</span> message
 * <span class="hljs-doctag">@param</span> duration
 */</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> ToastUtil <span class="hljs-title">Indefinite</span><span class="hljs-params">(Context context, CharSequence message, <span class="hljs-keyword">int</span> duration)</span> </span>{
    <span class="hljs-keyword">if</span>(toast==<span class="hljs-keyword">null</span>||(toastView!=<span class="hljs-keyword">null</span>&&toastView.getChildCount()><span class="hljs-number">1</span>)){
        toast= Toast.makeText(context, message,duration);
        toastView=<span class="hljs-keyword">null</span>;
    }<span class="hljs-keyword">else</span>{
        toast.setText(message);
        toast.setDuration(duration);
    }
     <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
}

<span class="hljs-comment">/**
 * 自定义显示Toast时间
 *
 * <span class="hljs-doctag">@param</span> context
 * <span class="hljs-doctag">@param</span> message
 * <span class="hljs-doctag">@param</span> duration
 */</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> ToastUtil <span class="hljs-title">Indefinite</span><span class="hljs-params">(Context context, <span class="hljs-keyword">int</span> message, <span class="hljs-keyword">int</span> duration)</span> </span>{
    <span class="hljs-keyword">if</span>(toast==<span class="hljs-keyword">null</span>||(toastView!=<span class="hljs-keyword">null</span>&&toastView.getChildCount()><span class="hljs-number">1</span>)){
        toast= Toast.makeText(context, message,duration);
        toastView=<span class="hljs-keyword">null</span>;
    }<span class="hljs-keyword">else</span>{
        toast.setText(message);
        toast.setDuration(duration);
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
}

<span class="hljs-comment">/**
 * 显示Toast
 * <span class="hljs-doctag">@return</span>
 */</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> ToastUtil <span class="hljs-title">show</span> <span class="hljs-params">()</span></span>{
    toast.show();

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
}

<span class="hljs-comment">/**
 * 获取Toast
 * <span class="hljs-doctag">@return</span>
 */</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> Toast <span class="hljs-title">getToast</span><span class="hljs-params">()</span></span>{
    <span class="hljs-keyword">return</span> toast;
}
}`

修改Toast背景色的使用法方法如下:

`<span class="hljs-type">ToastUtil</span> toastUtil=<span class="hljs-keyword">new</span> <span class="hljs-type">ToastUtil</span>();
toastUtil.<span class="hljs-type">Short</span>(<span class="hljs-type">MainActivity</span>.<span class="hljs-keyword">this</span>,<span class="hljs-string">"自定义message字体、背景色"</span>).setToastColor(<span class="hljs-type">Color</span>.<span class="hljs-type">WHITE</span>, getResources().getColor(<span class="hljs-type">R</span>.color.colorAccent)).show();`
![](http://upload-images.jianshu.io/upload_images/828721-66195248a10c3434.gif?imageMogr2/auto-orient/strip)
修改Toast背景色

方形的Toast看上去有些呆板,我自定义了一个名为toast_radius.xml的背景,代码如下:

`<span class="hljs-pi"><?xml version="1.0" encoding="utf-8"?></span>
<span class="hljs-tag"><<span class="hljs-title">shape</span>
<span class="hljs-attribute">xmlns:android</span>=<span class="hljs-value">"http://schemas.android.com/apk/res/android"</span>
<span class="hljs-attribute">android:shape</span>=<span class="hljs-value">"rectangle"</span>></span>
<span class="hljs-comment"><!-- 填充的颜色 --></span>
<span class="hljs-tag"><<span class="hljs-title">solid</span> <span class="hljs-attribute">android:color</span>=<span class="hljs-value">"#ffc107"</span> /></span>

<span class="hljs-comment"><!-- android:radius 弧形的半径 --></span>
<span class="hljs-tag"><<span class="hljs-title">corners</span> <span class="hljs-attribute">android:radius</span>=<span class="hljs-value">"20dip"</span> /></span>

<span class="hljs-tag"></<span class="hljs-title">shape</span>></span>`

然后上面设置背景的代码改成:

`<span class="hljs-tag">toastUtil</span><span class="hljs-class">.Short</span>(<span class="hljs-tag">MainActivity</span><span class="hljs-class">.this</span>,"自定义<span class="hljs-tag">message</span>字体颜色和背景")<span class="hljs-class">.setToastBackground</span>(<span class="hljs-tag">Color</span><span class="hljs-class">.WHITE</span>,<span class="hljs-tag">R</span><span class="hljs-class">.drawable</span><span class="hljs-class">.toast_radius</span>)<span class="hljs-class">.show</span>();`
![](http://upload-images.jianshu.io/upload_images/828721-575d63beed215b00.gif?imageMogr2/auto-orient/strip)
修改了背景的Toast

虽然官方认为Toast和Snackbar都应该是短文本的形式,不能包含图标,但是个人感觉加上图标还是挺好玩的…

向Toast中添加图标可以这样:

` ImageView toastImage = <span class="hljs-keyword">new</span> ImageView(getApplicationContext());
 toastImage.setImageResource(R.mipmap.ic_launcher);
 toastUtil.Short(MainActivity.<span class="hljs-keyword">this</span>,<span class="hljs-string">"向Toast添加了一个ImageView"</span>).setToastBackground(Color.WHITE,R.drawable.toast_radius).addView(toastImage,<span class="hljs-number">0</span>).show();`
![](http://upload-images.jianshu.io/upload_images/828721-ada7364a24c915ae.gif?imageMogr2/auto-orient/strip)
添加图标的Toast

如果你想要Toast显示自定义的布局,可以这样:

` View view = LayoutInflater.<span class="hljs-keyword">from</span>(MainActivity.<span class="hljs-keyword">this</span>).inflate(R.layout.image,<span class="hljs-keyword">null</span>);
 <span class="hljs-keyword">new</span> ToastUtil(MainActivity.<span class="hljs-keyword">this</span>,view,Toast.LENGTH_SHORT).show();`
![](http://upload-images.jianshu.io/upload_images/828721-f95a07f3fe9144af.gif?imageMogr2/auto-orient/strip)
自定义布局Toast,我的布局文件中只有一个默认图标的ImageView

大家都知道,连续触发Toast的show()方法的时候,Toast就会排着队连续展示,感觉上不太友好。所以我先判断了toast是否没被创建或者是否被添加了额外的view,如果是的话就重新生成一个toast对象;如果否的话就只修改message文字和显示时间。

![](http://upload-images.jianshu.io/upload_images/828721-ccb92e45086fe98a.gif?imageMogr2/auto-orient/strip)
Toast布局修改,不排队显示

我这个工具类不是完全体,大家再根据自己项目的具体需求进行修改。 []( ̄▽ ̄)*

 

转自:http://www.jianshu.com/p/5c5c8ee31ddb