Итак, у меня есть фрагмент критериев поиска, в который можно вводить критерии поиска, и когда поиск выполняется, результаты поиска отображаются во фрагменте результатов поиска. В альбомной ориентации два фрагмента, естественно, могут отображаться рядом. Пока это просто реализовать.
В портретной ориентации и на телефоне я бы хотел, чтобы фрагмент Критерии поиска отображался как всплывающее диалоговое окно, а не рядом с результатами поиска. В разделе Выбор между диалогом или встраиванием в DialogFragment я вижу, что я могу либо встроить фрагмент, либо показать его в виде диалога. Это может сработать для меня, если не усложнит изменение ориентации.
Если я использую теги 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 и повторно использовал ее всякий раз, когда onCreate вызывался в Activity. Это кажется мне очень неправильным.
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;
}
}
Здесь вы видите, что мне пришлось обойти проблему с повторным использованием вида. Произошла ошибка, указывающая на то, что представление уже имеет родителя и его необходимо удалить из него, прежде чем его можно будет добавить к другому родителю. Опять же, похоже, что я, должно быть, поступаю неправильно.
Рез / макет / 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>
Рез / макет-земля / 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.
Последние два макета, в которые я только что поместил заполнители для результатов и макетов критериев:
Рез / макет / 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>
Рез / макет / 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. Обратите внимание на то, что я установил полупрозрачный цвет фона для crit.xml RelativeLayout. Что я заметил, так это то, что в альбомной ориентации встроенный вид на самом деле сохранял старые версии вида, и они будут перекрываться новыми копиями вида каждый раз, когда я переключался в портретный режим и обратно. Это одна из причин, по которой я пытался сохранить только одну копию представления, возвращенного из onCreateView объекта SeachCriteriaFragment. Это не решает эту проблему.
Я могу сделать только один вывод: я, должно быть, поступаю неправильно. Я подозреваю, что структура Fragments никогда не была разработана для такого повторного использования фрагментов. Как я могу получить хорошее вращение, работающее, когда в Portrait я показываю DialogFragment в виде диалога, а в Landscape он встроен? Могу ли я заставить фреймворк делать что-то подобное более автоматически?
Я попытался установить searchCriteriaFragment.setRetainInstance (true), и весь ад развалился, поэтому я немедленно удалил эту строку.
Спасибо за любую помощь, чтобы вывести меня на правильный путь здесь.