36

Vấn đề
luân phiên một thiết bị từ một bức chân dung một khung PreferenceScreen đến một cảnh quan hai cửa sổ PreferenceScreen, gây ra cảnh quan để chỉ hiển thị như một cửa sổ. KHÔNG xảy ra khi xem màn hình tiêu đề.Các vấn đề với màn hình sở thích dual-pane

Thiết lập
Đây chỉ dành cho ICS và chỉ lên. Tôi có PreferenceActivity tải preference-headers. Mỗi tiêu đề liên kết với một số Fragment, lần lượt tải PreferenceScreen. Khá chạy của mil.

Chi tiết
Mọi thứ hoạt động tốt cho đến khi tôi nhận thấy Android sẽ chỉ tự động chuyển sang giao diện hai cửa sổ cho một số màn hình nhất định. Sau một số nghiên cứu tôi đã học được từ một số Commonsware post rằng Android sẽ chỉ làm như vậy đối với sw720dp. Bit của một sự lãng phí nếu bạn hỏi tôi vì nhiều thiết bị def có rất nhiều chỗ cho hai-panes. Vì vậy, tôi đã ghi đè phương thức onIsMultiPane() để trả về true cho w600dp trở lên. Làm việc như một say mê .... kinda.

Đưa ra một thiết bị sẽ hiển thị một cửa sổ theo chiều dọc và khung kép ở chế độ ngang; xem các tiêu đề theo chiều dọc và xoay ngang, hoạt động tốt. Tuy nhiên, nếu người dùng chọn một tiêu đề và tải màn hình tiếp theo của nó ở chế độ dọc, sau đó xoay để ngang thiết bị sẽ ở lại một cửa thay vì chuyển về chế độ hai ngăn. Nếu sau đó bạn quay trở lại điều hướng đến màn hình tiêu đề, nó sẽ trở lại giao diện hai ngăn ngoại trừ việc nó sẽ không chọn trước tiêu đề. Kết quả là ngăn chi tiết vẫn trống.

Hành vi này có dự định không? Dù sao để làm việc xung quanh nó? Tôi cũng đã cố gắng ghi đè onIsHidingHeaders() nhưng điều đó đã khiến mọi thứ hiển thị màn hình trống.


Preference Hoạt động:

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


Một Preference Tiêu đề 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

gì "nói" một góc độ debug? –

+0

Bạn có một giá trị chứa trạng thái "hiển thị". –

+0

PreferenceActivity xử lý các thay đổi về mức hiển thị. Tôi đặc biệt không thay đổi bất kỳ thứ gì. Các mã trên là nghĩa đen tất cả tôi đang làm. –

Trả lời

2

vấn đề giải quyết
Với cách phổ biến câu hỏi này đã trở thành, tôi quyết định xem lại vấn đề này một lần nữa và xem tôi Tôi có thể tìm thấy một giải pháp ... và tôi đã làm.Tìm thấy một công việc nhỏ đẹp xung quanh mà giải quyết các cửa sổ duy nhất hiển thị thay vì ngăn kép và đảm bảo một tiêu đề luôn luôn được lựa chọn trước khi ở chế độ cửa sổ kép.

Nếu bạn không quan tâm đến giải thích, bạn có thể chỉ cần bỏ qua xuống mã. Nếu bạn không quan tâm đến ICS, rất nhiều mã theo dõi tiêu đề có thể được gỡ bỏ khi JB thêm một getter cho danh sách mảng tiêu đề.

kép Pane Issue
Khi xem sở thích danh sách tiêu đề trong chế độ cửa sổ duy nhất hoặc chế độ cửa sổ kép, chỉ có bao giờ một PreferenceActivity tạo ra và đó là hoạt động tương tự cho cả hai trường hợp. Kết quả là, không bao giờ có vấn đề trong việc xử lý xoay màn hình sẽ chuyển sang chế độ cửa sổ.

Tuy nhiên, trong chế độ cửa sổ đơn khi bạn bấm vào một tiêu đề, đoạn tương ứng được gắn vào một PreferenceActivity MỚI. Đoạn mới này chứa PreferenceActivity không bao giờ gọi onBuildHeaders(). Và tại sao nó? Nó không cần hiển thị chúng. Điều này nằm trong vấn đề.

Khi xoay đoạn đó thành chế độ cửa sổ kép, nó không có bất kỳ danh sách tiêu đề nào để hiển thị để nó chỉ tiếp tục hiển thị đoạn đó. Ngay cả khi nó đã hiển thị danh sách của tiêu đề, bạn sẽ có một số vấn đề backstack vì bây giờ bạn sẽ có hai bản sao của PreferenceActivity hiển thị tiêu đề. Tiếp tục nhấp vào đủ tiêu đề và bạn sẽ nhận được khá nhiều hoạt động để người dùng điều hướng trở lại. Kết quả là, câu trả lời rất đơn giản. Chỉ cần finish() hoạt động. Sau đó nó sẽ tải PreferenceActivity ban đầu mà DOES có danh sách tiêu đề và sẽ hiển thị đúng chế độ cửa sổ kép.

Auto Lựa chọn Tiêu đề
Vấn đề tiếp theo mà cần giải quyết là chuyển đổi giữa duy nhất để chế độ cửa sổ kép với việc sửa chữa mới không tự động chọn một tiêu đề. Bạn đã được để lại với một danh sách tiêu đề và không có đoạn chi tiết nào được tải. Sửa chữa này không phải là khá đơn giản. Về cơ bản, bạn chỉ cần theo dõi tiêu đề nào được nhấp lần cuối và đảm bảo trong quá trình tạo PreferenceActivity ... một tiêu đề luôn được chọn.

Điều này kết thúc một chút phiền toái trong ICS vì API không hiển thị bộ thu thập cho danh sách tiêu đề được theo dõi nội bộ. Android đã tồn tại danh sách đó và bạn về mặt kỹ thuật có thể lấy nó bằng cách sử dụng cùng một khóa chuỗi nội bộ được lưu trữ riêng tư tuy nhiên đó chỉ là một lựa chọn thiết kế tồi. Thay vào đó, tôi khuyên bạn nên tự mình tiếp tục một lần nữa.

Nếu bạn không quan tâm đến ICS, bạn chỉ có thể sử dụng phương thức getHeaders() được hiển thị trong JB và không lo lắng về bất kỳ nội dung nào được lưu/khôi phục trạng thái này.


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

Đây là một giải pháp tốt, nhưng nó vẫn có một vấn đề tôi đã tìm thấy. Giả sử cho đơn giản đa cửa sổ là đúng iff bạn đang ở chế độ phong cảnh. Bây giờ chạy ứng dụng của bạn trên chế độ dọc (cửa sổ duy nhất), chọn một tiêu đề, chuyển sang chế độ ngang (đa cửa sổ) và sau đó chuyển sang chế độ dọc. Vấn đề là mục đã chọn không còn được khôi phục. Nó vừa trở lại màn hình cài đặt chính, hiển thị tất cả các tiêu đề. Không phải là một vấn đề lớn. Lạ thật ... –

0

Ý tưởng chính đằng sau mã dưới đây đến từ các blog entry Commonsware liên kết trong câu hỏi, vì vậy nó cảm thấy có liên quan. Tôi đặc biệt đã phải mở rộng khái niệm để đối phó với một vấn đề thay đổi định hướng mà âm thanh rất giống với một trong câu hỏi, vì vậy đây là hy vọng nó sẽ cho bạn một sự khởi đầu.

Lớp Cài đặt không được mang bất kỳ sự cố nào về vấn đề định hướng, nhưng bao gồm cả vấn đề vẫn rõ ràng.

mỗi comment mã của tôi, xem nếu checkNeedsResource cuộc gọi trong onCreate sẽ giúp tại tất cả:

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

Tôi không chắc chắn những gì bạn đăng ở đây nhưng điều này không hoạt động. Trong thực tế, tôi không chắc làm thế nào điều này xử lý bất kỳ thay đổi định hướng. Tôi cũng không lo lắng về bất cứ điều gì trước khi ICS, vì vậy không ai trong số đó bị phản đối addPreferencesFromResource hành vi có liên quan đến câu hỏi của tôi ... cũng không phải là sở thích của bạn thay đổi người nghe. –

+0

Lý do giải quyết sự cố mà tôi gặp phải là việc kiểm tra inCreate, xảy ra sau khi thay đổi định hướng. Rằng nó đã không giúp đỡ với các vấn đề bạn đang chạy vào được nhiều hơn hoặc ít hơn bao phủ trong "của tôi đây là hy vọng ...". Vui vì bạn giữ nó sau đó, và đăng độ phân giải của bạn. –

Các vấn đề liên quan