Java Android 片段显示为对话框片段或普通片段

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18578295/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 09:10:22  来源:igfitidea点击:

Android fragment show as dialogfragment or usual fragment

javaandroidandroid-layoutandroid-fragmentsandroid-dialogfragment

提问by gunar

What I am trying to achieve is to have a fragment that on tablet it shows as a DialogFragment, while on smartphone it would be shown as a regular fragment. I am aware there is already a similar post, but I am not able to make that work - apply the style to fragment.

我想要实现的是让一个片段在平板电脑上显示为DialogFragment,而在智能手机上它会显示为常规片段。我知道已经有一个类似的帖子,但我无法完成这项工作 - 将样式应用于片段。

To show things top down, MainActivity.java:

为了自上而下地显示内容,MainActivity.java:

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.action_next) {
            decideToNext();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private void decideToNext() {
        String device = getString(R.string.device);
        if ("normal".equalsIgnoreCase(device)) {
            Intent intent = new Intent(this, DetailedActivity.class);
            startActivity(intent);
        } else if ("large".equalsIgnoreCase(device)) {
            Log.d("SOME_TAG", "Yes, I am seeing this line on tablet only");
            DetailedFragment fragment = DetailedFragment.newInstance();
            getSupportFragmentManager().beginTransaction().add(fragment, "MAGIC_TAG").commit();
        }
    }

}

DetailedActivity is nothing much:

详细活动没什么大不了的:

public class DetailedActivity extends ActionBarActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.detailed_activity);
    }
}

its layout:

它的布局:

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_container"
    android:name="com.myapps.sampleandroid.DetailedFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

and the interesting DetailedFragment:

和有趣的DetailedFragment

public class DetailedFragment extends Fragment {

    public static DetailedFragment newInstance() {
        return new DetailedFragment();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Context contextThemeWrapper = new ContextThemeWrapper(getActivity(), R.style.MyDialogTheme);
        LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper);
        return localInflater.inflate(R.layout.detailed_fragment, container, false);
    }
}

... and its layout:

...及其布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Regular Text" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button Dummy" />

</LinearLayout>

In onCreateViewI've tried to set the custom styling but it doesn't seem to work for tablet.

onCreateView我尝试设置自定义样式,但它似乎不适用于平板电脑。

Styling

造型

res/values/styles.xml contains:

res/values/styles.xml 包含:

<resources>

    <style name="AppTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar">
    </style>

    <style name="MyDialogTheme" />

</resources>

while res/values-large/styles.xml:

而 res/values-large/styles.xml:

<resources>
    <!-- Is there anything I should add here? -->
    <style name="MyDialogTheme" parent="@android:style/Theme.Dialog"/>
</resources>

I've nested MyDialogThemefrom Theme.Dialog, but it doesn't seem to help.

我嵌套了MyDialogThemefrom Theme.Dialog,但似乎没有帮助。

On smartphone when tapping on "NEXT" action bar menu item I am seeing the detailed activity (snapshot from an SG2): snapshot from an SG2

在智能手机上点击“NEXT”操作栏菜单项时,我看到了详细的活动(来自 SG2 的快照): 来自 SG2 的快照

while tapping on the same "NEXT" menu item from the tablet it doesn't do anything (except viewing the message on Logcat: Yes, I am seeing this line). enter image description here

在平板电脑上点击相同的“NEXT”菜单项时,它不会执行任何操作(除了查看 Logcat: 上的消息Yes, I am seeing this line)。 在此处输入图片说明

What should I add more in styles.xml or in code in order to see DetailedFragmentas a dialog for tablet?

我应该在styles.xml 或代码中添加更多内容,以便将其DetailedFragment视为平板电脑的对话框?

EDIT

编辑

I've tried the solution Little Childproposed (to have a DialogFragmentcontain my initial fragment and show it). So, I've added a WrapperDetailedFragment:

我已经尝试了Little Child提出的解决方案(DialogFragment包含我的初始片段并显示它)。所以,我添加了一个WrapperDetailedFragment

public class WraperDetailedFragment extends DialogFragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.wrap_detailed_fragment, container, false);
    }
}

its layout:

它的布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_container_dialog"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <fragment
        android:id="@+id/wrapped_fragment_id"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        class="com.myapps.sampleandroid.DetailedFragment" />

</LinearLayout>

The code from MainActivity changes to:

MainActivity 中的代码更改为:

private void decideToNext() {
    String device = getString(R.string.device);
    if ("normal".equalsIgnoreCase(device)) {
        Intent intent = new Intent(this, DetailedActivity.class);
        startActivity(intent);
    } else if ("large".equalsIgnoreCase(device)) {
        Log.d("SOME_TAG", "Yes, I am seeing this line ...");
        WraperDetailedFragment fragment = new WraperDetailedFragment();
        fragment.show(getSupportFragmentManager(), "MAGICAL_TAG");
    }
}

but when I'm trying to add this DialogFragment I am getting the following crash:

但是当我尝试添加这个 DialogFragment 时,我遇到了以下崩溃:

android.view.InflateException: Binary XML file line #8: Error inflating class fragment
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
    at com.myapps.sampleandroid.WraperDetailedFragment.onCreateView(WraperDetailedFragment.java:12)
    at android.support.v4.app.Fragment.performCreateView(Fragment.java:1478)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:927)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1082)
    at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:304)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:676)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
    at com.myapps.sampleandroid.WraperDetailedFragment.onCreateView(WraperDetailedFragment.java:12)
    at android.support.v4.app.Fragment.performCreateView(Fragment.java:1478)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:927)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
    at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1460)
    at android.support.v4.app.FragmentManagerImpl.run(FragmentManager.java:440)
    at android.os.Handler.handleCallback(Handler.java:615)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4745)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalArgumentException: Binary XML file line #8: Duplicate id 0x7f050047, tag null, or parent id 0x0 with another fragment for com.myapps.sampleandroid.DetailedFragment
    at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:290)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:676)
    ... 28 more

采纳答案by gunar

This issue can be easily fixed if instead of trying to make a Fragmentlook like a DialogFragmentI would look from the opposite angle: make a DialogFragmentlook like a Fragment- after all, a DialogFragmentis a Fragment!

这个问题可以很容易地解决,如果不是试图让我Fragment看起来像DialogFragment我会从相反的角度DialogFragment看:让看起来像 a Fragment- 毕竟,aDialogFragment是 a Fragment

The key of this fix is to call or not DialogFragment.setShowsDialog();

此修复的关键是调用与否 DialogFragment.setShowsDialog();

So changing the DetailedFragmentto:

所以更改DetailedFragment为:

public class DetailedFragment extends DialogFragment {

    private static final String ARG_SHOW_AS_DIALOG = "DetailedFragment.ARG_SHOW_AS_DIALOG";

    public static DetailedFragment newInstance(boolean showAsDialog) {
        DetailedFragment fragment = new DetailedFragment();
        Bundle args = new Bundle();
        args.putBoolean(ARG_SHOW_AS_DIALOG, showAsDialog);
        fragment.setArguments(args);
        return fragment;
    }

    public static DetailedFragment newInstance() {
        return newInstance(true);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle args = getArguments();
        if (args != null) {
            setShowsDialog(args.getBoolean(ARG_SHOW_AS_DIALOG, true));
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.detailed_fragment, container, false);
    }
}

its layout remains as it was, DetailedActivitychanges to:

它的布局保持原样,DetailedActivity更改为:

public class DetailedActivity extends ActionBarActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.detailed_activity);
        if (savedInstanceState == null) {
            DetailedFragment fragment = DetailedFragment.newInstance(false);
            getSupportFragmentManager().beginTransaction().add(R.id.root_layout_details, fragment, "Some_tag").commit();
        }
    }
}

its layout as well:

它的布局也是:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_layout_details"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

and the caller activity does only:

并且调用方活动仅执行以下操作:

private void decideToNext() {
    String device = getString(R.string.device);
    if ("normal".equalsIgnoreCase(device)) {
        Intent intent = new Intent(this, DetailedActivity.class);
        startActivity(intent);
    } else if ("large".equalsIgnoreCase(device)) {
        DetailedFragment fragment = DetailedFragment.newInstance();
        fragment.show(getSupportFragmentManager(), "Tablet_specific");
    }
}

回答by Little Child

OK, I have been there and done that. To make a DialogFragmentyou need a layout defined in XML. Say, for this you have LinearLayoutas root. In this LinearLayoutyou can add a fragment class="...."and when you display your DialogFragment, it will be the same Fragmentyou displayed side by side on the tablet now displayed in a DialogFragment.

好的,我去过那里并做到了。要制作一个DialogFragment你需要一个用 XML 定义的布局。说,为此你有LinearLayout作为根。在此LinearLayout您可以添加一个fragment class="....",当您显示您的时DialogFragment,它将与Fragment您在平板电脑上并排显示的相同,现在以DialogFragment.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
<fragment class="com.example.tqafragments.FeedFragment" android:id="@+id/feedFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1"/>
</LinearLayout>  

Like so. And inflate this in your DialogFragment

像这样。并在你的DialogFragment

回答by gunar

To make a DialogFragmentshow as a regular Fragment, call add()or replace()using a resource ID for the fragment container, e.g

要将DialogFragment显示作为常规Fragment,请调用add()replace()使用片段容器的资源 ID,例如

beginTransaction().add(R.id.fragment_container, fragment)

But to make the DialogFragment display as a dialog, call add(fragment, "Fragment Tag"). Behind the scenes this results in a call to add(resId, fragment), setting the resource ID for the fragment container to 0, which causes the DialogFragmentto set its showAsDialogoption to true.

但要使 DialogFragment 显示为对话框,请调用add(fragment, "Fragment Tag"). 在幕后,这会导致调用add(resId, fragment),将片段容器的资源 ID 设置为 0,这会导致DialogFragment将其showAsDialog选项设置为 true。

As a consequence you can use a dialog fragment as a dialog or a regular fragment - depending on your needs - without needing to create any special logic to do it.

因此,您可以将对话框片段用作对话框或常规片段 - 根据您的需要 - 无需创建任何特殊逻辑来执行此操作。