36

Problem
ein Gerät aus einem Porträt einer Scheibe Rotierende PreferenceScreen auf eine Zwei-Scheiben-Landschaft PreferenceScreen verursachen Landschaft nur als eine Scheibe zu zeigen. Tritt nicht auf, wenn Sie den Kopfzeilenbildschirm anzeigen.Probleme mit Dual-Fenstern Vorzugsbildschirmen

Setup
Dies ist nur für ICS und aufwärts. Ich habe eine PreferenceActivity, die preference-headers lädt. Jeder Header verbindet sich mit einem , der wiederum eine PreferenceScreen lädt. Hübscher Lauf der Mil.

Einzelheiten
Alles funktionierte gut, bis ich, dass Android bemerkt wird nur Auto-Schalter auf einen Zwei-Scheiben-Look für bestimmte Bildschirme. Nach einiger Recherche habe ich von einer Commonsware post erfahren, dass Android das nur für sw720dp tun wird. Etwas von einer Verschwendung, wenn Sie mich fragen, da viele Geräte def viel Platz für zwei Scheiben haben. Also überging ich die onIsMultiPane() Methode, um für w600dp und aufwärts wahr zurückzukommen. Arbeitete wie ein Charme .... irgendwie.

Gegeben ein Gerät, das Single-Fenster im Hochformat und Dual-Fenster im Querformat zeigt; Anzeigen der Header im Hochformat und Drehen in die Landschaft, funktioniert gut. Wenn Sie jedoch eine Kopfzeile auswählen und den folgenden Bildschirm im Hochformat laden, drehen Sie den Mauszeiger auf Querformat, um das Gerät in einem einzigen Fenster zu belassen, anstatt wieder in das Dual-Fenster zu wechseln. Wenn Sie dann zurück zum Kopfzeilenbildschirm navigieren, wird wieder ein Dual-Pane-Look angezeigt, mit der Ausnahme, dass eine Kopfzeile nicht vorausgewählt wird. Daher bleibt das detaillierte Fenster leer.

Ist das beabsichtigte Verhalten? Wie auch immer, um es zu umgehen? Ich versuchte auch, onIsHidingHeaders() zu überschreiben, aber das verursachte nur alles, um einen leeren Bildschirm zu zeigen.

-Code
Preference Aktivität:

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); 
} 
} 


A Preference Kopf Frag:

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

Was "sagen", um eine Perspektive debug? –

+0

Sie haben einen Wert, der den Status "sichtbar" enthält. –

+0

PreferenceActivity behandelt die Sichtbarkeitsänderungen. Ich ändere gerade nichts davon. Der obige Code ist buchstäblich alles, was ich tue. –

Antwort

2

Problem gelöst
Mit wie beliebt diese Frage ist geworden, entschied ich mich, dieses Thema noch einmal zu besuchen und ich sehe Ich könnte eine Lösung finden ... und ich habe es getan.Es wurde eine nette kleine Arbeit gefunden, die das einzelne Fenster anstelle des Doppelfensters löst und sicherstellt, dass eine Kopfzeile im Dual-Fenster-Modus immer vorausgewählt ist.

Wenn Sie sich nicht um eine Erklärung kümmern, können Sie einfach weiter zum Code springen. Wenn Sie sich nicht für ICS interessieren, kann ein Großteil des Header-Tracking-Codes entfernt werden, da JB einen Getter für die Header-Array-Liste hinzugefügt hat.

Dual-Fenster Ausgabe
Wenn in Einscheiben-Modus oder Dual-Fenster-Modus die Präferenz Kopf Liste sehen, gibt es immer nur einen PreferenceActivity erstellt und es ist die gleiche Aktivität für beide Fälle. Daher gibt es bei der Behandlung von Bildschirmdrehungen nie ein Problem, das den Fenstermodus wechselt.

Wenn Sie jedoch im Einzelbildmodus auf eine Kopfzeile klicken, wird das entsprechende Fragment an eine NEUE PreferenceActivity angehängt. Dieses neue Fragment, das PreferenceActivity enthält, ruft niemals onBuildHeaders() auf. Und warum sollte es? Es muss sie nicht anzeigen. Das liegt am Problem.

Wenn Sie dieses Fragment in einen Dual-Fenster-Modus drehen, hat es keine Header-Liste zur Anzeige, so dass nur das Fragment angezeigt wird. Selbst wenn die Liste des Headers angezeigt wird, treten einige Backstack-Probleme auf, da Sie nun zwei Kopien der PreferenceActivity mit Headern haben. Klicken Sie auf genügend Header und Sie erhalten einen ziemlich langen Stapel von Aktivitäten, durch die der Benutzer zurück navigieren kann. Als Ergebnis ist die Antwort einfach. Nur finish() die Aktivität. Dann wird die ursprüngliche PreferenceActivity geladen, die die Header-Liste enthält und den Dual-Fenster-Modus korrekt anzeigt.

Auto Auswahl Kopf
Das nächste Problem, das war nötig Bewältigung, dass mit dem neuen Update zwischen Single Dual-Fenster-Modus Umschalten eines Header nicht automatisch ausgewählt hat. Sie hatten eine Kopfzeilenliste und kein Detailfragment geladen. Diese Lösung ist nicht ganz so einfach. Im Grunde müssen Sie nur verfolgen, welche Kopfzeile zuletzt angeklickt wurde und sicherstellen, dass während der PreferenceActivity-Erstellung ... immer eine Kopfzeile ausgewählt wird.

Dies ist ein wenig nervig in ICS, da die API keinen Getter für die intern nachverfolgte Header-Liste verfügbar macht. Android speichert diese Liste bereits und Sie können sie technisch abrufen, indem Sie den gleichen privat gespeicherten internen String-Schlüssel verwenden, aber das ist nur eine schlechte Design-Wahl. Stattdessen schlage ich vor, dass Sie es manuell wiederholen.

Wenn Sie sich nicht für ICS interessieren, dann können Sie einfach die getHeaders() Methode verwenden, die in JB offengelegt wurde, und sich keine Gedanken über irgendwelche gespeicherten/wiederhergestellten Zustände machen.

-Code

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); 
    } 
} 
} 
+0

Dies ist eine schöne Lösung, aber es hat immer noch ein Problem, das ich gefunden habe. Angenommen, die Multi-Pane-Funktion ist wahr, wenn Sie im Querformat arbeiten. Jetzt ist Ihre App auf Portrait-Modus (Einscheibensicherheitsglas) auszuführen, wählen Sie einen Header, wechseln Sie in Landschaft (Multi-Bereich) und wechseln Sie dann auf Portrait-Modus. Das Problem besteht darin, dass das ausgewählte Objekt nicht mehr wiederhergestellt wird. Es ging einfach zurück zum Haupteinstellungen Bildschirm, der alle Header anzeigt. Kein großes Problem. Einfach nur komisch... –

0

Die Schlüsselidee hinter dem Code kam unten aus dem Commonsware Blogeintrag verknüpft in die Frage, so fühlt es sich relevant an. Ich musste das Konzept speziell auf ein Problem der Orientierungsänderung ausweiten, das dem in der Frage sehr ähnlich klingt, also hoffe ich, dass es dir einen Anfang gibt.

Die Klasse "Einstellungen" sollte keine Auswirkungen auf das Ausrichtungsproblem haben, sie jedoch trotzdem einschließen, um klar zu sein.

Per meinen Code Kommentar, ob die checkNeedsResource Anruf in onCreate überhaupt helfen:

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); 
} 

}

+0

Ich bin mir nicht ganz sicher, was Sie hier gepostet, aber das funktioniert nicht. In der Tat bin ich nicht sicher, wie dies mit irgendwelchen Orientierungsänderungen umgeht. Ich bin auch keine Sorgen über irgendetwas vor ICS, so dass keiner der veralteten addPreferencesFromResource Verhalten ist relevant für meine Frage ... noch ist Ihre Präferenz Zuhörer geändert. –

+0

Der Grund ist es das Problem behoben ich in lief ist, dass der Check in onCreate, die nach einer Orientierungsänderung auftritt. Dass es bei dem Problem, in das du hineingerannt bist, nicht geholfen hat, war mehr oder weniger in meinem "Hier ist Hoffnung ..." enthalten. Ich bin froh, dass du dich daran gehalten hast und hast deine Entschließung veröffentlicht. –