Android自定义Toast

本文介绍了如何通过XML自定义Toast样式以提高可视化效果并满足复杂需求,以及使用Dialog伪装Toast以获取焦点和实现特定事件响应。通过提供代码示例和详细解释,文章深入探讨了自定义提醒方式的技术实现和应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

场景

Toast作为一个基本的界面提醒方式,使用还是比较广,但是介于默认样式比较难看外加有些特殊要求,比如需要在Toast的界面上做事件处理啥的,所以衍生出了Toast的自定义样式

默认样式

    Toast tempToast = Toast.makeText(getApplicationContext(), "默认的Toast样式",
                Toast.LENGTH_LONG);
    //可以设置位置
    //tempToast.setGravity(Gravity.BOTTOM | Gravity.RIGHT, 10, 10);
    tempToast.show();

默认样式

对于这种基本的样式,在不同的android版本或者不同的rom显示不同,比如在官方的4.4的版本之后该Toast会变成蓝色背景,而之前的背景都是如图的黑色背景。简单场景能用,稍微需要显示复杂点的东西就无法使用了

XML自定义样式

然而大部分的使用情况肯定不限于该种样式,很多开发者希望Toast能够显示更多东西,如图片和文字按一定规则混排啥的,这个也非常简单,只需要自定义一个xml布局即可
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/llToast"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#ffffffff"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/tvTitleToast"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="1dip"
        android:background="#bb000000"
        android:gravity="center"
        android:text="Title"
        android:textColor="#ffffffff" />

    <LinearLayout
        android:id="@+id/llToastContent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="1dip"
        android:layout_marginLeft="1dip"
        android:layout_marginRight="1dip"
        android:background="#44000000"
        android:orientation="vertical"
        android:padding="15dip" >

        <ImageView
            android:id="@+id/tvImageToast"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:contentDescription="@string/hello_world"
            android:src="@drawable/ic_launcher" />

        <TextView
            android:id="@+id/tvTextToast"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:paddingLeft="10dip"
            android:paddingRight="10dip"
            android:singleLine="false"
            android:text="自定义显示语句"
            android:textColor="#ff000000" />
    </LinearLayout>

</LinearLayout>
然后再代码中,将该布局设置为Toast的View即可
    public void showCustomToast(View v) {
        // 通用的布局加载器
        LayoutInflater inflater = getLayoutInflater();
        // 加载根容器,方便用于后面的view的定位
        View layout = inflater.inflate(R.layout.toast_test,
                (ViewGroup) findViewById(R.id.llToast));
        // 设置图片的源文件
        ImageView image = (ImageView) layout.findViewById(R.id.tvImageToast);
        image.setImageResource(R.drawable.ic_launcher);
        // 设置title及内容
        TextView title = (TextView) layout.findViewById(R.id.tvTitleToast);
        title.setText("通知");
        TextView text = (TextView) layout.findViewById(R.id.tvTextToast);
        text.setText("通过XML自定义Toast");

        Toast tempToast = new Toast(getApplicationContext());
        // 设置位置
        tempToast.setGravity(Gravity.BOTTOM | Gravity.RIGHT, 10, 10);
        // 设置显示时间
        tempToast.setDuration(Toast.LENGTH_LONG);
        tempToast.setView(layout);
        tempToast.show();
    }

通过xml自定义Toast

通过XML对Toast进行自定义后,可视化效果提高了很多,也能满足基本的现实要求了。
但是由于Toast的组件属性,导致其不能获取焦点,也就是我无法在上面获取onclick等事件,假设我想在Toast上增加一个关闭按钮,或者点击Toast的主体内容即可跳转一个网页啥的,这个时候基本的Toast就无法满足了

使用Dialog伪装Toast

当然,不仅限于Dialog,任何View都可以进行自定义布局然后伪装成Toast,只是Dialog提供好了show方法和dissmis方法,所以工作量比较小,就使用Dialog进行伪装而已
首先要去除Dialog的基本样式,也就是不能带有原有的基本边框,所以我们需要先定义一个需要的dialog的主题
    <style name="ToastDialog" parent="@android:Theme.Dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowNoTitle">true</item> 
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:backgroundDimEnabled">false</item>
    </style>
代码的意思就是单纯的英文意思,就不做翻译了,这样就吧dialog剥成了一个什么都没有的浮动view
下面对dialog的样式进行定义,也就是layout,跟上一段代码差不多,我们增加一个关闭按钮
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/llToast"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#ffffffff"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/tvTitleToast"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_margin="1dip"
            android:background="#bb000000"
            android:gravity="center"
            android:text="Title"
            android:textColor="#ffffffff" />

        <ImageView
            android:id="@+id/ivClose"
            android:layout_marginRight="1dip"
            android:layout_marginTop="1dip"
            android:layout_marginBottom="1dip"
            android:background="#bb000000"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:src="@android:drawable/presence_offline" />

    </LinearLayout>

    <LinearLayout
        android:id="@+id/llToastContent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="1dip"
        android:layout_marginLeft="1dip"
        android:layout_marginRight="1dip"
        android:background="#44000000"
        android:orientation="vertical"
        android:padding="15dip" >

        <ImageView
            android:id="@+id/tvImageToast"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:contentDescription="@string/hello_world"
            android:src="@drawable/ic_launcher" />

        <TextView
            android:id="@+id/tvTextToast"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:paddingLeft="10dip"
            android:paddingRight="10dip"
            android:singleLine="false"
            android:text="自定义显示语句"
            android:textColor="#ff000000" />
    </LinearLayout>

</LinearLayout>
接下来则是需要自定义一个dlalog的类,考虑到只是个教程,所以都是以最简单的方法进行编写
public class MyToastDialog extends Dialog {

    // 显示的时间,用于模拟Toast的duringTime
    private long showTime;

    // 显示结束后自动关闭dialog的线程
    private Runnable autoDissmis = new Runnable() {

        @Override
        public void run() {
            try {
                Thread.sleep(showTime);
                // 注意进行是否存在显示的判定
                if (isShowing()) {
                    dismiss();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };

    public MyToastDialog(Context context, long duringTime) {
        // 设置dialog的主题
        super(context, R.style.ToastDialog);
        // 设置dlaog的样式,把它放在构造函数里的好处在于:也可以再外面使用setContentView进行重新设定
        setContentView(R.layout.toast_test_dialog);
        showTime = duringTime;
    }

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

        // 通过获取dialog的windows对象对位置坐标进行设置
        Window dialogWindow = this.getWindow();
        WindowManager.LayoutParams lp = dialogWindow.getAttributes();
        dialogWindow.setGravity(Gravity.BOTTOM | Gravity.RIGHT);

        lp.x = 10; // 新位置X坐标
        lp.y = 10; // 新位置Y坐标
        // lp.width = 300; // 宽度
        // lp.height = 300; // 高度
        // lp.alpha = 1f; // 透明度

        dialogWindow.setAttributes(lp);
    }

    @Override
    public void show() {
        // 重构show函数,在show的同时 启动计时进程
        new Thread(autoDissmis).start();
        super.show();
    }

}
然后再代码中调用显示,并且设置想要设置的事件相应即可
    public void showToastDialog(View v) {
        long duringTime = 3000;
        final MyToastDialog tempDialog = new MyToastDialog(this, duringTime);

        ImageView image = (ImageView) tempDialog.findViewById(R.id.ivClose);
        image.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                tempDialog.dismiss();
            }
        });

        tempDialog.show();
    }
上图:

使用Dialog伪造Toast

这个的好处在于,可以获取Toast对象的焦点,可以实现像QQ左下角弹出对话框一样的东东~~估计还是有点点用处

总结

其实伪造的并不是很成功,因为Toast不获取焦点也有不获取焦点的好处,这样不会妨碍Toast显示过程中对后面界面的操作,但是一旦获取焦点之后,后面的界面就会变得无法操作,难免造成不良体验,当然需求总是仁者见仁智者见智,考虑实际场景选择合适的做法才是最优解决方案
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值