教你如何高仿实现微信录音 Toast

Toast 介绍

平时我们在Android开发中会经常用到一个叫Toast的东西,官方解释如下:

A toast is a view containing a quick little message for the user. The toast class helps you create and show those. When the view is shown to the user, appears as a floating view over the application. It will never receive focus. The user will probably be in the middle of typing something else. The idea is to be as unobtrusive as possible, while still showing the user the information you want them to see. Two examples are the volume control, and the brief message saying that your settings have been saved.

Toast 最基本的用法很简单,不用说大家都会(这里切记要调用 show() 去显示)

1
2
3
public static void showToast(Context context){
    Toast.makeText(context, "欢迎关注水寒的CSDN博客", Toast.LENGTH_LONG).show();
}

显示Toast示例 显示Toast示例

自定义 Toast

上面的 Toast 一般显示在手机偏下的一个位置上,有的时候我们需要将这个 Toast 的位置或者内容进行修改,比如让显示在屏幕中间,让内容里面有图片,这样的修改也比较容易,Toast 有一个和 ActionBar 类似的方法 setView(),这个方法就是提供给我们自定义 Toast 的。

显示Toast示例 显示Toast示例

1
2
3
4
5
6
7
8
9
public static void showToast(Context context){
    LayoutInflater inflater = LayoutInflater.from(context);
    View toastView = inflater.inflate(R.layout.toast_test_custome, null);
    Toast toast = new Toast(context); 
    toast.setDuration(3000);
    toast.setView(toastView);                //设置自定义view
    toast.setGravity(Gravity.CENTER, 0, 0);  //控制显示到屏幕中间
    toast.show();                            //注意:一定要调用才能显示
}

布局文件如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/custom_toast_bg"
    android:padding="15dip"
    android:gravity="center_horizontal"
    android:orientation="vertical" >

    <ImageView 
        android:layout_width="80dip"
        android:layout_height="80dip"
        android:scaleType="centerCrop"
        android:src="@drawable/shuihan"/>

    <TextView 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dip"
        android:textSize="16sp"
        android:text="欢迎访问水寒的CSDN博客"
        android:textColor="#ffffff"/>
</LinearLayout>

为什么要改变 Toast 的显示时长

上面的自定义非常简单,但是我们要改变 Toast 的显示时间就比较麻烦了,因为 Toast 的 setDuration 方法只能填写两个值 2000ms 或者 3000ms.

显示Toast示例 显示Toast示例

不信你可以给 setDuration 设置一个 10000 它最长只显示 3s,网上有各种延长 Toast 的方法,基本上都是通过定时器来延长显示的。 那么我们接下来就要思考一个问题了,我们为什么要延迟 Toast 的时间?为什么不用 Dialog 或者 PopupWindow 来替代? 其实原因很简单,Toast 显示是不获取焦点的,所以 Toast 一般是用来提示用户的,而不影响用户的操作。我们可以用一个很简单的例子证明一下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
findViewById(R.id.test_toast_button).setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //showToast();
            showDialog();
            Log.d("shuihan", "----down----");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.d("shuihan", "----move----");
            break;
        case MotionEvent.ACTION_UP:
            Log.d("shuihan", "----up----");
            break;
        case MotionEvent.ACTION_CANCEL:
            Log.d("shuihan", "----cancel----");
            break;
        default:
            break;
        }
        return true;
    }
});

我们分别去在 ACTION_DOWN 的时候去显示一下 toast 和 dialog 你再对照输出日志看一下,就会明白。 我们在微信里面录音的时候会有一个 Toast 大家应该都见过,如下:

显示Toast示例 显示Toast示例

这个 Toast 的一个很重要的特点就是只要你按着不放它就不消失,也就是说它的显示时间可以长于 3s.

实现显示时间长于 3 的 Toast

我们采用的方式也是使用定时器来实现重复显示一个 toast 从而延长它的时间,我们先来看一个 android 里面的 CountDownTimer 的用法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
new CountDownTimer(30000, 1000) {

    public void onTick(long millisUntilFinished) {
        mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
    }

    public void onFinish() {
        mTextField.setText("done!");
    }
}.start();

这是官方文档上的一个例子,一个 30s 的倒计时,每隔 1s 调用一次 onTick 方法,该方法返回一个倒计时剩余时间,ok,接下来我们来看看 toast 怎么让他显示 30s.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* 显示Toast
* @param toast
* @param duration
*/
public static void showToast(final Toast toast, long duration, final OnToastStatus toastStatu) {
    final long tickTime = 200;
    mCountDownTimer = new CountDownTimer(duration, tickTime) {
        @Override
        public void onTick(long millisUntilFinished) {
            if(millisUntilFinished <= 200){
                showToast("最长可录制一分钟");
            }else{
                toast.show();
            }
        }

        @Override
        public void onFinish() {
            toast.cancel();
            if(toastStatu != null){
                toastStatu.toastStop();
            }
        }
    }.start();
}

public interface OnToastStatus{
    public void toastStop();
}

/**
    * 停止显示Toast
    */
public static void stopToast(Toast toast){
    if(toast != null){
        toast.cancel();
    }
    if(mCountDownTimer != null){
        mCountDownTimer.cancel();
    }
}