• Android自定义Toast


    场景

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

    默认样式

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

    默认样式

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

    XML自定义样式

    然而大部分的使用情况肯定不限于该种样式,很多开发者希望Toast能够显示更多东西,如图片和文字按一定规则混排啥的,这个也非常简单,只需要自定义一个xml布局即可
    
     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:id="@+id/llToast"
     4     android:layout_width="wrap_content"
     5     android:layout_height="wrap_content"
     6     android:background="#ffffffff"
     7     android:orientation="vertical" >
     8 
     9     <TextView
    10         android:id="@+id/tvTitleToast"
    11         android:layout_width="match_parent"
    12         android:layout_height="wrap_content"
    13         android:layout_margin="1dip"
    14         android:background="#bb000000"
    15         android:gravity="center"
    16         android:text="Title"
    17         android:textColor="#ffffffff" />
    18 
    19     <LinearLayout
    20         android:id="@+id/llToastContent"
    21         android:layout_width="wrap_content"
    22         android:layout_height="wrap_content"
    23         android:layout_marginBottom="1dip"
    24         android:layout_marginLeft="1dip"
    25         android:layout_marginRight="1dip"
    26         android:background="#44000000"
    27         android:orientation="vertical"
    28         android:padding="15dip" >
    29 
    30         <ImageView
    31             android:id="@+id/tvImageToast"
    32             android:layout_width="wrap_content"
    33             android:layout_height="wrap_content"
    34             android:layout_gravity="center"
    35             android:contentDescription="@string/hello_world"
    36             android:src="@drawable/ic_launcher" />
    37 
    38         <TextView
    39             android:id="@+id/tvTextToast"
    40             android:layout_width="wrap_content"
    41             android:layout_height="wrap_content"
    42             android:gravity="center"
    43             android:paddingLeft="10dip"
    44             android:paddingRight="10dip"
    45             android:singleLine="false"
    46             android:text="自定义显示语句"
    47             android:textColor="#ff000000" />
    48     </LinearLayout>
    49 
    50 </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的主题
    
    1     <style name="ToastDialog" parent="@android:Theme.Dialog">
    2         <item name="android:windowFrame">@null</item>
    3         <item name="android:windowNoTitle">true</item> 
    4         <item name="android:windowIsFloating">true</item>
    5         <item name="android:windowContentOverlay">@null</item>
    6         <item name="android:backgroundDimEnabled">false</item>
    7     </style>
    代码的意思就是单纯的英文意思,就不做翻译了,这样就吧dialog剥成了一个什么都没有的浮动view
    下面对dialog的样式进行定义,也就是layout,跟上一段代码差不多,我们增加一个关闭按钮
    
     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:id="@+id/llToast"
     4     android:layout_width="wrap_content"
     5     android:layout_height="wrap_content"
     6     android:background="#ffffffff"
     7     android:orientation="vertical" >
     8 
     9     <LinearLayout
    10         android:layout_width="match_parent"
    11         android:layout_height="wrap_content"
    12         android:orientation="horizontal" >
    13 
    14         <TextView
    15             android:id="@+id/tvTitleToast"
    16             android:layout_width="0dp"
    17             android:layout_height="wrap_content"
    18             android:layout_weight="1"
    19             android:layout_margin="1dip"
    20             android:background="#bb000000"
    21             android:gravity="center"
    22             android:text="Title"
    23             android:textColor="#ffffffff" />
    24 
    25         <ImageView
    26             android:id="@+id/ivClose"
    27             android:layout_marginRight="1dip"
    28             android:layout_marginTop="1dip"
    29             android:layout_marginBottom="1dip"
    30             android:background="#bb000000"
    31             android:layout_width="wrap_content"
    32             android:layout_height="match_parent"
    33             android:src="@android:drawable/presence_offline" />
    34 
    35     </LinearLayout>
    36 
    37     <LinearLayout
    38         android:id="@+id/llToastContent"
    39         android:layout_width="wrap_content"
    40         android:layout_height="wrap_content"
    41         android:layout_marginBottom="1dip"
    42         android:layout_marginLeft="1dip"
    43         android:layout_marginRight="1dip"
    44         android:background="#44000000"
    45         android:orientation="vertical"
    46         android:padding="15dip" >
    47 
    48         <ImageView
    49             android:id="@+id/tvImageToast"
    50             android:layout_width="wrap_content"
    51             android:layout_height="wrap_content"
    52             android:layout_gravity="center"
    53             android:contentDescription="@string/hello_world"
    54             android:src="@drawable/ic_launcher" />
    55 
    56         <TextView
    57             android:id="@+id/tvTextToast"
    58             android:layout_width="wrap_content"
    59             android:layout_height="wrap_content"
    60             android:gravity="center"
    61             android:paddingLeft="10dip"
    62             android:paddingRight="10dip"
    63             android:singleLine="false"
    64             android:text="自定义显示语句"
    65             android:textColor="#ff000000" />
    66     </LinearLayout>
    67 
    68 </LinearLayout>
    接下来则是需要自定义一个dlalog的类,考虑到只是个教程,所以都是以最简单的方法进行编写
    
     1 public class MyToastDialog extends Dialog {
     2 
     3     // 显示的时间,用于模拟Toast的duringTime
     4     private long showTime;
     5 
     6     // 显示结束后自动关闭dialog的线程
     7     private Runnable autoDissmis = new Runnable() {
     8 
     9         @Override
    10         public void run() {
    11             try {
    12                 Thread.sleep(showTime);
    13                 // 注意进行是否存在显示的判定
    14                 if (isShowing()) {
    15                     dismiss();
    16                 }
    17             } catch (InterruptedException e) {
    18                 e.printStackTrace();
    19             }
    20         }
    21     };
    22 
    23     public MyToastDialog(Context context, long duringTime) {
    24         // 设置dialog的主题
    25         super(context, R.style.ToastDialog);
    26         // 设置dlaog的样式,把它放在构造函数里的好处在于:也可以再外面使用setContentView进行重新设定
    27         setContentView(R.layout.toast_test_dialog);
    28         showTime = duringTime;
    29     }
    30 
    31     @Override
    32     protected void onCreate(Bundle savedInstanceState) {
    33         super.onCreate(savedInstanceState);
    34 
    35         // 通过获取dialog的windows对象对位置坐标进行设置
    36         Window dialogWindow = this.getWindow();
    37         WindowManager.LayoutParams lp = dialogWindow.getAttributes();
    38         dialogWindow.setGravity(Gravity.BOTTOM | Gravity.RIGHT);
    39 
    40         lp.x = 10; // 新位置X坐标
    41         lp.y = 10; // 新位置Y坐标
    42         // lp.width = 300; // 宽度
    43         // lp.height = 300; // 高度
    44         // lp.alpha = 1f; // 透明度
    45 
    46         dialogWindow.setAttributes(lp);
    47     }
    48 
    49     @Override
    50     public void show() {
    51         // 重构show函数,在show的同时 启动计时进程
    52         new Thread(autoDissmis).start();
    53         super.show();
    54     }
    55 
    56 }
    然后再代码中调用显示,并且设置想要设置的事件相应即可
    
     1     public void showToastDialog(View v) {
     2         long duringTime = 3000;
     3         final MyToastDialog tempDialog = new MyToastDialog(this, duringTime);
     4 
     5         ImageView image = (ImageView) tempDialog.findViewById(R.id.ivClose);
     6         image.setOnClickListener(new OnClickListener() {
     7 
     8             @Override
     9             public void onClick(View v) {
    10                 tempDialog.dismiss();
    11             }
    12         });
    13 
    14         tempDialog.show();
    15     }
    上图:
    

    使用Dialog伪造Toast

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

    总结

    其实伪造的并不是很成功,因为Toast不获取焦点也有不获取焦点的好处,这样不会妨碍Toast显示过程中对后面界面的操作,但是一旦获取焦点之后,后面的界面就会变得无法操作,难免造成不良体验,当然需求总是仁者见仁智者见智,考虑实际场景选择合适的做法才是最优解
  • 相关阅读:
    2011年3月21日星期一
    AutoCAD VBA尺寸标注
    2011年3月22日星期二
    The method isEmpty() is undefined for the type String/String类型的isEmpty报错
    安全沙箱冲突..Error #2044: 未处理的 securityError:。 text=Error #2048: 安全沙箱冲
    Flash Builder4.6 无法启动,并且报 Failed to create the Java Virtual Machine (2—可能更好些)
    Flash Builder4.6 入门Demo_trace
    去掉JW Player水印及右键官方菜单
    JS如何判断单个radio是否被选中
    用JSON报错 java.lang.ClassNotFoundException: org.apache.commons.lang.exception.NestableRuntimeExcept .
  • 原文地址:https://www.cnblogs.com/coldcode/p/4504797.html
Copyright © 2020-2023  润新知