ListPreference
を作成しようとしていますが、どういうわけかアイテムの1つを無効にします。灰色か何かのようなもので、それを選択する能力がありません。これは今後の機能であり、選択できないようにリストに含めたいと思います。
カスタムListPreference
クラスを作成し、そのクラスにカスタムアダプターを作成しました。アダプターを使用して、必要なものを作成したいと考えています。
コードは機能し、アダプターを設定しますが、アダプター関数は呼び出されません。 getCount()
などのメソッドにブレークポイントを設定しましたが、呼び出されません。
これが私のコードです。 http://blog.350Nice.com/wp/archives/24 から取得したカスタムListPreference
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;
}
}
}
OK私はこれをほとんど機能させました。 ListPreference
を拡張するカスタム定義のクラスを使用する必要がありました。次に、その中でListView
の場合と同じようにカスタムアダプタクラスを作成し、builder.setAdapter()
を使用してビルダーに設定する必要がありました。また、RadioButtons
などのチェック解除を処理するListView
行とRadioButtons
行の両方のリスナーを定義する必要がありました。私がまだ抱えている唯一の問題は、カスタムListPreference
には[OK]ボタンと[キャンセル]ボタンの両方があり、ListPreference
にはキャンセルボタンしかないということです。 OKボタンを外す方法がわかりません。また、通常のListPreference
のように、行をクリックしてもハイライト表示されません。
カスタムListPreference
クラスのJavaコード。パッケージ名、設定名(キー)、エントリ、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();
}
}
});
}
}
}
}
私のPreferenceActivity
のxml。これは私の完全なxmlではありません。簡単にするために、他のすべての設定項目を削除しました。繰り返しになりますが、パッケージ名に注意してください。カスタム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の下に、ListPreference
のエントリ名と値を含むarray.xmlがあります。繰り返しますが、簡単にするために鉱山を短縮しました。
<?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();
}
}
ListPrefWrapperAdapterを使用するCustomListPreference基本クラスは次のとおりです。
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(...)
の後
function 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);
}
}
}
以下のようにコードを変更しました-
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は変更されたコードを要求しました。コメントのように、これは適合できず、ここで変更されたコードを更新します。
あなたはそれをより簡単に行うことができます。
手順:
ListPreferenceを拡張する
public class CustomListPreference extends ListPreference
{
Context mContext;
public CustomListPreference(Context context, AttributeSet attrs)
{
super(context, attrs);
mContext = context;
}
}
OnPrepareDialogBuilderをオーバーライドし、DialogPreferenceのmBuilderを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();
}
}
ProxyBuilder-> AlertDialog-> onShow-> getListView-> AdapterでgetViewを処理します
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;
}
}
ListPreferenceのenabledフラグをfalseに設定することで、まさにあなたが望むことを達成できると思います。
ListPreference lp = (ListPreference) findPreference("YOUR_KEY");
lp.setEnabled(false);
これにより、説明がグレー表示され、選択できなくなります。
これは私にとってはうまくいきましたが、リストが画面に収まらない場合(そしてスクロールが必要な場合)はうまくいきませんでした。解決策を見つけるのにかなりの時間がかかりました(しかし、私はついにそうしました)。
最初の問題:ここで説明されているように: 高速スクロール時に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();
}
});
}
これにあまりにも多くの時間を費やすので、誰かを助けることを願っています:)
全体として、このコード例にはまだ本当に満足しています! (カラーピッカーとして使用してください)。
P.S.この投稿が気に入ったら、投票してください。どうも!