前言

  在聊DialogFragment之前,我们看看以往我们在Android里实现一个对话框一般有这几种方式:

  •   Dialog 继承重写Dialog实现一个自定义的Dialog
  •   AlertDialog Android原生提供的对话框(底层是继承Dialog实现)
  •   PopupWindow 用弹出悬浮框,实现对话框。这种对话框可以用在指定位置显示,一般用于一些非常小的按键弹窗。怎么实现可以参考我的博客:https://www.cnblogs.com/guanxinjing/p/10156153.html

  这3种弹窗对话框都有一个问题,就是与activity的生命周期不是捆绑的,得时刻注意在activity后台之后关闭Dialog。所以,后面google推荐使用DialogFragment来取代它们。DialogFragment本质其实是Fragment,有Fragment的生命周期并且与创建它的activity有捆绑,在google推出了Jetpack系列后,配合Jetpack系列的LiveData与navigation在使用上比一般的Dialog安全更多,并且在数据传递上也非常简单,配合navigation架构管理起来也十分简单明晰。

  如果你未接触过不了解Jetpack系列,可以参考我的博客:https://www.cnblogs.com/guanxinjing/category/1550385.html   了解完Jetpack系列,你就可以明白google为什么推出这种对话框了。

  下面我们就根据2个最简单demo和与一些使用特例,来介绍DialogFragment的使用。

  

Dialog创建DialogFragment的简单Demo

  DialogFragment有2种方法创建我们需要的对话框内容,其中就有以Dialog来创建内容方式。

继承重写DialogFragment: 

public class MyDialog1 extends DialogFragment {

    @NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
//创建对话框,我们需要返回dialog
AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
dialog.setTitle("测试Dialog");
dialog.setMessage("DialogFragment");
return dialog.create();
} @Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//此方法在视图已经创建后返回的,但是这个view 还没有添加到父级中,我们在这里可以重新设定view的各个数据
}
}

在activity里显示对话框:

        mBtnTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myDialog = new MyDialog1();
myDialog.show(getSupportFragmentManager(),"myDialog");
}
});

效果图:

布局View创建DialogFragment的简单Demo

  DialogFragment另一种创建内容方法,导入一个View

public class MyDialog extends DialogFragment {

    @Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.set_wifi_password_dialog_layout, container, false);
return view;
} @Override
public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
/*
此方法在视图View已经创建后返回的,但是这个view 还没有添加到父级中。
我们在这里可以重新设定view的各个数据,但是不能修改对话框最外层的ViewGroup的布局参数。
因为这里的view还没添加到父级中,我们需要在下面onStart生命周期里修改对话框尺寸参数
*/ } @Override
public void onStart() {
/*
因为View在添加后,对话框最外层的ViewGroup并不知道我们导入的View所需要的的宽度。 所以我们需要在onStart生命周期里修改对话框尺寸参数
*/
WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
getDialog().getWindow().setAttributes((WindowManager.LayoutParams) params);
super.onStart();
}
}

显示对话框的代码跟上面的demo一样,就不重复贴出来了,看看效果图:

改变对话框的显示位置

public class MyDialog2 extends DialogFragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.set_wifi_password_dialog_layout, container, false);
return view;
} @Override
public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); } @Override
public void onStart() {
WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
params.gravity = Gravity.BOTTOM; //将对话框放到布局下面,也就是屏幕下方
getDialog().getWindow().setAttributes((WindowManager.LayoutParams) params);
super.onStart();
}
}

效果图:

将对话框的宽或者高铺满屏幕

设置对话框铺满屏幕有2种方式:

第一种  需要在styles.xml文件里,添加一个没有内边距的style,如下:

  在上面的出现在屏幕下方的对话框中,依然与屏幕有小段距离,那个其实是dialog自带的padding内边距属性导致的。这种方式可以设置只在宽度上铺满屏幕,但是高度上依然留有一定的内边距。

    <style name="dialogFullScreen" parent="Theme.AppCompat.Dialog">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:padding">0dp</item>
<item name="android:windowBackground">@android:color/white</item>
<item name="android:textColor">@android:color/black</item>
</style>

第二种 需要在styles.xml文件里,设置 android:windowFullscreen 属性:

    <style name="dialogFullScreen" parent="Theme.AppCompat.Dialog">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowBackground">@android:color/white</item>
<item name="android:textColor">@android:color/black</item>
<item name="android:windowFullscreen">true</item>
</style>

以上2种互为互补,都可以实现需要的效果

然后依然是重写DialogFragment

public class MyDialog3 extends DialogFragment {

    @Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.set_wifi_password_dialog_layout, container, false);
return view;
} @Override
public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); } @Override
public void onStart() {
WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
params.width = ViewGroup.LayoutParams.MATCH_PARENT;//设置宽度为铺满
params.gravity = Gravity.BOTTOM;
getDialog().getWindow().setAttributes((WindowManager.LayoutParams) params);
super.onStart();
}
}

然后是重点,在创建DialogFragment对话框的时候添加我们的style。

        mBtnTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyDialog3 myDialog = new MyDialog3();
myDialog.setStyle(DialogFragment.STYLE_NORMAL, R.style.dialogFullScreen);//添加上面创建的style
myDialog.show(getSupportFragmentManager(),"aa");
}
});

下方的效果图里,我们就获得了一个在宽度上铺满屏幕的对话框,举一反三在设置高度上也是一样的:

设置点击外部空白处不会关闭对话框

方式一

  在前面创建的对话框里,在点击外部后依然会关闭对话框,我们有时候有些重要消息并不希望用户可以点击外部可以取消。

这个属性一样在styles.xml,创建style里添加 <item name="android:windowCloseOnTouchOutside">false</item>

    <style name="dialogFullScreen" parent="Theme.AppCompat.Dialog">
<item name="android:padding">0dp</item>
<item name="android:windowBackground">@android:color/white</item>
<item name="android:textColor">@android:color/black</item>
<item name="android:windowCloseOnTouchOutside">false</item>
</style>

方式二

        //getDialog().setCancelable(false);//这个会屏蔽掉返回键
getDialog().setCanceledOnTouchOutside(isCanceledOnTouchOutside());

设置在弹出对话框后同时弹出软键盘

我只需要两步,1.将需要输入内容的EditText设置为焦点 2.设置软键盘可见

public class MyDialog3 extends DialogFragment {

    @Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.set_wifi_password_dialog_layout, container, false);
return view;
} @Override
public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) {
EditText editPassword = view.findViewById(R.id.edit_password);
editPassword.requestFocus();//设置焦点
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);//设置输入盘可见
super.onViewCreated(view, savedInstanceState);
} @Override
public void onStart() {
WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
params.gravity = Gravity.BOTTOM;
getDialog().getWindow().setAttributes((WindowManager.LayoutParams) params);
super.onStart();
}
}

效果图:

在Fragment里启动对话框

与activity里一样没啥区别,唯一的区别就是你打算依然用老套的onActivityResult来向下传值,那么你就需要设置一个目标Fragment在下面的代码里setTargetFragment()方法就是起到这个作用的,在下面的代码里我们用MyDialog1 启动了 MyDialog2。

DialogFragment其实就是Fragment,所以我这里就偷懒一下,直接用对话框启动对话框了。。。不在单独写一个Fragment

MyDialog1.Java

public class MyDialog1 extends DialogFragment {

    @NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
dialog.setTitle("测试Dialog");
dialog.setMessage("启动另外一个对话框");
dialog.setPositiveButton("启动", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
MyDialog2 myDialog2 = new MyDialog2();
myDialog2.setTargetFragment(MyDialog1.this, 300);
myDialog2.setStyle(DialogFragment.STYLE_NORMAL, R.style.dialogFullScreen);
myDialog2.show(getFragmentManager(), "myDialog2"); }
}); return dialog.create();
} @Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
} @Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//这里可以返回 MyDialog2 Fragment的数据
}
}

MyDialog2.Java

public class MyDialog2 extends DialogFragment {
private static final String TAG = "MyDialog";
private ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener; @Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.set_wifi_password_dialog_layout, container, false);
return view;
} @Override
public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
} @Override
public void onStart() {
WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
params.gravity = Gravity.BOTTOM;
getDialog().getWindow().setAttributes((WindowManager.LayoutParams) params);
super.onStart();
}
}

设置圆角与实际不符合的问题

实际上是你设置的背景图片,被Dialog自带的背景遮盖了,导致圆角无法显示。所以设置一下透明背景就可以了。

注意设置DecorView的背景与设置Window的背景是有区别的,区别如下:

设置DecorView背景

    @Override
public void onStart() {
WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
getDialog().getWindow().setAttributes(params);
getDialog().getWindow().getDecorView().setBackground(new ColorDrawable(Color.TRANSPARENT));super.onStart();
}

效果图:

设置Window的背景

    @Override
public void onStart() {
WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
getDialog().getWindow().setAttributes(params);
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
super.onStart();
}

end

Android开发 DialogFragment对话框详解的更多相关文章

  1. Android开发–Intent-filter属性详解

    Android开发–Intent-filter属性详解 2011年05月09日 ⁄ Andriod ⁄ 暂无评论 ⁄ 被围观 1,396 views+ 如果一个 Intent 请求在一片数据上执行一个 ...

  2. 搭建Android开发环境附图详解+模拟器安装(JDK+Eclipse+SDK+ADT)

    ——搭建android开发环境的方式有多种,比如:JDK+Eclipse+SDK+ADT或者JDK+Eclipse+捆绑好的AndroidSDK或者Android Studio. Google 决定将 ...

  3. android 开发 View _6_Canvas详解

    牛逼大神的博客地址:http://www.gcssloop.com/customview/Canvas_BasicGraphics 安卓自定义View进阶-Canvas之绘制图形 在上一篇自定义Vie ...

  4. Android 开发 之 Fragment 详解

    本文转载于 : http://blog.csdn.net/shulianghan/article/details/38064191 本博客代码地址 : -- 单一 Fragment 示例 : http ...

  5. 2-5 Flutter开发环境与Android开发环境设置详解(Windows)

    第二个是国内服务器的网址 andoid stuido的一些使用的说明文档 https://developer.android.google.cn/studio/intro 安装Flutter Dart ...

  6. Android开发 VideoView视频播放详解

    前言 VideoView是Android主要的视频播放View,它其实是对MediaPlayer的再次封装.如果你已经了解过MediaPlayer在使用VideoView是十分简单的.如果你想先了解M ...

  7. Android开发 WebView的详解

    前言 WebView 是Android显示html内容的主要方式,当然TextView也可以加载html内容.但是WebView除了功能更加强大,最重要的是还能调用Html里的JavaScript语言 ...

  8. Android 开发之动画详解

    一.动画类型 Android的animation由四种类型组成:alpha.scale.translate.rotate XML配置文件中 alpha 渐变透明度动画效果 scale 渐变尺寸伸缩动画 ...

  9. Android开发 navigation入门详解

    前言 Google 在2018年推出了 Android Jetpack,在Jetpack里有一种管理fragment的新架构模式,那就是navigation. 字面意思是导航,但是除了做APP引导页面 ...

随机推荐

  1. php连接mysql遇到的问题: (HY000/1130) 和 [caching_sha2_password]

    说明一下我的mysql是安装在虚拟机上的 所以遇到的第一个问题就是访问问题 解决: update user set host = '%' where user = 'root'; 重启mysql服务 ...

  2. react-swiper 如何实现滑动小卡片的移动?

    1.引入插件 import ReactSwipes from 'react-swipes'; import './swiperCard.css'; 2.代码构成 export default clas ...

  3. ttytype - 终端设备映射的默认终端类型

    DESCRIPTION(描述) /etc/ttytype 文件把termcap/terminfo中的终端类型名与tty行关联起来.每行包括一种终端类型,后面跟着空格,然后是tty名(不带 /dev/ ...

  4. 2019_7_30python

    当6引号给予变量的时候,变为字符串 6引号注释多行 语言元素 python中大小写敏感 不要和关键字 print( a + b ) print( a - b ) print( a * b ) prin ...

  5. MonkeyTalk使用方法

    1.简单介绍 MonkeyTalk软件测试工具由两部分构成:MonkeyTalk IDE 和 MonkeyTalk Agents MonkeyTalk IDE是Eclipse平台的工具,工能是:对iO ...

  6. 【centos】 error: command 'gcc' failed with exit status 1 错误

    转载自 :http://blog.csdn.net/fenglifeng1987/article/details/38057193 用安装Python模块出现error: command 'gcc' ...

  7. 干货满满!10分钟看懂Docker和K8S

    2010年,几个搞IT的年轻人,在美国旧金山成立了一家名叫“dotCloud”的公司. 这家公司主要提供基于PaaS的云计算技术服务.具体来说,是和LXC有关的容器技术. LXC,就是Linux容器虚 ...

  8. CSS控制Span强制换行、溢出隐藏

    CSS控制Span强制换行 word-wrap: break-word; word-break: break-all; white-space: pre-wrap !important; 盒子文字设置 ...

  9. 使用vue-cli 脚手架快速搭建单页面组件 -------webpack工具的介绍

    在使用vue-cli时我们先了解一下什么是webpack. Webpack 是当下最热门的前端资源模块化管理和打包工具.它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源.还可以将按 ...

  10. thinkphp 防止XSS(跨站脚本攻击)

    XSS(跨站脚本攻击)可以用于窃取其他用户的Cookie信息,要避免此类问题,可以采用如下解决方案: 直接过滤所有的JavaScript脚本: 转义Html元字符,使用htmlentities.htm ...