【Android】三种弹窗 Fragment弹窗管理
三三要成为安卓糕手
零:布局转换
在很多工程当中用的都是LinearLayout和relativelayout,这两者都可以转化为Constrainlayout
注:这种用法并不能精确转换,具体还是要根据自己的需求来做布局约束
一:snackbar显示弹窗
((20250705191320-a3dyocx “之前学习过Toast弹窗,类比思想snackbar;我们以之前设计过的登录页面为基础展开弹窗的学习”))
1:代码
private EditText etUserName;private EditText etPassword;private String userName;private String password;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_relative_converse_constraint_layout);//1:获取用户名框view 和 密码框viewetUserName = findViewById(R.id.et_user_name);etPassword = findViewById(R.id.et_password);//2:定位到登录按钮Button button = findViewById(R.id.btn_login);//3:对按钮进行监听button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//3.1:获取框里输入的内容userName = etUserName.getText().toString().trim();password = etPassword.getText().toString().trim();//3.2 如果用户名为空 就弹窗if(userName.length() == 0){Snackbar.make(button,"用户名为空",Snackbar.LENGTH_LONG).show();return;}//3.3 如果密码为空 也弹窗if(password.length() == 0){Snackbar.make(button,"密码为空",Snackbar.LENGTH_LONG)//4.2.1 并且弹出输入法.setAction("去输入密码",new View.OnClickListener(){@Overridepublic void onClick(View v) {//4.2.1.1 密码输入框请求获取焦点;这个跟自动化测试切换句柄有点像etPassword.requestFocus();//4.2.1.2 获取系统的某项服务InputMethodManager inputMethodManager = getSystemService(InputMethodManager.class);inputMethodManager.showSoftInput(etPassword,InputMethodManager.SHOW_IMPLICIT);}}).show();}}});// button.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// if(!userName.equals("admin") || !password.equals("123456")){
// Toast.makeText(ConstraintLoginActivity.this,"用户名与密码不匹配",Toast.LENGTH_SHORT).show();
// return;
// }
// startActivity(new Intent(ConstraintLoginActivity.this,TestActivity.class));
// }
// });}
注:在一个方法中,两个监听器同时监控同一个button,在代码运行时会爆出一些程序崩溃的bug
2:Snackbar.make
snack 零食 bar 条 轻量级提示条 非常有意思的一种起名
第一个参数是当前页面的任何一个View;第二个参数文本;第三个参数显示的时间长短——短1.5s,长3s
3:setAction
Snackbar.setAction()
是用于为 Snackbar 添加可点击操作按钮的方法。Snackbar 是一种轻量级的提示组件,显示在屏幕底部,而 setAction()
可以让它变得交互式。
点击“去输入密码”就会跳出来输入法的使用
4:获取焦点
焦点的概念:当前哪一个视图在和用户进行交互
我们要做的事情是,点击去输入密码之后弹出输入法,让用户去输入密码
etPassword代指密码的TextView,requestFocus请求获取焦点,
@Overridepublic void onClick(View v) {//4.2.1.1 密码输入框请求获取焦点;这个跟自动化测试切换句柄有点像etPassword.requestFocus();//4.2.1.2 获取系统的某项服务InputMethodManager inputMethodManager = getSystemService(InputMethodManager.class);inputMethodManager.showSoftInput(etPassword, InputMethodManager.SHOW_IMPLICIT);}
5:弹出软键盘
(1)获取服务
getSystemService 获取系统的某项服务
InputMethodManager.class
是 Java 的类字面量(Class Literal)
//4.2.1.2 获取系统的某项服务InputMethodManager inputMethodManager = getSystemService(InputMethodManager.class);inputMethodManager.showSoftInput(etPassword, InputMethodManager.SHOW_IMPLICIT);
(2)显示方式
implicit [ɪmˈplɪsɪt] 隐式的
SHOW_IMPLICIT
理解成尊重用户之前的操作习惯,可选择的弹出或者不弹出输入法
SHOW_FORCED
管你丫之前开没开过输入法,直接给你弹出来
二:AlertDialog弹窗的使用
1:完整代码及效果
AlertDialog.Builder builder = new AlertDialog.Builder(AlertDialogActivity.this);builder.setTitle("是否删除").setMessage("删除后不能恢复")//设置积极的按钮(积极消极其实就是按钮的位置不同罢了,little problem).setPositiveButton("确定",new DialogInterface.OnClickListener(){@Overridepublic void onClick(DialogInterface dialog, int which) {}}).setNegativeButton("取消",new DialogInterface.OnClickListener(){@Overridepublic void onClick(DialogInterface dialog, int which) {}});AlertDialog alertDialog = builder.create();findViewById(R.id.btn_show).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {alertDialog.show();}});//关闭弹窗//alertDialog.dismiss();
显示效果
2:AlertDialog.Builder-建房子
Alert 警觉的 Dialog 对话 翻译为:警示对话框
导包选第二个;Androidx包下的样式更丰富一点,相对来说更好用一点,传入的参数是当前上下文,返回类型是Builder
3:setTitle和setMessage
设置标题和设置信息,如上方效果显示的那样;
4:Positive/NegativeButton
dialog下提供了两种设置按钮的形式
设置两个按钮,积极的那个按钮默认放置在右边,消极的按钮默认放置在左边;
通过按钮设置监听器,进而可以写一些处理逻辑
5:builder.create()创建房子
其实很好理解,前面我们对build进行设置相当于打地基建房子装修,create方法就是把这个暗中的房子创建出来;
下面设置的点击按钮事情,只是一个单纯的触发媒介,不必惊慌
AlertDialog alertDialog = builder.create();findViewById(R.id.btn_show).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {alertDialog.show();}});
默认情况下,无论点击按钮的哪个选项,关闭弹窗这件事情系统都会处理掉;
注:有时候需要手动的关闭弹窗,或者在其他时机关闭对话框时,就要调用 dismiss() 方法。
//关闭弹窗alertDialog.dismiss();
三:Toast弹窗提示
之前有详细的讲过,此处仅做对比
Toast.makeText(CheckBoxActivity.this, "请勾选协议!", Toast.LENGTH_SHORT).show();
三个参数:上下文(一般是当前类),弹窗内容,弹窗时间(有长有短)
show方法展示
四:DialogFragment管理弹窗(难)
提出问题:定义的弹窗可能会被多处使用,那么它的创建和销毁,也就是生命周期的管理尤为重要。
这里我们介绍DialogFragment,一个专门用于创建对话框的抽象类;
Fragment在 Android 中,特指 “碎片”,是一种可嵌入 Activity 中的界面组件,用于构建灵活的界面(了解即可)
1:代码
老规矩先上代码
public class YesOrNoDialog extends DialogFragment {@NonNull@Overridepublic Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());builder.setTitle("是否删除").setMessage("删除后不能恢复")//设置积极的按钮(积极消极其实就是按钮的位置不同罢了,little problem).setPositiveButton("确定",new DialogInterface.OnClickListener(){@Overridepublic void onClick(DialogInterface dialog, int which) {}}).setNegativeButton("取消",new DialogInterface.OnClickListener(){@Overridepublic void onClick(DialogInterface dialog, int which) {}});AlertDialog alertDialog = builder.create();return alertDialog;}
}
public class DialogFragment extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_alert_dialog);Button fragmentDialog = findViewById(R.id.btn_show_dialog_fragment);fragmentDialog.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {YesOrNoDialog yesOrNoDialog = new YesOrNoDialog();yesOrNoDialog.show(getSupportFragmentManager(),"yesOrNo");}});}
}
2:对比分析
不要捉急
大局观对比看代码——((20250723152429-786dmu7 "我们在二:AlertDialog弹窗的使用 ")) 中装修房子的任务丢给了一个方法,在类中调用这个方法
而下面这张图片展示是把装修房子的任务丢给了一个类中被重写的方法,这个类继承自DialogFragment;
这样写的好处
- 生命周期管理:自动处理对话框与 Activity 的生命周期绑定(如旋转屏幕时保持状态)。
3:继承追溯
DialogFragment
是 Android 提供的一个抽象类,专门用于创建对话框,最终指向DIalog,是所有弹窗的父类,了解即可
4:onCreatDialog 重写方法介绍
onCreateDialog()
是继承父类后被重写的方法,是 DialogFragment 的核心,用于创建并返回对话框实例,返回类型是Dialog;
固定写法记住就好
import包导入第二个,否则重写onCreateDIalog出不来(on首字母小写)
5:getActivity
这里实例化一个Builder,需要传参一个Activity类,可以理解成依附于 调用它的 Activity;这里使用getActivity()方法,指的就是DialogFragment类调用,就依附于DialogFragment这个类
AlertDialog.Builder builder = new AlertDialog.Builder(DialogFragment.this);
像直接在DialogFragment类中使用我们定义出来的方法,就直接传参好了,如上述代码
6:如何使用
YesOrNoDialog yesOrNoDialog = new YesOrNoDialog();yesOrNoDialog.show(getSupportFragmentManager(),"yesOrNo");
这两行代码是精髓,给show方法传递两个参数,第一个参数获取Fragment管理器,第二个参数tag,随便取一个唯一的指就可以
(1)getSupportFragmentManager
返回一个FragmentManager对象,用于管理Activity中所有的Fragment(碎片)(包括DialogFragment-对话碎片)
作用
-
DialogFragment 需要依附于一个 Activity 来显示,而 FragmentManager 就是连接两者的桥梁。
其实就是中间商,因为FragmentManager还管理其他的碎片
-
FragmentManager 会跟踪 DialogFragment 的生命周期(如创建、显示、销毁),并处理与其他 Fragment 的交互。
(2)TAG
这是一个 String 类型的标签(tag) ,用于唯一标识这个 DialogFragment。
作用:
- 通过标签,你可以在 FragmentManager 中查找并获取这个 DialogFragment 的引用(例如使用
findFragmentByTag()
)。 - 标签也会在日志或调试信息中显示,方便追踪问题。
7:容器化管理
(1)官方建议
官方建议不要在 Activity 或某个地方直接使用 Dialog,而是用‘容器’”
直接在 Activity 中创建 Dialog(如 AlertDialog)存在几个问题:
-
生命周期脱节:
Dialog
是独立于 Activity 生命周期的。例如,当屏幕旋转(Activity 重建)时,直接创建的
Dialog
会被销毁且不会自动重建,导致界面状态丢失(比如对话框突然消失)。 -
内存泄漏风险:
如果Dialog
持有 Activity 的引用(如this
),而Dialog
的生命周期长于 Activity(比如 Activity 被销毁但Dialog
未关闭),会导致 Activity 无法被 GC 回收,造成内存泄漏。 -
配置变更处理复杂:
屏幕旋转、语言切换等配置变更时,需要手动保存和恢复Dialog
的状态(如输入内容、选中状态),代码繁琐且易出错。
这是一种思想,慢慢体会
(2)为什么 “容器化”(DialogFragment)更好?
- 自动跟随生命周期:
DialogFragment
由 FragmentManager 管理,当 Activity 重建时,FragmentManager 会自动重建DialogFragment
及其内部的对话框,保持状态一致性(比如旋转屏幕后对话框仍在!!!这里理解非常好)。 - 避免内存泄漏:
DialogFragment
与 Activity 的绑定通过 FragmentManager 实现,遵循 Fragment 的生命周期规则,减少了不当引用导致的内存泄漏风险。