问题
将设备从单窗格纵向PreferenceScreen
旋转到双窗格横向PreferenceScreen
,会导致横向仅显示为单窗格。查看标题屏幕时不会发生。
设置
这仅适用于ICS。我有PreferenceActivity
加载preference-headers
。每个标题都与Fragment
相关联,后者又会加载PreferenceScreen
。相当运行的mil。
详情
一切都运作良好,直到我注意到Android只会自动切换到某个屏幕的双窗格外观。经过一些研究后,我从Commonsware post了解到Android只会对sw720dp这样做。如果你问我我有点浪费,因为许多设备def有足够的空间用于双窗格。所以我重写了onIsMultiPane()
方法,为w600dp及以上返回true。工作就像一个魅力....有点。
给定一个设备,它将在纵向和双窗格中显示单窗格;以纵向查看标题并旋转到横向,工作正常。但是,如果选择一个标题并以纵向模式加载它的后续屏幕,则旋转到横向设备将保持单窗格而不是切换回双窗格。如果您然后返回导航到标题屏幕,它将返回双窗格外观,但它不会预先选择标题。因此,详细信息窗格保持空白。
这是预期的行为吗?无论如何要解决它吗?我尝试覆盖onIsHidingHeaders()
,但这只会导致所有内容显示为空白。
代码
偏好活动:
public class SettingsActivity extends PreferenceActivity {
@Override
public void onBuildHeaders(List<Header> target) {
super.onBuildHeaders(target);
loadHeadersFromResource(R.xml.preference, target);
}
@Override
public boolean onIsMultiPane() {
return getResources().getBoolean(R.bool.pref_prefer_dual_pane);
}
}
偏好标题片段:
public class ExpansionsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_expansions);
}
public static ExpansionsFragment newInstance() {
ExpansionsFragment frag = new ExpansionsFragment();
return frag;
}
}
答案 0 :(得分:2)
解决问题
随着这个问题越来越受欢迎,我决定再次重新审视这个问题,看看我能否找到解决方案......而且我做到了。找到了一个很好的小工作,它解决了单个窗格显示而不是双窗格,并确保在双窗格模式下始终预先选择标题。
如果您不关心解释,可以直接跳到代码。如果你不关心ICS,可以删除很多头部跟踪代码,因为JB为头部数组列表添加了一个getter。
双重窗格问题
在单窗格模式或双窗格模式下查看首选项标题列表时,只创建了一个PreferenceActivity,并且对于这两种情况它都是相同的活动。因此,处理将切换窗格模式的屏幕旋转永远不会出现问题。
但是,在单一窗格模式下单击标题时,相应的片段将附加到新的PreferenceActivity。这个包含PreferenceActivity的新片段从不调用onBuildHeaders()
。为什么会这样呢?它不需要显示它们。这就是问题所在。
将该片段旋转到双窗格模式时,它没有任何要显示的标题列表,因此它只是继续显示片段。即使它确实显示了标题列表,您也会遇到一些后端问题,因为您现在有两个PreferenceActivity副本显示标题。继续单击足够的标题,您将获得相当长的一系列活动,供用户导航回来。结果,答案很简单。只需finish()
活动。然后它将加载原始的PreferenceActivity,它具有标题列表,并将正确显示双窗格模式。
自动选择标题
需要解决的下一个问题是,使用新修复程序在单窗格模式和双窗格模式之间切换时,不会自动选择标头。你留下了一个标题列表,没有加载任何细节片段。这个修复不是那么简单。基本上你只需要跟踪上次点击的标题,并确保在创建PreferenceActivity期间...始终选择标题。
这最终在ICS中有点烦人,因为API不会为内部跟踪的标题列表公开getter。 Android确实已经保留了该列表,您可以通过使用相同的私有存储内部字符串键从技术上检索它,但这只是一个糟糕的设计选择。相反,我建议你自己再次手动保持它。
如果您不关心ICS,那么您可以使用JB中公开的getHeaders()
方法,而不用担心任何这种保存/恢复状态。
<强>代码强>
public class SettingsActivity extends PreferenceActivity {
private static final String STATE_CUR_HEADER_POS = "Current Position";
private static final String STATE_HEADERS_LIST = "Headers List";
private int mCurPos = AdapterView.INVALID_POSITION; //Manually track selected header position for dual pane mode
private ArrayList<Header> mHeaders; //Manually track headers so we can select one. Required to support ICS. Otherwise JB exposes a getter instead.
@Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.preference, target);
mHeaders = (ArrayList<Header>) target; //Grab a ref of the headers list
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//This is the only code required for ensuring a dual pane mode shows after rotation of a single paned preference screen
if (onIsMultiPane() && onIsHidingHeaders()) {
finish();
}
}
@Override
public boolean onIsMultiPane() {
//Override this if you want dual pane to show up on smaller screens
return getResources().getBoolean(R.bool.pref_prefer_dual_pane);
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
//Intercept a header click event to record its position.
mCurPos = position;
}
@Override
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
//Retrieve our saved header list and last clicked position and ensure we switch to the proper header.
mHeaders = state.getParcelableArrayList(STATE_HEADERS_LIST);
mCurPos = state.getInt(STATE_CUR_HEADER_POS);
if (mHeaders != null) {
if (mCurPos != AdapterView.INVALID_POSITION) {
switchToHeader(mHeaders.get(mCurPos));
} else {
switchToHeader(onGetInitialHeader());
}
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//Persist our list and last clicked position
if (mHeaders != null && mHeaders.size() > 0) {
outState.putInt(STATE_CUR_HEADER_POS, mCurPos);
outState.putParcelableArrayList(STATE_HEADERS_LIST, mHeaders);
}
}
}
答案 1 :(得分:0)
以下代码背后的关键思想来自问题中链接的Commonsware博客条目,因此感觉相关。我特别需要扩展这个概念来处理一个方向改变问题,这个问题与问题中的问题非常相似,所以这里希望它能给你一个开始。
“设置”类不应对方向问题有任何影响,但无论如何都要包含它以便清楚。
根据我的代码评论,看看checkNeedsResource
中的onCreate
电话是否有帮助:
public class SettingsActivity
extends
PreferenceActivity
{
@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Show settings without headers for single pane or pre-Honeycomb. Make sure to check the
// single pane or pre-Honeycomb condition again after orientation change.
if (checkNeedsResource()) {
MyApp app = (MyApp)getApplication();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(app);
Settings settings = new Settings();
addPreferencesFromResource(R.xml.prefs_api);
settings.setupPreference(findPreference(MyApp.KEY_USERNAME), prefs.getString(MyApp.KEY_USERNAME, null), true);
settings.setupPreference(findPreference(MyApp.KEY_API_URL_ROOT), prefs.getString(MyApp.KEY_API_URL_ROOT, null), true);
if (this.isHoneycomb) {
// Do not delete this. We may yet have settings that only apply to Honeycomb or higher.
//addPreferencesFromResource(R.xml.prefs_general);
}
addPreferencesFromResource(R.xml.prefs_about);
settings.setupPreference(findPreference(MyApp.KEY_VERSION_NAME), app.getVersionName());
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void onBuildHeaders(List<Header> target) {
super.onBuildHeaders(target);
// This check will enable showing settings without headers for single pane or pre-Honeycomb.
if (!checkNeedsResource()) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
}
private boolean checkNeedsResource() {
// This check will enable showing settings without headers for single pane or pre-Honeycomb.
return (!this.isHoneycomb || onIsHidingHeaders() || !onIsMultiPane());
}
private boolean isHoneycomb = (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB);
}
public class Settings {
public Settings() {
}
public void setupPreference(Preference pref, String summary, boolean setChangeListener) {
if (pref != null) {
if (summary != null) {
pref.setSummary(summary);
}
pref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference pref, Object newValue) {
pref.setSummary(newValue.toString());
return true;
}
});
}
}
public void setupPreference(Preference pref, String summary) {
setupPreference(pref, summary, false);
}
}