2013-06-25 3 views
7

Мне нужно создать пользовательский диалог ListPreference, чтобы я мог добавить текст заголовка (TextView) над списком (ListView). Я создал класс, который расширяет MyListPreference ListPreference и отменяет onCreateDialogView():Почему ListView остается выше TextView в диалоговом окне ListPreference?

@Override 
protected View onCreateDialogView() { 
    LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    View v = (View) inflater.inflate(R.layout.dialog_preference_list, null); 
    return v; 
} 

Мой макет XML dialog_preference_list.xml содержит:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:orientation="vertical" > 

    <TextView 
     android:id="@+id/textView1" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="TextView" /> 

    <ListView 
     android:id="@android:id/list" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:drawSelectorOnTop="false" 
     android:scrollbarAlwaysDrawVerticalTrack="true" /> 

</LinearLayout> 

Проблема: TextView отображается под ListView вместо выше. Мне нужно, чтобы TextView был выше. Я пробовал оба с LinearLayout и RelativeLayout (используя атрибуты «ниже» или «выше») без успеха: я не могу найти способ разместить TextView над ListView ... Макет довольно прост, и я не вижу почему список остается выше ... Также обратите внимание, что проблема возникает как на реальном устройстве (Nexus 4, Android 4.2.2), так и на эмуляторе. Однако при просмотре макета, представленного в графическом макете Eclipse, макет правильный! Посмотрите обе прикрепленные фотографии.

Любая идея о том, как это решить?

Макет визуализации на устройстве (неправильному):

Layout rendered on the device (incorrect)

Layout вынесенном Eclipse, (правильный):

Layout rendered on Eclipse (correct)

Edit с раствором 10.07.2013

Как предложено принятым ответом, проблема возникает из-за использования builder.setSingleChoiceItems() в onPrepareDialogBuilder() в ListPreference. Я исправил его, расширив ListPreference и переопределив onCreateDialogView(), чтобы построить диалог без строителя, чтобы я мог создать пользовательский вид, отображающий текст заголовка над элементами списка.

GPListPreference.java:

public class GPListPreference extends ListPreference { 
    ... 

    @Override 
    protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { 
     builder.setNegativeButton(null, null); 
     builder.setPositiveButton(null, null); 
    } 

    private int getValueIndex() { 
     return findIndexOfValue(getValue()); 
    } 

    @Override 
    protected View onCreateDialogView() { 
     LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     ListView lv = (ListView) inflater.inflate(R.layout.dialog_preference_list, null); 

     TextView header = (TextView) inflater.inflate(R.layout.dialog_preference_list_header, null); 
     header.setText(getDialogMessage()); // you should set the header text as android:dialogMessage in the preference XML 
     lv.addHeaderView(header); 

     ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(getContext(), R.layout.dialog_preference_list_singlechoice, getEntries()); 
     lv.setAdapter(adapter); 

     lv.setClickable(true); 
     lv.setEnabled(true); 
     lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 
     lv.setItemChecked(getValueIndex() + 1, true); 
     lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { 

      @Override 
      public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 
       setValueIndex(position - 1); 
       getDialog().dismiss(); 
      } 
     }); 

     return lv; 
    } 
} 

dialog_preference_list.xml:

<?xml version="1.0" encoding="utf-8"?> 
<ListView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@android:id/list" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:drawSelectorOnTop="false" 
    android:scrollbarAlwaysDrawVerticalTrack="true" /> 

dialog_preference_list_singlechoice.xml

<?xml version="1.0" encoding="utf-8"?> 
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@android:id/text1" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:checkMark="?android:attr/listChoiceIndicatorSingle" 
    android:ellipsize="marquee" 
    android:gravity="center_vertical" 
    android:minHeight="?android:attr/listPreferredItemHeight" 
    android:paddingBottom="2dip" 
    android:paddingLeft="10dip" 
    android:paddingRight="10dip" 
    android:paddingTop="2dip" 
    android:textAppearance="?android:attr/textAppearanceMedium" /> 

dialog_preference_list_header.xml

<?xml version="1.0" encoding="utf-8"?> 
<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:padding="10dip" 
    android:textAppearance="?android:attr/textAppearanceSmall"> 

</TextView> 
+0

Вы можете добавить код, в котором вы инициализировать значения для списка? или любой код, который ссылается на «ListView» – Muzikant

+0

. Чтобы быть понятным, вы пробовали: 'android: layout_above =" @ + id/list "' и, необязательно, 'android: layout_alignParentTop =" true "', как в TextView из вашего исходного файла dialog_preference_list.xml, ? – JaKXz

+0

Потрясающий ответ! Спасибо, мусликрик. – Tiago

ответ

4

Я думаю, что проблема связана с тем, как работает ListPreference. ListPreference использует Builder.setSingleChoiceItems() для создания строк с помощью RadioButtons, и он имеет предпочтение над настраиваемым макетом, который вы пытаетесь добавить (в вашем случае TextView и ListView внутри LinearLayout. Вместо этого решение расширяет DialogPreference. Here is .. ссылка на GitHub, где я создал пользовательский DialogPreference, который делает то, что вам нужно, я не закодированы логики RadioButton

+0

это вам помогло? – Emmanuel

+0

Спасибо за ваши предложения. Действительно, проблема исходит от Builder.setSingleChoiceItems(). Я исправил его, расширив ListPreference и переопределив onCreateDialogView(), чтобы не использовать построитель диалогового окна. Я положу код в отдельный ответ. – muslidrikk

+0

Хорошо, что я смог помочь. Помогла ли вам ссылка GitHub? – Emmanuel

2

Я предполагаю, что это проблема тематизации. Попробуйте изменить тему своего диалога внутри конструктора, сделайте что-то вроде setStyle(STYLE_NO_TITLE, R.style.AppTheme). Тема вашего базового приложения с типом no_title.

Если это не проблема, это может быть связано с самим классом ListPreference.Это может быть переопределение вашего макета для согласованности при просмотре представлений предпочтений. Тем не менее, я раньше не использовал ListPreference, поэтому его просто догадаться.

Можете ли вы воспроизвести тот же результат, играя с темами в XML-графическом представлении макета?

+0

Спасибо за ваше предложение. Однако после игры с темами это оказалось не проблема. – muslidrikk

1

Другой вариант, вы можете попробовать это добавить TextView в качестве заголовка к ListView, как это:

TextView textView = new TextView(getActivity()); 
ListView listView = new ListView(getActivity()); 
listView.addHeaderView(textView); 

addHeaderView принимает View так что вы теоретически что-нибудь вы хотите быть заголовком, но я использовал только TextView.

+0

Спасибо, но addHeaderView(), похоже, не работает при использовании в ListView ListPreference ... – muslidrikk

0

Ссылка выше не работает. В этом решении идея переопределяет ListPreference и раздувает ваш собственный список, с данными, определенными в ListPreference.

@Override 
protected View onCreateDialogView() { 

    LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    ListView lv = new ListView(getContext()); 

    // Inflate the view into the header only if a message was set 
    if (getDialogMessage() != null && ! getDialogMessage().equals("")) { 

     TextView header = (TextView) inflater.inflate(R.layout.dialog_preference_list_header, null); 
     header.setText(getDialogMessage()); 
     lv.addHeaderView(header, null, false); 

    } 

    // Create a new adapter and a list view and feed it with the ListPreference entries 
    ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(getContext(), 
      R.layout.custom_dialog_single_choice_list_adapter, getEntries()); 

    lv.setAdapter(adapter); 
    lv.setClickable(true); 
    lv.setEnabled(true); 
    lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 
    lv.setItemChecked(getValueIndex() + 1, true); 
    lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { 

     @Override 
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 
      setValueIndex(position - 1); 
      getDialog().dismiss(); 
     } 
    }); 
    return lv; 
} 

Еще одна важная вещь - вызвать onPrepareDialogBuilder и не называть супер в нем. Это позволит избежать, чтобы список отображался дважды.

@Override 
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { 
    // Not calling super, to avoid having 2 listviews 

    // Set the positive button as null 
    builder.setPositiveButton(null, null); 
} 

private int getValueIndex() { 
    return findIndexOfValue(getValue()); 
} 

Где dialog_preference_list_header в моем случае только TestView, но это может быть более сложным, вид и custom_dialog_single_choice_list_adapter может быть что-то вроде этого:

<?xml version="1.0" encoding="utf-8"?> 
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@android:id/text1" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:checkMark="?android:attr/listChoiceIndicatorSingle" 
    android:ellipsize="marquee" 
    android:gravity="center_vertical" 
    android:minHeight="?android:attr/listPreferredItemHeight" 
    android:paddingBottom="2dip" 
    android:paddingLeft="10dip" 
    android:paddingRight="10dip" 
    android:paddingTop="2dip" 
    android:textAppearance="?android:attr/textAppearanceMedium" />