片段可以在旋转时从Dialog切换到Embedded吗?

时间:2012-02-10 23:13:40

标签: android android-fragments

因此,我有一个搜索条件片段,可以输入搜索条件,并且在执行搜索时,搜索结果显示在搜索结果片段中。在平板电脑的风景中,两个片段自然可以并排显示。到目前为止,这很容易实现。

在纵向和手机上,我希望搜索条件片段显示为弹出对话框,而不是搜索结果旁边。在DialogFragment的Selecting Between Dialog or Embedding部分,我看到我可以嵌入片段,也可以将其显示为对话框。如果方向改变不复杂,这可能对我有用。

如果我正在使用< fragment>活动布局中的XML标签,当我进行方向更改时,我会遇到各种各样的麻烦。

编辑:今天我决定尝试看看我是否可以使用DialogFragment在显示对话框和嵌入之间切换,具体取决于设备的方向。事实证明这很困难,我仍然没有找到有用的东西。这是我到目前为止所拥有的。

package org.nsdev.experiments;

import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

public class FragmentSearchTestActivity extends FragmentActivity
{
    private static SearchCriteriaFragment searchCriteriaFragment;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        View container = findViewById(R.id.search_criteria_container);

        android.support.v4.app.FragmentTransaction ft = getSupportFragmentManager().beginTransaction();

        if (searchCriteriaFragment == null)
        {
            searchCriteriaFragment = SearchCriteriaFragment.newInstance();
            searchCriteriaFragment.setStyle(DialogFragment.STYLE_NO_TITLE, 0);
        }

        android.support.v4.app.Fragment f = getSupportFragmentManager().findFragmentByTag("search_criteria");
        if (f != null)
        {
            ft.remove(f);
        }

        if (container == null)
        {
            searchCriteriaFragment.setCancelable(true);
            searchCriteriaFragment.setHasOptionsMenu(false);
            searchCriteriaFragment.show(getSupportFragmentManager(), "search_criteria");
        }
        else
        {
            ft.remove(searchCriteriaFragment);
            ft.add(R.id.search_criteria_container, searchCriteriaFragment, "search_criteria");
            ft.commit();
        }
    }

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

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        if (item.getItemId() == R.id.menu_item_search)
        {
            searchCriteriaFragment.show(getSupportFragmentManager(), "search_criteria");
        }
        return super.onOptionsItemSelected(item);
    }
}

具体来说,除非我保留SearchCriteriaFragment的静态副本并在Activity中调用onCreate时重复使用它,否则我无法正常工作。这对我来说似乎非常不对。

SearchResultsFragment.java:

package org.nsdev.experiments;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class SearchResultsFragment extends android.support.v4.app.Fragment
{

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

}

SearchCriteriaFragment.java:

package org.nsdev.experiments;

import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class SearchCriteriaFragment extends android.support.v4.app.DialogFragment
{

    private static final String TAG = "SearchCriteriaFragment";
    View v;

    static SearchCriteriaFragment newInstance()
    {
        Log.e(TAG, "newInstance");
        SearchCriteriaFragment d = new SearchCriteriaFragment();
        return d;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        if (v == null)
        {
            v = inflater.inflate(R.layout.criteria, container, false);
        } 
        else
        {
            if (v.getParent() instanceof ViewGroup) 
            {
                Log.e(TAG, "Removing from viewgroup");
                ((ViewGroup)v.getParent()).removeAllViews();
            }
        }

        return v;
    }

}

在这里,您可以看到我必须解决视图被重用的问题。有一个错误表明该视图已经有一个父级,并且需要在将其添加到另一个父级之前将其从中删除。再次,这似乎我必须采取错误的方式。

RES /布局/ main.xml中:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <fragment
        android:id="@+id/search_results"
        android:name="org.nsdev.experiments.SearchResultsFragment"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</RelativeLayout>

RES /布局脊/ main.xml中:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <FrameLayout
        android:id="@+id/search_criteria_container"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent" />

    <fragment
        android:id="@+id/search_results"
        android:layout_toRightOf="@+id/search_criteria_container"
        android:name="org.nsdev.experiments.SearchResultsFragment"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</RelativeLayout>

您可以从这两个布局中看到我想要做的事情。在正常方向,FrameLayout不存在,因此我们可以检测到它并显示DialogFragment。否则,我们可以将DialogFragment嵌入到FrameLayout中。

最后两个布局我只是将占位符放入结果和标准布局中:

RES /布局/ criteria.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" android:background="#300F">

    <CheckBox
        android:id="@+id/checkBox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="21dp"
        android:paddingRight="30dp"
        android:text="Test Criteria" />

</RelativeLayout>

RES /布局/ results.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" android:background="#f00">

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:text="Results"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>

在我开始旋转设备并检查ICS设备上的复选框之前,我以为我已经弄明白了。请注意,我已将该颜色设置为criteria.xml RelativeLayout背景的半透明颜色。我注意到的是,在横向方向上,嵌入式视图实际上是保留了旧版本的视图,每当我切换到纵向并再次返回时,这些视图将覆盖更新的视图副本。这是我试图只保留SeachCriteriaFragment的onCreateView返回的视图的一个副本的原因之一。这不能解决这个问题。

我只能得出一个结论:我一定是做错了。我怀疑Fragments框架从未被设计用于执行这种片段重用。如何在Portrait中显示一个很好的旋转工作,我将DialogFragment显示为对话框,而在Landscape中它是嵌入式的?我可以让框架更自动地执行此类操作吗?

我尝试设置searchCriteriaFragment.setRetainInstance(true)并且所有地狱都崩溃了,所以我立即删除了该行。

感谢您帮助我走上正确的道路。

1 个答案:

答案 0 :(得分:0)

我会说这个。

在手机上将SearchFormFragment设为Activity,并为其指定主题Dialog。 然后,SearchResultsFragment也是一个单独的Activity。

SearchForm xml看起来像:

 <LinearLayout >
   <fragment class="com.your.package.ui.fragment.SearchFormFragment" />
 </LinearLayout>

获取Dialog theme

 <manifest . . . >
      <application . . . >
         <activity 
            android:name=".ui.phone.SearchFormFragmentActivity"
            android:theme="@android:style/Theme.Dialog" . . . >
         <activity 
            android:name=".ui.phone.SearchResultsFragmentActivity" . . . >

这可以使用onSaveInstanceStateonRestoreInstanceState以及活动生命周期简化方向更改。

然后在平板电脑上,你有另外两个片段的活动。

         <activity 
            android:name=".ui.tablet.SearchFragmentActivity" . . . >

SearchFragmentActivity.xml:

   <LinearLayout >
     <fragment class="com.your.pacakage.ui.fragment.SearchFormFragment"/>
     <fragment class="com.your.package.ui.fragment.SearchResultsFragment" />
   </LinearLayout>

简化。