【问题标题】:Android full-screen dialog callback issueAndroid全屏对话框回调问题
【发布时间】:2015-06-06 15:03:57
【问题描述】:

我无法理解某些东西,但让我先描述一下我的设置:

我有一个引用 3 个片段的活动,每个片段都在正确的时间显示。这是 ChildrenSpecificationFragment 的外观:

如果用户单击浮动操作按钮,则会打开以下 DialogFragment:

我在新材料设计指南中找到了以下信息:https://www.google.com/design/spec/components/dialogs.html#dialogs-full-screen-dialogs

避免出现以下情况的对话框: 从对话框中打开其他对话框。 包含滚动内容,尤其是警报。相反,请考虑为阅读大量内容或与大量内容交互而优化的替代容器或布局。

例外情况包括:全屏对话框可能会打开其他对话框,例如选择器,因为它们的设计可以容纳额外的材料层,而不会显着增加应用的感知 z 深度或视觉噪音。

这就是我的问题开始的地方。 “添加孩子”对话框具有可滚动的内容(横向模式),当用户单击“出生日期”时,会打开一个日期选择器。

我正在尝试找到一种方法来实现一个全屏对话框(如指南中所述),该对话框具有对 ChildrenSpecificationFragment 的回调,以便我可以将孩子添加到 RecyclerView 。

我希望我的问题是明确的,并且非常感谢任何能引导我找到解决方案的意见。提前致谢!

【问题讨论】:

  • 你添加子片段的布局文件是什么?
  • 我已经看到了使用 FragmentTransaction 添加对话框的答案和其他问题,但我还没有让它工作。
  • 嗨,乔恩,我找到了一种让它发挥作用的方法,我昨天写了一篇关于它的博客文章:jeroendruwe.be/full-screen-dialogs-in-android。虽然我不知道这是否是解决问题的最佳方法。
  • 您是否对这里的说明有任何帮助:developer.android.com/guide/topics/ui/…。这对我不起作用,但我也在使用android设计的NavigtionView,这可能会影响它。

标签: android android-fragments android-dialogfragment


【解决方案1】:

TL;DR - DialogFragment 不足以用于完全全屏以外的任何内容。改用 Activity。

可以全屏制作DialogFragment(显示ActionBar),但会带来很多麻烦。

顾名思义,DialogFragmentDialogFragment 合二为一:它可以同时被视为 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,则不可能让对话框覆盖选项卡而不是操作栏。见Show DialogFragment over TabLayout

这个问题(由我提出)的答案与@Jdruwe 相同,即忘记DialogFragment 的绝望并改用Activity

【讨论】:

【解决方案2】:

我的博客上描述的使用 startActivityForResult(...) 的解决方案:http://jeroendruwe.be/full-screen-dialogs-in-android/

【讨论】:

  • 那还在使用 DialogFragment 吗?
【解决方案3】:

我没有从您的帖子中看到代码。所以我猜你的代码结构是一个开始。 首先使用侦听器构建对话框并处理 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 派生的内部类。它可以调用外部类ChildrenSpecificationFragment 中的公共方法passData() 来传递您需要的任何数据。
  • 我正在使用内部类,因为我认为这就是您在图表中的意思

添加子全屏片段

  • 这种编码技术比启动新的 Activity 和 Intent 更容易。

为了显示全屏对话框,我认为有一个很好的谷歌网页@Dialog - Fullscreen。搜索“全屏显示对话框或嵌入片段”的文本。

【讨论】:

  • 但这是否以谷歌的例子全屏显示布局的内容:material-design.storage.googleapis.com/publish/material_v_4/…
  • 因为我原来是这样的,一个fragment扩展dialogfragment并调用了父实现的接口方法。
  • @Jdruwe,我的示例中的片段 SubChildFragment 可以是 dialogFragment,它可以显示全屏。我认为对话框可以通过布局规范全屏显示。数据传递与 GUI 布局是分开的。有一个链接developer.android.com/guide/topics/ui/dialogs.html,以防您没有阅读此链接。我以为你已经解决了全屏问题。
  • @Jdruwe,我在底部添加了更多关于“全屏对话框”的 cmets。
  • 感谢您的解决方案! :D 你如何将它与我在jeroendruwe.be/full-screen-dialogs-in-android 中描述的解决方案进行比较?
【解决方案4】:

将此行添加到自定义对话框片段中的 oncreate 中。

setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Black_NoTitleBar_Fullscreen);

另一方面,您可以使用内容解析器来存储您的孩子数据。 它具有观察者模式。因此,每个附加到该内容的 CursorAdapter 都会自行刷新,而无需调用 notifySetDataChanged();

我认为您正在使用 RecyclerView.Adapter。你可以使用this class.

实现添加子功能的另一个建议是使用startActivityForResult(activity);。 您可以使用getIntent().getExtras().put(key,value);发回数据您可以搜索自定义开始活动的结果。

祝你好运

【讨论】:

  • setStyle 不起作用,这是我使用它的结果:imgur.com/Zb5dtPP。而且我真的不明白这如何提供指南中的“向上导航”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-21
  • 2011-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-23
相关资源
最近更新 更多