美文网首页自定义程序员Android知识
打造一个属于记几的自定义Toast

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

作者: Wang_Guan | 来源:发表于2017-03-20 08:54 被阅读283次

    好久不更,强更。

    作为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呗。(。・∀・)ノ゙嗨

    相关文章

      网友评论

      • BrokenDust:从来没有注意过的东西!见识了

      本文标题:打造一个属于记几的自定义Toast

      本文链接:https://www.haomeiwen.com/subject/ufyenttx.html