пользовательская строка в listPreference?

Я пытаюсь создать ListPreference но как-то отключить один из элементов. Вроде как серый или что-то в этом роде и не имеет возможности выбрать его. Это будет предстоящая функция, и я хочу, чтобы она была в списке просто не выбирается.

Я создал пользовательский ListPreference class и в этом классе пользовательский адаптер, надеясь использовать адаптер для создания того, что я хочу.

код работает, и он устанавливает адаптер, но ни одна из функций адаптера не вызывается. Я точки останова в методах, такие как getCount() но их никогда не называют.

вот мой код. Пользовательский ListPreference взят изhttp://blog.350nice.com/wp/archives/240

import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.preference.ListPreference;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.app.AlertDialog.Builder;

public class CustomListPreference extends ListPreference {

    private boolean[] mClickedDialogEntryIndices;
    CustomListPreferenceAdapter customListPreferenceAdapter = null;
    Context mContext;

    public CustomListPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        mClickedDialogEntryIndices = new boolean[getEntries().length];
    }

    @Override
    protected void onPrepareDialogBuilder(Builder builder) {
        CharSequence[] entries = getEntries();
        CharSequence[] entryValues = getEntryValues();
        if (entries == null || entryValues == null
                || entries.length != entryValues.length) {
            throw new IllegalStateException(
                    "ListPreference requires an entries array "
                    +"and an entryValues array which are both the same length");
        }
        builder.setMultiChoiceItems(entries, mClickedDialogEntryIndices,
                new DialogInterface.OnMultiChoiceClickListener() {

                    public void onClick(DialogInterface dialog, int which,
                            boolean val) {
                        mClickedDialogEntryIndices[which] = val;
                    }
                });
        // setting my custom list adapter
        customListPreferenceAdapter = new CustomListPreferenceAdapter(mContext);
        builder.setAdapter(customListPreferenceAdapter, null);
    }

    private class CustomListPreferenceAdapter extends BaseAdapter {

        public CustomListPreferenceAdapter(Context context) {}

        public int getCount() {
            return 1;
        }

        public Object getItem(int position) {
            return position;
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            convertView.setBackgroundColor(Color.BLUE);
            return convertView;
        }
    }
}

9 ответов


хорошо, я получил это на работу, в основном. Мне пришлось использовать пользовательский класс, который расширяет ListPreference. Тогда внутри этого мне пришлось создать пользовательский класс адаптера, как и для ListView и установите его в строитель, используя builder.setAdapter(). Мне также пришлось определить слушателей для обоих RadioButtons и ListView строки, которые обрабатывали снятие флажка RadioButtons и такие. Единственные проблемы, которые у меня все еще есть, - это мой обычай ListPreference имеет как OK, так и кнопку отмены, где ListPreference есть только кнопка отмены. Я не знаю, как удалить кнопку OK. Кроме того, я не могу получить строки, чтобы выделить, когда я нажимаю на них, как они делают в обычном ListPreference.

код java для пользовательского ListPreference класса. Обязательно имейте в виду такие вещи, как имя вашего пакета, имя предпочтения (ключ), ваши записи и значения для ListPreference, и имена ваших элементов xml.

package your.package.here;

import java.util.ArrayList;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.preference.ListPreference;
import android.preference.PreferenceManager;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CompoundButton;
import android.widget.RadioButton;
import android.widget.TextView;
import android.app.Dialog;
import android.app.AlertDialog.Builder;

public class CustomListPreference extends ListPreference
{   
    CustomListPreferenceAdapter customListPreferenceAdapter = null;
    Context mContext;
    private LayoutInflater mInflater;
    CharSequence[] entries;
    CharSequence[] entryValues;
    ArrayList<RadioButton> rButtonList;
    SharedPreferences prefs;
    SharedPreferences.Editor editor;

    public CustomListPreference(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        mContext = context;
        mInflater = LayoutInflater.from(context);
        rButtonList = new ArrayList<RadioButton>();
        prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
        editor = prefs.edit();
    }

    @Override
    protected void onPrepareDialogBuilder(Builder builder)
    {
        entries = getEntries();
        entryValues = getEntryValues();

        if (entries == null || entryValues == null || entries.length != entryValues.length )
        {
            throw new IllegalStateException(
                    "ListPreference requires an entries array and an entryValues array which are both the same length");
        }

        customListPreferenceAdapter = new CustomListPreferenceAdapter(mContext);

        builder.setAdapter(customListPreferenceAdapter, new DialogInterface.OnClickListener()
        {
            public void onClick(DialogInterface dialog, int which)
            {

            }
        });
    }

    private class CustomListPreferenceAdapter extends BaseAdapter
    {        
        public CustomListPreferenceAdapter(Context context)
        {

        }

        public int getCount()
        {
            return entries.length;
        }

        public Object getItem(int position)
        {
            return position;
        }

        public long getItemId(int position)
        {
            return position;
        }

        public View getView(final int position, View convertView, ViewGroup parent)
        {  
            View row = convertView;
            CustomHolder holder = null;

            if(row == null)
            {                                                                   
                row = mInflater.inflate(R.layout.custom_list_preference_row, parent, false);
                holder = new CustomHolder(row, position);
                row.setTag(holder);

                // do whatever you need here, for me I wanted the last item to be greyed out and unclickable
                if(position != 3)
                {
                    row.setClickable(true);
                    row.setOnClickListener(new View.OnClickListener()
                    {
                        public void onClick(View v)
                        {
                            for(RadioButton rb : rButtonList)
                            {
                                if(rb.getId() != position)
                                    rb.setChecked(false);
                            }

                            int index = position;
                            int value = Integer.valueOf((String) entryValues[index]);
                            editor.putInt("yourPref", value);

                            Dialog mDialog = getDialog();
                            mDialog.dismiss();
                        }
                    });
                }
            }

            return row;
        }

        class CustomHolder
        {
            private TextView text = null;
            private RadioButton rButton = null;

            CustomHolder(View row, int position)
            {    
                text = (TextView)row.findViewById(R.id.custom_list_view_row_text_view);
                text.setText(entries[position]);
                rButton = (RadioButton)row.findViewById(R.id.custom_list_view_row_radio_button);
                rButton.setId(position);

                // again do whatever you need to, for me I wanted this item to be greyed out and unclickable
                if(position == 3)
                {
                    text.setTextColor(Color.LTGRAY);
                    rButton.setClickable(false);
                }

                // also need to do something to check your preference and set the right button as checked

                rButtonList.add(rButton);
                rButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
                {
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
                    {
                        if(isChecked)
                        {
                            for(RadioButton rb : rButtonList)
                            {
                                if(rb != buttonView)
                                    rb.setChecked(false);
                            }

                            int index = buttonView.getId();
                            int value = Integer.valueOf((String) entryValues[index]);
                            editor.putInt("yourPref", value);

                            Dialog mDialog = getDialog();
                            mDialog.dismiss();
                        }
                    }
                });
            }
        }
    }
}

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

<?xml version="1.0" encoding="utf-8"?>

<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android">

        <PreferenceCategory
                android:title="Your Title">

                <your.package.here.CustomListPreference
                    android:key="yourPref"
                    android:title="Your Title"
                    android:dialogTitle="Your Title"
                    android:summary="Your Summary"
                    android:defaultValue="1"
                    android:entries="@array/yourArray"
                    android:entryValues="@array/yourValues"/>

        </PreferenceCategory>
</PreferenceScreen>

мой xml для строки представления списка диалогового окна. В методе getView обязательно используйте имя этого xml-файла в строке, которая раздувает это.

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:paddingBottom="8dip"
    android:paddingTop="8dip"
    android:paddingLeft="10dip"
    android:paddingRight="10dip">

    <TableLayout
        android:id="@+id/custom_list_view_row_table_layout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:stretchColumns="0">

        <TableRow
            android:id="@+id/custom_list_view_row_table_row"
            android:gravity="center_vertical"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/custom_list_view_row_text_view"
                android:textSize="22sp"
                android:textColor="#000000"  
                android:gravity="center_vertical"
                android:layout_width="160dip" 
                android:layout_height="40dip" />

            <RadioButton
                android:checked="false"
                android:id="@+id/custom_list_view_row_radio_button"/>
        </TableRow>
    </TableLayout>

</LinearLayout>

наконец, под res / values вот мой массив.xml, содержащий имена и значения записей для ListPreference. Снова, укоротил Мой для простоты.

<?xml version="1.0" encoding="utf-8"?>
<resources> 
    <string-array name="yourArray">
        <item>Item 1</item>
        <item>Item 2</item>
        <item>Item 3</item>
        <item>Item 4</item>
    </string-array>

    <string-array name="yourValues">
        <item>0</item>
        <item>1</item>
        <item>2</item>
        <item>3</item>
    </string-array>
</resources>

Это сработало хорошо для меня. Я использовал подход адаптера, который вводит обернутый адаптер в представление.

вот базовый класс обернутого адаптера:

import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.WrapperListAdapter;

class ListPrefWrapperAdapter implements WrapperListAdapter {
    private ListAdapter mOrigAdapter;

    public ListPrefWrapperAdapter(ListAdapter origAdapter) {
        mOrigAdapter = origAdapter;
    }

    @Override
    public ListAdapter getWrappedAdapter() {
        return mOrigAdapter;
    }

    @Override
    public boolean areAllItemsEnabled() {
        return getWrappedAdapter().areAllItemsEnabled();
    }

    @Override
    public boolean isEnabled(int position) {
        return getWrappedAdapter().isEnabled(position);
    }

    @Override
    public void registerDataSetObserver(DataSetObserver observer) {
        getWrappedAdapter().registerDataSetObserver(observer);
    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
        getWrappedAdapter().unregisterDataSetObserver(observer);
    }

    @Override
    public int getCount() {
        return getWrappedAdapter().getCount();
    }

    @Override
    public Object getItem(int position) {
        return getWrappedAdapter().getItem(position);
    }

    @Override
    public long getItemId(int position) {
        return getWrappedAdapter().getItemId(position);
    }

    @Override
    public boolean hasStableIds() {
        return getWrappedAdapter().hasStableIds();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return getWrappedAdapter().getView(position, convertView, parent);
    }

    @Override
    public int getItemViewType(int position) {
        return getWrappedAdapter().getItemViewType(position);
    }

    @Override
    public int getViewTypeCount() {
        return getWrappedAdapter().getViewTypeCount();
    }

    @Override
    public boolean isEmpty() {
        return getWrappedAdapter().isEmpty();
    }
}

вот базовый класс CustomListPreference, который использует ListPrefWrapperAdapter:

import android.app.AlertDialog;
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
import android.widget.ListAdapter;
import android.widget.ListView;

public class CustomListPreference extends ListPreference {
    public CustomListPreference(Context context) {
        super(context);
    }

    public CustomListPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void showDialog(Bundle state) {
        super.showDialog(state);
        AlertDialog dialog = (AlertDialog) getDialog();
        ListView listView = dialog.getListView();
        ListAdapter adapter = listView.getAdapter();
        final ListPrefWrapperAdapter fontTypeAdapter = createWrapperAdapter(adapter);

        // Adjust the selection because resetting the adapter loses the selection.
        int selectedPosition = findIndexOfValue(getValue());
        listView.setAdapter(fontTypeAdapter);
        if (selectedPosition != -1) {
            listView.setItemChecked(selectedPosition, true);
            listView.setSelection(selectedPosition);
        }
    }

    protected ListPrefWrapperAdapter createWrapperAdapter(ListAdapter origAdapter) {
        return new ListPrefWrapperAdapter(origAdapter);
    }

}

наконец, вот производные классы, которые делают отключение и включение определенных строк:

import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckedTextView;
import android.widget.ListAdapter;

public class FontTypePreference extends CustomListPreference {

    public FontTypePreference(Context context) {
        super(context);
    }

    public FontTypePreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected ListPrefWrapperAdapter createWrapperAdapter(ListAdapter origAdapter) {
        return new Adapter(origAdapter);
    }

    private class Adapter extends ListPrefWrapperAdapter {
        private static final float TEXT_SIZE = 25.0f;
        private static final int STARTING_UPGRADE_REQUIRED_INDEX = 8;

        public Adapter(ListAdapter origAdapter) {
            super(origAdapter);
        }

        @Override
        public boolean areAllItemsEnabled() {
            return false;
        }

        @Override
        public boolean isEnabled(int position) {
            return position < STARTING_UPGRADE_REQUIRED_INDEX;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            CheckedTextView textView = (CheckedTextView) getWrappedAdapter()
                    .getView(position, convertView, parent);
            textView.setTextColor(position < STARTING_UPGRADE_REQUIRED_INDEX ?
                    Color.BLACK : Color.RED);
            return textView;
        }


    }

}

Я тестировал этот код только на SDK версии 15 и выше.


вероятно, придется добавить editor.commit(); после каждого editor.putInt(...)


функции getcount() возвращает неправильно.

public int getCount()
    {
        return entries.length;
    }

    public Object getItem(int position)
    {
        return null;
    }

    public long getItemId(int position)
    {
        return position;
    }

спасибо Бобу за этот ответ, и Vamsi за попытку исправить ошибку повторяющихся записей, но исправление Vamsi не сработало для меня. Я должен был сохранить массив представлений и вернуть его на позицию, если он уже был создан раньше. Итак, вот мой полный класс CustomListPreferenceAdapter. Он также содержит исправление для проверки выбранного значения предпочтения.

private class CustomListPreferenceAdapter extends BaseAdapter
{
    View[] Views;

    public CustomListPreferenceAdapter(Context context)
    {
        Views = new View[entries.length];
    }

    public int getCount()
    {
        return entries.length;
    }

    public Object getItem(int position)
    {
        return null;
    }

    public long getItemId(int position)
    {
        return position;
    }

    public View getView(final int position, View convertView, ViewGroup parent)
    {  
        View row = Views[position];
        CustomHolder holder = null;

        if(row == null)
        {                                                             
            row = mInflater.inflate(R.layout.listrow, parent, false);
            holder = new CustomHolder(row, position);
            row.setTag(holder);
            Views[position] = row;
        }

        return row;
    }

    class CustomHolder
    {
        private TextView text = null;
        private RadioButton rButton = null;

        CustomHolder(View row, int position)
        {    
            text = (TextView)row.findViewById(R.id.custom_list_view_row_text_view);
            text.setText(entries[position]);

            rButton = (RadioButton)row.findViewById(R.id.custom_list_view_row_radio_button);
            rButton.setId(position);

            if(getPersistedString("").compareTo((String)entryValues[position])==0)
                rButton.setChecked(true);

            rButtonList.add(rButton);
        }
    }
}

Я думаю, вы можете достичь именно того, что хотите, установив флаг enabled ListPreference в false:

ListPreference lp = (ListPreference) findPreference("YOUR_KEY");
lp.setEnabled(false);

это серое описание и делает его не выбираемым.


изменил код, как показано ниже -

if(row == null) {                                                                   
    row = mInflater.inflate(R.layout.custom_list_preference_row, parent, false);
    holder = new CustomHolder(row, position);
} else {
    holder = row.getTag()
}
// update the holder with new Text/Drawables etc.,
row.setTag(holder);
return row;

PS-NidhiGondhia запросил измененный код, так как в комментариях это не подходит, обновляя измененный код здесь.


вы можете сделать это более легко.

действия:

  1. Расширить ListPreference

    public class CustomListPreference extends ListPreference
    {
        Context mContext;
    
        public CustomListPreference(Context context, AttributeSet attrs)
        {
            super(context, attrs);
            mContext = context;
        }
    }
    
  2. переопределить onPrepareDialogBuilder и заменить mBuilder в DialogPreference на ProxyBuilder:

    @Override
    protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder builder){
        super.onPrepareDialogBuilder(builder);
    
        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.FROYO) {
            return;
        }
    
        // Inject Builder Proxy for intercepting of getView.
        try {
            Field privateBuilderField =
                DialogPreference.class.getDeclaredField("mBuilder");
            privateBuilderField.setAccessible(true);
    
            privateBuilderField.set(this, new ProxyBuilder(mContext, (android.app.AlertDialog.Builder)privateBuilderField.get(this)));
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    
  3. обрабатывать getView в ProxyBuilder - >AlertDialog - >onShow - >getListView - >адаптер

    private class ProxyBuilder extends android.app.AlertDialog.Builder{
    
        android.app.AlertDialog.Builder mBuilder;
    
        private ProxyBuilder(Context context, AlertDialog.Builder builder) {
            super(context);
            mBuilder = builder;
        }
    
    
        @TargetApi(Build.VERSION_CODES.FROYO)
        @Override
        public AlertDialog create() {
            AlertDialog alertDialog = mBuilder.create();
            alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
                @Override
                public void onShow(DialogInterface dialog) {
                    ListView listView = ((AlertDialog)dialog).getListView();
                    final ListAdapter originalAdapter = listView.getAdapter();
    
                    listView.setAdapter(new ListAdapter(){
                        @Override
                        public int getCount() {
                            return originalAdapter.getCount();
                        }
    
                        @Override
                        public Object getItem(int id) {
                            return originalAdapter.getItem(id);
                        }
    
                        @Override
                        public long getItemId(int id) {
                            return originalAdapter.getItemId(id);
                        }
    
                        @Override
                        public int getItemViewType(int id) {
                            return originalAdapter.getItemViewType(id);
                        }
    
                        @Override
                        public View getView(int position, View convertView, ViewGroup parent) {
                            View view = originalAdapter.getView(position, convertView, parent);
                            TextView textView = (TextView)view;
                            textView.setTextColor(Color.RED);
                            return view;
                        }
    
                        @Override
                        public int getViewTypeCount() {
                            return originalAdapter.getViewTypeCount();
                        }
    
                        @Override
                        public boolean hasStableIds() {
                            return originalAdapter.hasStableIds();
                        }
    
                        @Override
                        public boolean isEmpty() {
                            return originalAdapter.isEmpty();
                        }
    
                        @Override
                        public void registerDataSetObserver(DataSetObserver observer) {
                            originalAdapter.registerDataSetObserver(observer);
    
                        }
    
                        @Override
                        public void unregisterDataSetObserver(DataSetObserver observer) {
                            originalAdapter.unregisterDataSetObserver(observer);
    
                        }
    
                        @Override
                        public boolean areAllItemsEnabled() {
                            return originalAdapter.areAllItemsEnabled();
                        }
    
                        @Override
                        public boolean isEnabled(int position) {
                            return originalAdapter.isEnabled(position);
                        }
    
                    });
                }
            });
            return alertDialog;
        }
    }
    

это сработало для меня, но это не сработало хорошо, если список не подходит на экране (и требует прокрутки). Мне потребовалось много времени, чтобы найти решение (но я, наконец, это сделал).

первая проблема: Как описано здесь: getView вызывается с неправильным положением при прокрутке быстро вы получите непредсказуемое поведение при использовании прослушивателя onclick в:

public View getView(final int position, View convertView, ViewGroup parent)

в моем случае событие onClick будет сохранено в памяти и будет выполняется, когда пользователь пытается прокрутить (немного).

и теперь решение: Поместите прослушиватель onClick в основной класс (по крайней мере, это сработало для меня):

public class CustomListPreference extends ListPreference {

// Other code (see above)
@Override
protected void onPrepareDialogBuilder(Builder builder)
{
    builder.setPositiveButton(null, null);

    entries = getEntries();
    entryValues = getEntryValues();

    if (entries == null || entryValues == null || entries.length != entryValues.length )
    {
        throw new IllegalStateException("ListPreference requires an entries array and an entryValues array which are both the same length");
    }

    customListPreferenceAdapter = new CustomListPreferenceAdapter(mContext);

    builder.setAdapter(customListPreferenceAdapter, new DialogInterface.OnClickListener()
    {
        public void onClick(DialogInterface dialog, int position)
        {
            // Code here, using position to indicate the row that was clicked...
            dialog.dismiss();
        }
    });

}

тратить waaaay слишком много времени на это, поэтому надеюсь, что это поможет кому-то:)

в целом, все еще очень доволен этим примером кода! (используйте его как выбор цвета).

P. S. Если вам понравилась эта должность, пожалуйста, проголосуйте полезно. Thx!