Android full-screen 对话框回调问题
Android full-screen dialog callback issue
我无法理解某事,但让我先描述一下我的设置:
我有一个 activity 引用了 3 个片段,每个片段都在正确的时间显示。这是 ChildrenSpecificationFragment 的样子:
如果用户单击浮动操作按钮,将打开以下 DialogFragment:
我在新的 material 设计指南中找到了以下信息:https://www.google.com/design/spec/components/dialogs.html#dialogs-full-screen-dialogs
Avoid dialogs that:
Open additional dialogs from within a dialog.
Contain scrolling content, particularly alerts. Instead, consider alternate containers or layouts that are optimized for reading or interacting with significant amounts of content.
Exceptions include:Full-screen dialogs may open additional dialogs, such as pickers, because their design accommodates additional layers of material without significantly increasing the app’s perceived z-depth or visual noise.
这就是我的问题开始的地方。 'add child' 对话框具有可滚动的内容(在横向模式下),当用户单击 'Birth date' 时,会打开一个日期选择器。
我正在尝试找到一种方法来实现全屏对话框(如指南中所述),该对话框具有对 ChildrenSpecificationFragment 的回调,以便我可以将 child 添加到 RecyclerView 。
我希望我的问题很清楚,并且非常感谢任何能引导我找到解决方案的意见。提前致谢!
将此行添加到自定义对话框片段中的 oncreate。
setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Black_NoTitleBar_Fullscreen);
另一方面,您可以使用内容解析器来存储您的 children 数据。
它具有观察者模式。因此,每个附加到该内容的 CursorAdapter 都会在不调用 notifySetDataChanged();
.
的情况下自行刷新
我认为您正在使用 RecyclerView.Adapter。您可以使用 this class.
实现添加 child 功能的另一个建议是使用 startActivityForResult(activity);
。
您可以使用 getIntent().getExtras().put(key,value);
发回数据 您可以搜索自定义开始 activity 以获取结果。
祝你好运
在我的博客上使用 startActivityForResult(...) 描述的解决方案:http://jeroendruwe.be/full-screen-dialogs-in-android/
我没有看到您 post 的代码。所以我猜你的代码结构是一个开始。
首先使用侦听器构建对话框并处理 setPositiveButton() 和 onClick 事件。
代码建议:
public class ChildrenSpecificationFragment extends Fragment {
...
public void passData(Object obj) {
}
class SubChildFragment extends Fragment {
AlertDialog.Builder builder = new AlertDialog.Builder(thisContext);
...
// Add the buttons...
builder.setPositiveButton("Save", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
...
passData(Object obj); // pass data to the outer fragment class
备注:
例如SubChildFragment
,是从Fragment派生出来的一个内class。它可以在外部 class ChildrenSpecificationFragment
中调用 public 方法 passData
() 来传递您需要的任何数据。
- 我正在使用内部 class 因为我认为这就是你在图表中
的意思
Add child full-screen fragment
- 这种编码技术比开始一个新的 Activity 和 Intent 更容易。
为了显示 全屏对话框 ,我认为 @ Dialog - Fullscreen 有一个很好的 Google 网页。搜索 "Showing a Dialog Fullscreen or as an Embedded Fragment".
的文本
TL;DR - 除了完全全屏之外,DialogFragment 是不够的。请改用 Activity。
可以制作 DialogFragment
全屏(显示 ActionBar
),但会带来很多麻烦。
A DialogFragment
,顾名思义,是 Dialog
和 Fragment
合二为一:可以将其视为 Dialog
,使用 show()
和 dismiss()
,或作为 Fragment
,与 FragmentManager
.
一起使用
与 official documentation suggests 一样,通过将对话框附加到根视图,可以使对话框完全全屏显示(覆盖所有内容)android.R.id.content
:
public void showDialog() {
FragmentManager fragmentManager = getSupportFragmentManager();
CustomDialogFragment newFragment = new CustomDialogFragment();
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.add(android.R.id.content, newFragment)
.addToBackStack(null).commit();
}
}
要使对话框显示在 ActionBar
下方,需要一个 FrameLayout
,用于代替根布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.CoordinatorLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Use ThemeOverlay to make the toolbar and tablayout text
white -->
<android.support.design.widget.AppBarLayout
android:id="@+id/abl_top"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:fitsSystemWindows="true"
android:layout_height="wrap_content"
android:layout_width="match_parent"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header"
app:menu="@menu/nav_view"/>
</android.support.v4.widget.DrawerLayout>
痛苦来了。
根据应用程序主导航的设置方式,需要跳过不同的环节才能使一切正常运行。
上面的例子有一个NavigationView
。由于主页按钮 android.R.id.home
是在主视图中处理的,因此需要一些逻辑来检查我们的对话框是否显示,以便主页按钮(现在是 X
)将关闭对话框。此处返回false
允许在对话框中处理事件。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
FragmentManager fm = getSupportFragmentManager();
Fragment f = fm.findFragmentById(R.id.content);
if (f instanceof MyDialogFragment) {
return false;
}
mDrawerLayout.openDrawer(GravityCompat.START);
return true;
}
return super.onOptionsItemSelected(item);
}
此外,后退按钮需要类似的逻辑来确定 NavigationView
是否需要关闭或 ActionBar
内容重置。
@Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
mDrawerLayout.closeDrawer(GravityCompat.START);
} else {
FragmentManager fm = getSupportFragmentManager();
Fragment f = fm.findFragmentById(R.id.content);
if (f instanceof MyDialogFragment) {
final ActionBar ab = getSupportActionBar();
ab.setHomeAsUpIndicator(R.drawable.ic_menu);
ab.setTitle(R.string.app_name);
}
super.onBackPressed();
}
}
在 DialogFragment
本身中,需要实现关闭对话框(并滥用 ActionBar
)的逻辑。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if (mActionBar != null) {
mActionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
mActionBar.setTitle(R.string.app_name);
}
getActivity().getSupportFragmentManager().popBackStack();
case R.id.action_save:
if (mOnAcceptListener != null) {
mOnAcceptListener.onAccept();
}
if (mActionBar != null) {
mActionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
mActionBar.setTitle(R.string.app_name);
}
getActivity().getSupportFragmentManager().popBackStack();
return true;
}
return super.onOptionsItemSelected(item);
}
这一切感觉真的kludgy。当然,如果你使用的是 TabLayout
,请忘记我刚才所说的一切。
使用 TabLayout
您可以处理 DialogFragment
中的所有内容,但如果您使用 ViewPager
,则无法让对话框覆盖选项卡,但不是操作栏。参见 。
这个问题(由我提出)的答案与@Jdruwe 的建议相同,即忘记 DialogFragment
的绝望并改用 Activity
。
我无法理解某事,但让我先描述一下我的设置:
我有一个 activity 引用了 3 个片段,每个片段都在正确的时间显示。这是 ChildrenSpecificationFragment 的样子:
如果用户单击浮动操作按钮,将打开以下 DialogFragment:
我在新的 material 设计指南中找到了以下信息:https://www.google.com/design/spec/components/dialogs.html#dialogs-full-screen-dialogs
Avoid dialogs that: Open additional dialogs from within a dialog. Contain scrolling content, particularly alerts. Instead, consider alternate containers or layouts that are optimized for reading or interacting with significant amounts of content.
Exceptions include:Full-screen dialogs may open additional dialogs, such as pickers, because their design accommodates additional layers of material without significantly increasing the app’s perceived z-depth or visual noise.
这就是我的问题开始的地方。 'add child' 对话框具有可滚动的内容(在横向模式下),当用户单击 'Birth date' 时,会打开一个日期选择器。
我正在尝试找到一种方法来实现全屏对话框(如指南中所述),该对话框具有对 ChildrenSpecificationFragment 的回调,以便我可以将 child 添加到 RecyclerView 。
我希望我的问题很清楚,并且非常感谢任何能引导我找到解决方案的意见。提前致谢!
将此行添加到自定义对话框片段中的 oncreate。
setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Black_NoTitleBar_Fullscreen);
另一方面,您可以使用内容解析器来存储您的 children 数据。
它具有观察者模式。因此,每个附加到该内容的 CursorAdapter 都会在不调用 notifySetDataChanged();
.
我认为您正在使用 RecyclerView.Adapter。您可以使用 this class.
实现添加 child 功能的另一个建议是使用 startActivityForResult(activity);
。
您可以使用 getIntent().getExtras().put(key,value);
发回数据 您可以搜索自定义开始 activity 以获取结果。
祝你好运
在我的博客上使用 startActivityForResult(...) 描述的解决方案:http://jeroendruwe.be/full-screen-dialogs-in-android/
我没有看到您 post 的代码。所以我猜你的代码结构是一个开始。 首先使用侦听器构建对话框并处理 setPositiveButton() 和 onClick 事件。
代码建议:
public class ChildrenSpecificationFragment extends Fragment {
...
public void passData(Object obj) {
}
class SubChildFragment extends Fragment {
AlertDialog.Builder builder = new AlertDialog.Builder(thisContext);
...
// Add the buttons...
builder.setPositiveButton("Save", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
...
passData(Object obj); // pass data to the outer fragment class
备注:
-
例如
SubChildFragment
,是从Fragment派生出来的一个内class。它可以在外部 classChildrenSpecificationFragment
中调用 public 方法passData
() 来传递您需要的任何数据。- 我正在使用内部 class 因为我认为这就是你在图表中 的意思
Add child full-screen fragment
- 这种编码技术比开始一个新的 Activity 和 Intent 更容易。
为了显示 全屏对话框 ,我认为 @ Dialog - Fullscreen 有一个很好的 Google 网页。搜索 "Showing a Dialog Fullscreen or as an Embedded Fragment".
的文本TL;DR - 除了完全全屏之外,DialogFragment 是不够的。请改用 Activity。
可以制作 DialogFragment
全屏(显示 ActionBar
),但会带来很多麻烦。
A DialogFragment
,顾名思义,是 Dialog
和 Fragment
合二为一:可以将其视为 Dialog
,使用 show()
和 dismiss()
,或作为 Fragment
,与 FragmentManager
.
与 official documentation suggests 一样,通过将对话框附加到根视图,可以使对话框完全全屏显示(覆盖所有内容)android.R.id.content
:
public void showDialog() {
FragmentManager fragmentManager = getSupportFragmentManager();
CustomDialogFragment newFragment = new CustomDialogFragment();
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.add(android.R.id.content, newFragment)
.addToBackStack(null).commit();
}
}
要使对话框显示在 ActionBar
下方,需要一个 FrameLayout
,用于代替根布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.CoordinatorLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Use ThemeOverlay to make the toolbar and tablayout text
white -->
<android.support.design.widget.AppBarLayout
android:id="@+id/abl_top"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:fitsSystemWindows="true"
android:layout_height="wrap_content"
android:layout_width="match_parent"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header"
app:menu="@menu/nav_view"/>
</android.support.v4.widget.DrawerLayout>
痛苦来了。
根据应用程序主导航的设置方式,需要跳过不同的环节才能使一切正常运行。
上面的例子有一个NavigationView
。由于主页按钮 android.R.id.home
是在主视图中处理的,因此需要一些逻辑来检查我们的对话框是否显示,以便主页按钮(现在是 X
)将关闭对话框。此处返回false
允许在对话框中处理事件。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
FragmentManager fm = getSupportFragmentManager();
Fragment f = fm.findFragmentById(R.id.content);
if (f instanceof MyDialogFragment) {
return false;
}
mDrawerLayout.openDrawer(GravityCompat.START);
return true;
}
return super.onOptionsItemSelected(item);
}
此外,后退按钮需要类似的逻辑来确定 NavigationView
是否需要关闭或 ActionBar
内容重置。
@Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
mDrawerLayout.closeDrawer(GravityCompat.START);
} else {
FragmentManager fm = getSupportFragmentManager();
Fragment f = fm.findFragmentById(R.id.content);
if (f instanceof MyDialogFragment) {
final ActionBar ab = getSupportActionBar();
ab.setHomeAsUpIndicator(R.drawable.ic_menu);
ab.setTitle(R.string.app_name);
}
super.onBackPressed();
}
}
在 DialogFragment
本身中,需要实现关闭对话框(并滥用 ActionBar
)的逻辑。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if (mActionBar != null) {
mActionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
mActionBar.setTitle(R.string.app_name);
}
getActivity().getSupportFragmentManager().popBackStack();
case R.id.action_save:
if (mOnAcceptListener != null) {
mOnAcceptListener.onAccept();
}
if (mActionBar != null) {
mActionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
mActionBar.setTitle(R.string.app_name);
}
getActivity().getSupportFragmentManager().popBackStack();
return true;
}
return super.onOptionsItemSelected(item);
}
这一切感觉真的kludgy。当然,如果你使用的是 TabLayout
,请忘记我刚才所说的一切。
使用 TabLayout
您可以处理 DialogFragment
中的所有内容,但如果您使用 ViewPager
,则无法让对话框覆盖选项卡,但不是操作栏。参见
这个问题(由我提出)的答案与@Jdruwe 的建议相同,即忘记 DialogFragment
的绝望并改用 Activity
。