关于弹窗Dialog,Toast,PopupWindow,SnackBar总结分析
目录介绍:
0.关于弹窗概述
1.关于Dialog简单介绍
2.关于Toast简单介绍
3.关于SnackBar简单介绍
4.关于PopupWindow简单介绍
5.关于弹框总结
好消息
- 博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计47篇[近20万字],转载请注明出处,谢谢!
- 链接地址:https://github.com/yangchong211/YCBlogs
- 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!
0.关于弹窗概述
- 弹窗的分类:应用窗口,子窗口,系统窗口
在Android中窗口是一个抽象的概念,每一个Activity就对应着一个窗口,而所有的窗口都是由视图(View)来呈现,而我们知道View构成的一个树形结构的视图就组成了一个Activity的界面了
- 应用窗口:所谓应用窗口指的就是该窗口对应一个Activity,因此,要创建应用窗口就必须在Activity中完成了。
- 子窗口:所谓子窗口指的是必须依附在某个父窗口之上。
- 系统窗口:所谓系统窗口指的是由系统进程创建,不依赖于任何应用或者不依附在任何父窗口之上。
-
窗口和窗口管理器类:Window,WindowManager
WindowManager
在WindowManager类的内部类LayoutParams中定义了以上三种窗口类型,我们暂且不管WindowManager类是干嘛的,直接看其内部类LayoutParams的实现。内部类LayoutParams其实是一组用于描述窗口(Window)参数的数据类,其中包括窗口的大小,类型,特征,软键盘输入法模式,相对位置以及动画,背景图像格式等等。分析WindowManager源代码
分析:WindowManager.LayoutParams继承自ViewGrop.LayoutParams用于描述Android窗口的参数。由上面代码定义我们知道关于窗口有以下几个重要的参数:
- width:描述窗口的宽度,该变量是父类ViewGroup.LayoutParams的成员变量。
- height:描述窗口的高度,该变量同样是父类ViewGroup.LayoutParams的成员变量。
- x:描述窗口的起点X轴的坐标。
- y:描述窗口起点Y轴的坐标。
- type:窗口的类型,分为三个大类型:应用窗口,子窗口,系统窗口。
- flag:窗口特征标记,比如是否全屏,是否隐藏标题栏等。
- gravity:窗口的对齐方式,居中还是置顶或者置底等等。
- 获取管理器WindowManager
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE)
2.关于Toast简单介绍
- Toast只会弹出一段信息,告诉用户某某事情已经发生了,过一段时间后就会自动消失。它不会阻挡用户的任何操作。
基本用法
Toast.makeText(context, "things happened", Toast.LENGTH_SHORT).show();
注意:Toast.LENGTH_SHORT表示显示时间较短,Toast.LENGTH_LONG表示显示时间较长
使用中遇到的问题
例如:当点击有些按钮,需要吐司进行提示时;快速连续点击了多次按钮,Toast就触发了多次。可能导致Toast就长时间关闭不掉了。又或者我们其实已在进行其他操作了,应该弹出新的Toast提示,而上一个Toast却还没显示结束。解决的办法
创建工具类:
/**
* 吐司工具类 避免点击多次导致吐司多次,最后导致Toast就长时间关闭不掉了
* @param context
* @param content
*/
private static Toast toast;
public static void showToast(Context context, String content) {
if (toast == null) {
toast = Toast.makeText(context, content, Toast.LENGTH_SHORT);
} else {
toast.setText(content);
}
toast.show();
}
- 这样用的原理
先判断Toast对象是否为空,如果是空的情况下才会调用makeText()方法来去生成一个Toast对象,否则就直接调用setText()方法来设置显示的内容,最后再调用show()方法将Toast显示出来。由于不会每次调用的时候都生成新的Toast对象,因此刚才我们遇到的问题在这里就不会出现
3.关于SnackBar简单介绍
- Snackbar和Toast比较相似,但是用途更加广泛,并且它是可以和用户进行交互的。Snackbar使用一个动画效果从屏幕的底部弹出来,过一段时间后也会自动消失。
- 简单使用方法
Snackbar.make(view, "确定是否删除",Snackbar.LENGTH_LONG)
.setAction("确定", new View.OnClickListener(){
@Override
public void onClick(View v) {
//点击事件
}
})
.show();
*
* 第一个参数需要传入一个view,只要是当前界面布局的任意一个view都可以,Snackbar会使用这个view来自动查找最外层的布局,用于展示Snackbar。make()方法是用来生成Snackbar的
* 第二个参数就是Snackbar中显示的内容
* 第三个参数是Snackbar显示的时长。这些和Toast都是类似的。
*
* setAction()方法可设置Snackbar右侧按钮,增加进行交互事件。如果不使用setAction()则只显示左侧message。
*
- 如何变色?
Snackbar和Toast的默认样式都很单一,但是有时我们希望把不同类型信息区别显示,从而使用户更容易注意到提示信息。所以使Snackbar变色是一个不错的想法。
Snackbar的官方API只提供了setActionTextColor()这个方法修改Action的文字颜色,这怎么办?查源码吧,哪里不会点哪里。
在源码中我们看到Snackbar内定义了一个继承自LinearLayout的内部类SnackbarLayout,Snackbar的样子就是由这个SnackbarLayout实现的。
SnackbarLayout中加载了R.layout.design_layout_snackbar_include布局文件
public static void setSnackBarColor(Snackbar snackbar, int messageColor, int backgroundColor) {
//获取Snackbar的view
View view = snackbar.getView();
if(view!=null){
//修改view的背景色
view.setBackgroundColor(backgroundColor);
//获取Snackbar的message控件,修改字体颜色
((TextView) view.findViewById(R.id.snackbar_text)).setTextColor(messageColor);
}
}
4.关于PopupWindow基本介绍
- PopupWindow 这个类用来实现一个弹出框,可以使用任意布局的 View 作为其内容,这个弹出框是悬浮在当前 activity 之上的。
- 悬浮窗
- 简单使用方法
private PopupWindow popMenu;
private View popMenuView;
private void showPublishDialog() {
if(popMenu!=null && popMenu.isShowing()){
return;
}
popMenuView = this.getLayoutInflater().inflate(R.layout.dialog_main_publish, null);
popMenu = new PopupWindow(popMenuView, RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT, true);
popMenu.setBackgroundDrawable(new ColorDrawable(Color.WHITE));
popMenu.setClippingEnabled(false); //允许弹出窗口超出屏幕范围
popMenu.setFocusable(true); //点击其他地方关闭
popMenu.setOutsideTouchable(true); //设置PopupWindow是否能响应外部点击事件
popMenu.setTouchable(true); //设置PopupWindow是否能响应点击事件
popMenu.setAnimationStyle(R.style.main_menu_animStyle); //设置动画样式
popMenu.showAtLocation(popMenuView, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0); //设置位置
}
@Override
protected void onDestroy() {
super.onDestroy();
if (popMenu != null && popMenu.isShowing()) {
popMenu.dismiss();
}
}
- 注意事项
1.这里要注意这两行,“真正”响应外部点击事件
popMenu.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
popMenu.setOutsideTouchable(true);
只有同时设置PopupWindow的背景和可以响应外部点击事件,它才能“真正”响应外部点击事件。也就是说,当你点击PopupWindow的外部或者按下“Back”键时,PopupWindow才会消失。
2.当弹窗出现后,发现弹窗和背景不是很容易区分,如果此时弹窗的背景能“变暗”就好,可以自定义背景暗的色值百分比
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.alpha=0.3f;
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
getWindow().setAttributes(lp);
popMenu.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
WindowManager.LayoutParams lp=getWindow().getAttributes();
lp.alpha=1.0f;
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
getWindow().setAttributes(lp);
}
});
5.关于弹窗总结
- 有四种方式可以给用户提示信息,Dialog、Toast,Snackbar,PopupWindow ,对这三种方式的使用时机做个总结。
- Dialog:当提示信息是至关重要的,并且必须要由用户做出决定才能继续的时候,使用Dialog。
- Toast:当提示信息只是告知用户某个事情发生了,用户不需要对这个事情做出响应的时候,使用Toast。
- Snackbar:以上两者之外的任何其他场景,Snackbar可能会是你最好的选择。
- PopupWindow:跟dialog差不多
5.后续:
平时喜欢写写文章,笔记。别人建议我把笔记,以前写的东西整理,然后写成博客,所以我会陆续整理文章,只发自己写的东西,敬请期待:
知乎:https://www.zhihu.com/people/yang-chong-69-24/pins/posts
领英:https://www.linkedin.com/in/chong-yang-049216146/
:http://www.jianshu.com/u/b7b2c6ed9284
csdn:http://my.csdn.net/m0_37700275
网易博客:http://yangchong211.blog.163.com/
新浪博客:http://blog.sina.com.cn/786041010yc
github:https://github.com/yangchong211
喜马拉雅听书:http://www.ximalaya.com/zhubo/71989305/
脉脉:yc930211
开源中国:https://my.oschina.net/zbj1618/blog