文章目录
概述
DialogFragment 在 android 3.0 时被引入。是一种特殊的 Fragment,用于在 Activity 的内容之上展示一个模态的对话框。典型的用于:展示警告框,输入框,确认框等等
在 DialogFragment 产生之前,我们创建对话框:一般采用 AlertDialog 和 Dialog。注:官方不推荐直接使用Dialog创建对话框
使用 DialogFragment 来管理对话框,当旋转屏幕和按下后退键时可以更好的管理其声明周期,它和 Fragment 有着基本一致的声明周期。且 DialogFragment 也允许开发者把 Dialog 作为内嵌的组件进行重用,类似 Fragment(可以在大屏幕和小屏幕显示出不同的效果)
使用 DialogFragment 至少需要实现 onCreateView
或者 onCreateDIalog
方法。onCreateView
即使用定义的 xml 布局文件展示 Dialog。onCreateDialog
即利用 AlertDialog 或者 Dialog 创建出Dialog
创建 DialogFragment 有两种方式
覆写其 onCreateDialog 方法 — ① 利用AlertDialog或者Dialog创建出Dialog
覆写其 onCreateView 方法 — ② 使用定义的xml布局文件展示Dialog
虽然这两种方式都能实现相同的效果,但是它们各有自己适合的应用场景:
方法 ①,一般用于创建替代传统的 Dialog 对话框的场景,UI 简单,功能单一
方法 ②,一般用于创建复杂内容弹窗或全屏展示效果的场景,UI 复杂,功能复杂,一般有网络请求等异步操作
另外它又是Fragment,所以当旋转屏幕和按下后退键时可以更好的管理其声明周期,它和Fragment有着基本一致的声明周期
重写onCreateView创建Dialog
a)创建一个布局 fragment_edit_name.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<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>
b)继承 DialogFragment,重写 onCreateView 方法
public class EditNameDialogFragment extends DialogFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_edit_name, container, false);
return view;
}
}
c)测试运行
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EditNameDialogFragment fragment = new EditNameDialogFragment();
fragment.show(getSupportFragmentManager(),"EditNameDialog");
}
}
运行结果
重写 onCreateDialog创建 Dialog
在 onCreateDialog 中一般可以使用 AlertDialog 或者 Dialog 创建对话框,不过既然 google 不推荐直接使用 Dialog,我们就使用 AlertDialog 来创建一个登录的对话框
a)fragment_login_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="64dp"
android:background="#FFFFBB33"
android:gravity="center"
android:scaleType="center"
android:text="Android App"
android:textColor="@android:color/white" />
<EditText
android:id="@+id/id_txt_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginTop="16dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:hint="input username"
android:inputType="textEmailAddress" />
<EditText
android:id="@+id/id_txt_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginTop="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="16dp"
android:fontFamily="sans-serif"
android:hint="input password"
android:inputType="textPassword" />
</LinearLayout>
b)继承 DialogFragment 重写 onCreateDialog 方法
public class LoginDialogFragment extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.fragment_login_dialog, null);
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
builder.setView(view)
// Add action buttons
.setPositiveButton("Sign in",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
}
})
.setNegativeButton("Cancel", null);
return builder.create();
}
}
c)调用
LoginDialogFragment dialog = new LoginDialogFragment();
dialog.show(getSupportFragmentManager(), "loginDialog");
运行结果
传递数据给Activity
修改上面的代码
public class LoginDialogFragment extends DialogFragment {
private EditText mUsername;
private EditText mPassword;
public interface LoginInputListener {
void onLoginInputComplete(String name, String passwd);
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.fragment_login_dialog, null);
mUsername = (EditText) view.findViewById(R.id.id_txt_username);
mPassword = (EditText) view.findViewById(R.id.id_txt_password);
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
builder.setView(view)
// Add action buttons
.setPositiveButton("Sign in",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
LoginInputListener listener = (LoginInputListener) getActivity();
listener.onLoginInputComplete(mUsername.getText().toString(),
mPassword.getText().toString());
}
})
.setNegativeButton("Cancel", null);
return builder.create();
}
}
TestActivity 中实现我们的接口 LoginInputListener,实现我们的方法,就可以实现当用户点击登陆时,获得我们的帐号密码了
public class TestActivity extends AppCompatActivity implements LoginDialogFragment.LoginInputListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LoginDialogFragment dialog = new LoginDialogFragment();
dialog.show(getSupportFragmentManager(), "loginDialog");
}
@Override
public void onLoginInputComplete(String name, String passwd) {
Toast.makeText(this, "姓名:" + name + ",密码:" + passwd, Toast.LENGTH_SHORT).show();
}
}
运行结果
DialogFragment做屏幕适配
我们希望,一个对话框在大屏幕上以对话框的形式展示,而小屏幕上则直接嵌入当前的 Actvity 中。这种效果的对话框,只能通过重写 onCreateView 实现。下面我们利用上面的 EditNameDialogFragment 来显示
EditNameDialogFragment 我们已经编写好了,直接在MainActivity中写调用
public class TestActivity extends AppCompatActivity implements LoginDialogFragment.LoginInputListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
FragmentManager fragmentManager = getSupportFragmentManager();
EditNameDialogFragment newFragment = new EditNameDialogFragment();
boolean mIsLargeLayout = getResources().getBoolean(R.bool.large_layout) ;
Log.e("TAG", mIsLargeLayout+"");
if (mIsLargeLayout ) {
// The device is using a large layout, so show the fragment as a dialog
newFragment.show(fragmentManager, "dialog");
} else {
// The device is smaller, so show the fragment fullscreen
FragmentTransaction transaction = fragmentManager.beginTransaction();
// For a little polish, specify a transition animation
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
// To make it fullscreen, use the 'content' root view as the
// container
// for the fragment, which is always the root view for the activity
transaction.replace(R.id.id_ly, newFragment).commit();
}
}
@Override
public void onLoginInputComplete(String name, String passwd) {
Toast.makeText(this, "姓名:" + name + ",密码:" + passwd, Toast.LENGTH_SHORT).show();
}
}
可以看到,我们通过读取R.bool.large_layout,然后根据得到的布尔值,如果是大屏幕则直接以对话框显示,如果是小屏幕则嵌入我们的Activity布局中
在默认的values下新建一个bools.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="large_layout">false</bool>
</resources>
然后在 res 下新建一个 values-large,在values-large下再新建一个 bools.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="large_layout">true</bool>
</resources>