今天项目中要求写一个从底部向上的Dialog的弹窗, 当然GitHub上有大神开源库BottomSheetLayout , 专门针对底部向上弹窗的控件,使用只需要把需要弹窗的布局全部包裹起来即可,感兴趣的朋友可以去看看; 而今天在这里,我想分享下FragmentDialog的使用
为什么使用FragmentDialog: 自己写的代码,可维护性更高,并且FragmentDialog不像AlertDialog一样, 在用户输入的同时切换横竖屏会消失, 而且.美工要求说,弹窗后面背景不能为灰色的(BottomSheetLayout弹上来后后面为灰色的), 所以我们就来自己写一个FragmentDialog吧
那么,下面开始吧
package com.hanzheng.fragmentdialog;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;
/**
* 官方推荐 DialogFragment 创建对话框
*/
public class MainActivity extends AppCompatActivity implements LoginDialog.LoginInputListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void showConfirmDialog(View view) {
ConfimDialog confimDialog = new ConfimDialog();
confimDialog.show(getSupportFragmentManager(),"confirmDialog");
}
//显示登录的对话框,用AlertDialog
public void showLoginDialog(View view) {
LoginDialog loginDialog = new LoginDialog();
loginDialog.show(getFragmentManager(),"loginDialog");
}
@Override
public void login(String username, String pwd) {
Toast.makeText(this,"姓名:" + username+";密码:" + pwd,Toast.LENGTH_LONG).show();
}
}
首先, 主布局的代码: 两个按钮的点击事件,中可以看到,DialogFragment是new出来,然后调用show()显示的, 同时主页面还实现了LoginDialog类中的LoginInputListener的接口
ConfirmDialog继承DialogFragment
布局文件的写法:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="50dp"
android:layout_height="50dp" >
<TextView
android:id="@+id/id_label_your_name"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:gravity="center_vertical"
android:text="Your name:" />
<EditText
android:id="@+id/id_txt_your_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/id_label_your_name"
android:imeOptions="actionDone"
android:inputType="text" />
<Button
android:id="@+id/id_sure_edit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@id/id_txt_your_name"
android:text="ok" />
</RelativeLayout>
代码:
package com.hanzheng.fragmentdialog;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
/**
* Created by zmybi on 2017/1/9.
*
* 确认对话框
*/
public class ConfimDialog extends DialogFragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//去掉Dialog上空白的标题 占的位置
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
View view = inflater.from(getActivity()). inflate(R.layout.confirm_dialog,container);
return view;
}
}
这里from 中参数一定是写getActivity()来得到上下文, 因为Dialog是依附于Activity的
同时 关于LayoutInflator.inflate(int resource, ViewGroup root, boolean attachToRoot)三个参数的方法的说明:
- 当root=null时候, 第三个参数attachToRoot为false或者true 已经没有意义了, 表示不考虑resource布局条目的书写, 根布局写什么 也只会将它包裹起来
- 当root 不为null时候, 第三个参数为false 表示考虑根布局的书写, 但是如果返回一个view 将其添加到父root中,则这些layout属性将会失效
- 当root不为null时候,第三个参数为true, 表示给控件加载一个父布局,直接将R.layout...的布局传入某些自定义控件中,同时将当前对象this返回,返回值影响极大
- 在设置attachToRoot的情况下, 如果root不为null, 则attachToRoot默认为true
这就是我总结的关于LayoutInflator的三个参数的作用, 在RecyclerView中条目布局中使用极其广泛
回到上面, 当点击第一个按钮的时候,则弹出一个宽度填充父容器的对话框
2 FragmentDialog的第二种用法,这种用法也是很重要的,看LoginDialog类中的代码
package com.hanzheng.fragmentdialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
/**
* LoginDialog
* 并且实现 从Dialog传递数据给Activity
*/
public class LoginDialog extends DialogFragment {
private EditText mUsername;
private EditText mPossword;
public interface LoginInputListener{
void login(String username,String pwd);
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//返回一个Dialog用于展示
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater layoutInflater = getActivity().getLayoutInflater();
final View view = layoutInflater.inflate(R.layout.login_dialog,null);
builder.setView(view)
.setPositiveButton("login", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
mUsername = (EditText) view.findViewById(R.id.et_username_login);
mPossword = (EditText) view.findViewById(R.id.et_pwd_login);
LoginInputListener loginInputListener = (LoginInputListener) getActivity();
loginInputListener.login(mUsername.getText().toString().trim(),mPossword.getText().toString().trim());
}
})
.setNegativeButton("cancle",null);
return builder.create();
}
}
同样也是继承DialogFragment ,但是这次是重写了其onCreateDialog() 返回一个Dialog用于展示; 先new一个builder出来,参数同样是传入getActivity();而这里用LayoutInflator打了一个布局出来, 我第二个参数传入的是null,下面是布局文件的写法
当点击按钮回调点击事件, 将Activity强转为我们定义的接口,并且调用接口中的方法,传入用户在Dialog中输入的username和password;
同时在主页面我们实现了这个LoginInputListener的接口, 重写方法, 则在Activity就能得到并打印 用户用户输入的值了
至此,两个DialogFragment实现完毕