2013-03-21 2 views
6

Я бы хотел отобразить экран настроек, подобный экрану настроек Android: используя заголовки, PreferenceActivity, PreferenceFragment и категории заголовков.Android - Категории заголовков в PreferenceActivity with PreferenceFragment

Я wan't этот результат на планшете:

enter image description here

И это один на смартфоне:

enter image description here

Это работает, если я просто использовать основные заголовки, но если я пытаюсь добавить категории, он работает на смартфоне и падает на планшет, где я получаю исключение «java.lang.NullPointerException: name == null»:

FATAL EXCEPTION: main 
java.lang.RuntimeException: Unable to start activity ComponentInfo{fr.ifremer.testandroid/fr.ifremer.testandroid.models.preferences.MainPreferenceActivity}: java.lang.NullPointerException: name == null 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2110) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2135) 
    at android.app.ActivityThread.access$700(ActivityThread.java:140) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237) 
    at android.os.Handler.dispatchMessage(Handler.java:99) 
    at android.os.Looper.loop(Looper.java:137) 
    at android.app.ActivityThread.main(ActivityThread.java:4921) 
    at java.lang.reflect.Method.invokeNative(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:511) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805) 
    at dalvik.system.NativeStart.main(Native Method) 
Caused by: java.lang.NullPointerException: name == null 
    at java.lang.VMClassLoader.findLoadedClass(Native Method) 
    at java.lang.ClassLoader.findLoadedClass(ClassLoader.java:354) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:491) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:461) 
    at android.app.Fragment.instantiate(Fragment.java:574) 
    at android.preference.PreferenceActivity.switchToHeaderInner(PreferenceActivity.java:1222) 
    at android.preference.PreferenceActivity.switchToHeader(PreferenceActivity.java:1255) 
    at android.preference.PreferenceActivity.onCreate(PreferenceActivity.java:630) 
    at fr.ifremer.testandroid.models.preferences.MainPreferenceActivity.onCreate(MainPreferenceActivity.java:19) 
    at android.app.Activity.performCreate(Activity.java:5206) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2074) 
    ... 11 more 

Bellow - это части кода. Я получил их в основном из источника приложений Android.

Любая идея?

Заранее спасибо


MainPreferenceActivity:

public class MainPreferenceActivity extends PreferenceActivity { 

    private static List<Header> _headers; 

    @Override 
    public void onBuildHeaders(List<Header> headers) { 

     _headers = headers; 
     loadHeadersFromResource(R.xml.preference_headers, headers); 
    } 

    @Override 
    public void setListAdapter(ListAdapter adapter) { 

     if (adapter == null) { 
      super.setListAdapter(null); 
     } else { 
      super.setListAdapter(new HeaderAdapter(this, _headers)); 
     } 
    } 
} 

PreferencesFragment:

public class PreferencesFragment extends PreferenceFragment { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     String settings = getArguments().getString("settings"); 

     if (settings.equals("DIVE")) { 

      addPreferencesFromResource(R.xml.preference_dive_tile); 
     } 
     else if (settings.equals("MAP")) { 

      addPreferencesFromResource(R.xml.preference_map_tile); 
     } 
    } 
} 

preference_headers.xml:

<?xml version="1.0" encoding="utf-8"?> 
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android" > 

    <header 
     android:id="@+id/header_section_1" 
     android:title="Section 1" /> 

    <header 
     android:fragment="fr.ifremer.testandroid.models.preferences.PreferencesFragment" 
     android:summary="DIVE summary" 
     android:title="DIVE title" > 
     <extra 
      android:name="settings" 
      android:value="DIVE" /> 
    </header> 
    <header 
     android:fragment="fr.ifremer.testandroid.models.preferences.PreferencesFragment" 
     android:summary="MAP summary" 
     android:title="MAP title" > 
     <extra 
      android:name="settings" 
      android:value="MAP" /> 
    </header> 

</preference-headers> 

И последнее, но не в последнюю очередь, HeaderAdapter:

public class HeaderAdapter extends ArrayAdapter<Header> { 

    static final int HEADER_TYPE_CATEGORY = 0; 
    static final int HEADER_TYPE_NORMAL = 1; 
    private static final int HEADER_TYPE_COUNT = HEADER_TYPE_NORMAL + 1; 

    private LayoutInflater mInflater; 

    private static class HeaderViewHolder { 
     ImageView icon; 
     TextView title; 
     TextView summary; 
    } 

    public HeaderAdapter(Context context, List<Header> objects) { 

     super(context, 0, objects); 

     mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    } 

    static int getHeaderType(Header header) { 

     if (header.fragment == null && header.intent == null) return HEADER_TYPE_CATEGORY; 
     else return HEADER_TYPE_NORMAL; 
    } 

    @Override 
    public int getItemViewType(int position) { 
     Header header = getItem(position); 
     return getHeaderType(header); 
    } 

    @Override 
    public boolean areAllItemsEnabled() { return false; /* because of categories */ } 

    @Override 
    public boolean isEnabled(int position) { return getItemViewType(position) != HEADER_TYPE_CATEGORY; } 

    @Override 
    public int getViewTypeCount() { return HEADER_TYPE_COUNT; } 

    @Override 
    public boolean hasStableIds() { return true; } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 

     HeaderViewHolder holder; 
     Header header = getItem(position); 
     int headerType = getHeaderType(header); 
     View view = null; 

     if (convertView == null) { 

      holder = new HeaderViewHolder(); 

      switch (headerType) { 

       case HEADER_TYPE_CATEGORY: 

        view = new TextView(getContext(), null, android.R.attr.listSeparatorTextViewStyle); 
        holder.title = (TextView) view; 
        break; 

       case HEADER_TYPE_NORMAL: 

        view = mInflater.inflate(R.layout.preference_header_item, parent, false); 
        holder.icon = (ImageView) view.findViewById(R.id.icon); 
        holder.title = (TextView) view.findViewById(R.id.title); 
        holder.summary = (TextView) view.findViewById(R.id.summary); 
        break; 
      } 

      view.setTag(holder); 
     } 
     else { 

      view = convertView; 
      holder = (HeaderViewHolder) view.getTag(); 
     } 

     // All view fields must be updated every time, because the view may be recycled 
     switch (headerType) { 

      case HEADER_TYPE_CATEGORY : 

       holder.title.setText(header.getTitle(getContext().getResources())); 
       break; 

      case HEADER_TYPE_NORMAL : 

       holder.icon.setImageResource(header.iconRes); 

       holder.title.setText(header.getTitle(getContext().getResources())); 
       CharSequence summary = header.getSummary(getContext().getResources()); 

       if (!TextUtils.isEmpty(summary)) { 

        holder.summary.setVisibility(View.VISIBLE); 
        holder.summary.setText(summary); 
       } 
       else { 
        holder.summary.setVisibility(View.GONE); 
       } 
       break; 
     } 

     return view; 
    } 
} 

ответ

1

Может быть, первый заголовок по умолчанию выбрано меню. Если это так, у него должен быть атрибут фрагмента, чтобы показать его правую сторону.

+0

Извините, что я опаздываю, я некоторое время отказался от этой проблемы. Вы правы, это не сработало, потому что первый заголовок рассматривался как фрагмент. Но, чтобы исправить это, я не добавил фрагмент к первому заголовку, как мой ответ ниже. –

6

Как сказал bestofbest1, проблема заключалась в том, что Android попытался показать первый элемент в файле preferences_headers.xml, который не содержит фрагмент.

Чтобы исправить это, я добавил в OnCreate MainPreferenceActivity по линии ниже (ДО super.onCreate) для выбора фрагмента по умолчанию при использовании планшета:

if(onIsMultiPane()) getIntent().putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, PreferencesFragment.class.getName()); 

Я также установить фрагмент по умолчанию в PreferencesFragment:

Тогда последняя проблема, PreferenceActivity.EXTRA_SHOW_FRAGMENT не выбирает заголовок в левой части. Чтобы исправить это в MainPreferencesActivity сохранить ссылку на ваши заголовки (в onBuildHeaders), и добавить:

@Override 
protected void onResume() { 

    // Call super : 
    super.onResume(); 

    // Select the displayed fragment in the headers (when using a tablet) : 
    // This should be done by Android, it is a bug fix 
    if(_headers != null) { 

     final String displayedFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT); 
     if (displayedFragment != null) { 
      for (final Header header : _headers) { 
       if (displayedFragment.equals(header.fragment)) { 
        switchToHeader(header); 
        break; 
       } 
      } 
     } 
    } 
} 
2

я получаю решение проблемы Тима работать для меня (программа будет по-прежнему аварии). Я работал над этим по-другому, просто выбрав первый заголовок без категории по умолчанию вместо первого в списке.Для этого я перекрытая метода onGetInitialHeader в моем PreferenceActivity

@Override 
public Header onGetInitialHeader() { 
    for (int i = 0; i < mHeaders.size(); i++) { 
     Header h = mHeaders.get(i); 
     if (!isCategory(h)) { 
      return h; 
     } 
    } 
} 

protected static boolean isCategory(Header h) { 
    return h.fragment == null; 
} 

mHeaders просто ссылка на список заголовков, сохраненный в вызове onBuildHeaders. Следует также отметить, что это только вопрос до 4.3, с тех пор он был исправлен. Надеюсь, что это поможет кому-то из

1

В качестве более простой формы решения Тима Аутина отключите многопалубное устройство, чтобы создать однослойный телефонный дисплей на планшетах.

public class PreferencesActivity extends PreferenceActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     if(onIsMultiPane()) 
      getIntent().putExtra(PreferenceActivity.EXTRA_NO_HEADERS, true); 
     super.onCreate(savedInstanceState); 
    } 
... 
} 
+0

Мой фрагмент предпочтений работал в Android 4 и 5, но был застрял в режиме с одной панелью при использовании Android 6. Это было единственное решение, которое заставило все вернуться к многоуровневой панели. Благодаря!!! – Logic1