Domanda

Sto cercando di creare un ListPreference ma in qualche modo disabilitazione delle voci. Un po 'come grigio fuori o qualcosa e non ha la possibilità di sceglierlo. Sarà una caratteristica imminente e voglio che sia nella lista semplicemente non selezionabile.

Ho creato una classe ListPreference personalizzato e in quella classe di un adattatore personalizzato, nella speranza di utilizzare l'adattatore per creare ciò che voglio.

Il codice funziona, e pone l'adattatore, ma nessuna delle funzioni di adattamento vengono chiamati. Ho impostato i punti di interruzione sui metodi, come ad esempio getCount() ma non ottengono mai chiamato.

Ecco il mio codice. Personalizzato ListPreference preso da 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;
        }
    }
}
È stato utile?

Soluzione

OK ho ottenuto questo al lavoro, per lo più. Ho dovuto usare una classe definita personalizzato che si estende ListPreference. Poi all'interno di che ho dovuto creare una classe adattatore personalizzato, proprio come si farebbe per un ListView e impostarlo al costruttore utilizzando builder.setAdapter(). Ho dovuto anche per definire gli ascoltatori sia per il RadioButtons e le righe ListView che ha gestito deselezionando del RadioButtons e così via. Gli unici problemi che ho ancora sono, il mio ListPreference personalizzato ha sia un OK e un pulsante Annulla in cui un ListPreference ha solo il pulsante Annulla. Non so come rimuovere il pulsante OK. Inoltre, non riesco a ottenere le righe a punto culminante quando clicco su di loro come fanno in un ListPreference regolare.

Il codice Java per la classe ListPreference personalizzato. Essere sicuri di mente cose come il vostro nome del pacchetto, il nome preferenza (chiave), le voci ei valori per il ListPreference, ed i nomi dei tuoi oggetti 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();
                        }
                    }
                });
            }
        }
    }
}

L'XML per la mia PreferenceActivity. Questo non è il mio xml piena, tirò fuori tutti i miei altri elementi preferenza per la semplicità. Anche in questo caso, essere sicuri di mente il nome del pacchetto, la classe ListPreference personalizzato deve essere riferimento il nome del pacchetto. mente anche i nomi di preferenza ei nomi di array che contengono le voci ei valori.

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

Il mio XML per la riga di visualizzazione elenco della finestra di dialogo. Nel metodo GetView assicurarsi di utilizzare il nome di questo file XML nella linea che si gonfia questo.

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

Infine, sotto res / valori ecco la mia array.xml che contiene i nomi di ingresso e valori per la ListPreference. Ancora una volta, abbreviato miniera per semplicità.

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

Altri suggerimenti

Questo ha funzionato bene per me. Ho usato un approccio adattatore che inietta un adattatore avvolto nella vista.

Questa è la base avvolta classe di adattatori:

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

Questa è la classe di base CustomListPreference che utilizza il 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);
    }

}

Infine, ecco le classi derivate che fanno la disattivazione e consentendo di righe specifiche:

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


    }

}

Ho testato solo su questo codice SDK versione 15 e superiori.

Probabilmente dovrà aggiungere editor.commit(); dopo ogni editor.putInt(...)

ritorna funzione getcount() è sbagliato.

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

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

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

Grazie Bob per la sua risposta, e Vamsi per cercare di correggere le voci duplicate bug, ma Vamsi di correzione non ha funzionato per me. Ho dovuto tenere una serie di punti di vista e riportarlo sulla posizione se fosse già stato creato prima. Così qui è la mia classe piena CustomListPreferenceAdapter. Esso contiene anche la correzione per controllare il valore preferenza selezionata.

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

Credo che si può ottenere esattamente quello che vuoi impostando il flag abilitato del ListPreference su false:

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

Questa grigi fuori la descrizione e lo rende non selezionabile.

modificato il codice come qui sotto -

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 richiesti per codice modificato, come nei commenti questo non può essere in forma, l'aggiornamento del codice modificato qui

Si può fare più facilmente.

Passi:

  1. Estendere ListPreference

    public class CustomListPreference extends ListPreference
    {
        Context mContext;
    
        public CustomListPreference(Context context, AttributeSet attrs)
        {
            super(context, attrs);
            mContext = context;
        }
    }
    
  2. Override onPrepareDialogBuilder e sostituire mBuilder in DialogPreference con 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. Maniglia GetView in ProxyBuilder-> AlertDialog-> onShow-> getListView-> Adapter

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

Questo ha funzionato per me, ma non ha funzionato bene, se l'elenco non si adatta allo schermo (e richiede lo scorrimento). Mi c'è voluto una vita per trovare la soluzione (ma alla fine ho fatto io).

In primo luogo il problema: Come descritto qui: GetView chiamato con la posizione sbagliata durante lo scorrimento veloce si otterrà un comportamento imprevedibile quando si utilizza un ascoltatore onclick in:

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

Nel mio caso, l'evento onClick sarebbe memorizzato e sarà eseguito quando l'utente ha tentato di scorrimento (un po ').

E ora la soluzione: Mettere l'ascoltatore onClick nella classe principale (almeno questo ha funzionato per me):

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

}

Trascorrere troppo sopravvalutato troppo tempo su questo, quindi spero che aiutare qualcuno:)

Tutto sommato, comunque molto contento di questo esempio di codice! (Usarlo come un selettore di colori).

P.S. Se ti piace questo post, si prega di votare utile. Thx!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top