Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does ListView stays above TextView in ListPreference dialog?

I need to create a custom ListPreference dialog so that I can add some header text (a TextView) above the List (ListView). I've created MyListPreference class that extends ListPreference and overrides onCreateDialogView():

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

My XML layout dialog_preference_list.xml contains:

<?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>

Problem: The TextView is displayed below the ListView instead of above. I need the TextView to be above. I've tried both with LinearLayout and RelativeLayout (using "below" or "above" attributes) with no success: I can't find a way to put the TextView above the ListView... The layout is pretty simple and I cannot see why the list stays above... Also, note that the problem occurs on both a real device (Nexus 4, Android 4.2.2) and the emulator. However, when looking at the layout rendered in Eclipse's graphical layout, the layout is correct! See both attached pictures.

Any idea on how to solve this?

Layout rendered on the device (incorrect):

Layout rendered on the device (incorrect)

Layout rendered on Eclipse (correct):

Layout rendered on Eclipse (correct)

Edit with solution 10.07.2013

As suggested by the accepted answer, the problem comes from the use of builder.setSingleChoiceItems() in ListPreference's onPrepareDialogBuilder(). I've fixed it by extending ListPreference and overriding onCreateDialogView() to build the Dialog without the builder so that I can create a custom View showing the header text above the list items.

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>
like image 829
gpo Avatar asked Jun 25 '13 13:06

gpo


1 Answers

I think the problem is with the way ListPreference works. ListPreference uses Builder.setSingleChoiceItems() to create the rows with the RadioButtons, and it has preference over the custom layout you are trying to add (in your case a TextView and a ListView inside a LinearLayout. The solution is extending DialogPreference instead. Here is a link to a GitHub where I created a custom DialogPreference that does what you need. I haven't coded the RadioButton logic.

like image 172
Emmanuel Avatar answered Sep 28 '22 05:09

Emmanuel