【问题标题】:Have at least one item selected in Android MultiSelectListPreference在 Android MultiSelectListPreference 中至少选择了一项
【发布时间】:2016-07-03 01:54:20
【问题描述】:

我现在已经通过互联网搜索了几个小时,但到目前为止没有发现任何实质性内容。我想做的是一个多选偏好视图,如果它不再是单独的,它会禁用最后一个项目并重新启用它。

到目前为止,我通过超级类强制读取那里的私有变量来编写我自己的onPrepareDialogBuilder(AlertDialog.Builder builder)。它正在配置自己的OnMultiChoiceClickListener,在只剩下一个项目的那一刻跳进去。这里的问题是,我使用不好的做法强制读取私有变量,并且到目前为止我不知道如何获取复选框项目以及如何禁用它。但我认为更深入地研究 Android SDK 将解决这个问题。

最后,如果没有任何效果,则通过覆盖OnPreferenceChangeListener 来解决问题,以在用户选择的项目少于一项时显示敬酒。但用户友好性是一个很高的价值,需要获得,而且通常并不容易。

谢谢。

import android.content.Context;
import android.preference.MultiSelectListPreference;
import android.util.AttributeSet;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import georg.com.flironetest_01.Variables.Units;

/**
 * Created by Georg on 16/03/16.
 */
public class UnitMultipleSelectorPreference extends MultiSelectListPreference {

    public UnitMultipleSelectorPreference(Context context, AttributeSet attrs) {
        super(context, attrs);

        List<CharSequence> humanU = new ArrayList<>();
        List<CharSequence> machineU = new ArrayList<>();

        Units[] all = Units.values(); // Units is a enum with a rewriten to string statement.
        for (Units elem : all) {
            humanU.add(elem.toString());
            machineU.add(elem.name());
        }

        setEntries(humanU.toArray(new CharSequence[humanU.size()]));
        setEntryValues(machineU.toArray(new CharSequence[machineU.size()]));

        Set<String> mU = new HashSet<>();
        mU.add(Units.C.name());
        mU.add(Units.K.name());

        setDefaultValue(mU);
    }
}

【问题讨论】:

    标签: java android options multichoiceitems multiselectlistpreference


    【解决方案1】:

    好的。在“自我就是男人”的座右铭之后在这里回答我自己的问题:我最终编写了自己的偏好面板。下面是代码。如果有人喜欢查看它并给出一些时间如何使其更加稳定:请随意。

    但总结一下我所做的:我创建了自己的 ArrayAdapter。但是DialogPreference 不允许我创建自己的多重选择器。您需要更改最终的对话框片段以创建一个有效的多重选择器列表(参见此处:https://stackoverflow.com/a/17907379/5759814)。如果您使用 DialogPreferences,这不是一件容易的事。原因是这几行代码:

    /**
     * Shows the dialog associated with this Preference. This is normally initiated
     * automatically on clicking on the preference. Call this method if you need to
     * show the dialog on some other event.
     * 
     * @param state Optional instance state to restore on the dialog
     */
    protected void showDialog(Bundle state) {
        Context context = getContext();
    
        mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
    
        mBuilder = new AlertDialog.Builder(context)
            .setTitle(mDialogTitle)
            .setIcon(mDialogIcon)
            .setPositiveButton(mPositiveButtonText, this)
            .setNegativeButton(mNegativeButtonText, this);
    
        View contentView = onCreateDialogView();
        if (contentView != null) {
            onBindDialogView(contentView);
            mBuilder.setView(contentView);
        } else {
            mBuilder.setMessage(mDialogMessage);
        }
    
        onPrepareDialogBuilder(mBuilder);
    
        getPreferenceManager().registerOnActivityDestroyListener(this);
    
        // Create the dialog
        final Dialog dialog = mDialog = mBuilder.create();
        if (state != null) {
            dialog.onRestoreInstanceState(state);
        }
        if (needInputMethod()) {
            requestInputMethod(dialog);
        }
        dialog.setOnDismissListener(this);
        dialog.show();
    }
    

    如您所见,这里触发了一个使用onPrepareDialogBuilder 更改我的对话框构建器的方法,但之后似乎没有触发任何其他函数,这将允许我在创建对话框后直接更改它.更改onPrepareDialogBuilder 以便我可以在那里初始化所有内容的第二个想法并没有真正帮助,因为我最终会显示对话框窗口。这导致我决定创建我自己的 Preference 类。有了这个决定,我放弃了所有准备好的函数,如 onRestoreInstanceState 和 Co,但我现在有一个具有更持久流的应用程序,当我为我的热视图选择零单位时,它不会做任何愚蠢的事情。

    在未注释的代码下方。很抱歉,但我认为这对所有登陆这里的人来说已经足够简单了。

    import android.app.AlertDialog;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.content.SharedPreferences;
    import android.preference.Preference;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.View;
    import android.widget.AbsListView;
    import android.widget.AdapterView;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    import android.widget.Toast;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    import georg.com.flironetest_01.Variables.Units;
    
    /**
     * Created by Georg on 16/03/16.
     */
    public class UnitMultipleSelectorPreference extends Preference implements DialogInterface.OnClickListener, Preference.OnPreferenceClickListener {
    
        String[] human_entries = null;
        String[] machine_entries = null;
    
    
    
        public SharedPreferences prev;
    
        public UnitMultipleSelectorPreference(Context context, AttributeSet attrs) {
            super(context, attrs);
    
    
            prev = getSharedPreferences();
    
            List<String> humanU = new ArrayList<>();
            List<String> machineU = new ArrayList<>();
    
            Units[] all = Units.values();
            for (Units elem : all) {
                humanU.add(elem.toString());
                machineU.add(elem.name());
            }
    
            human_entries = humanU.toArray(new String[humanU.size()]);
            machine_entries = machineU.toArray(new String[machineU.size()]);
    
            Set<String> mU = new HashSet<>();
            mU.add(Units.C.name());
            mU.add(Units.K.name());
    
            setDefaultValue(mU);
    
            setOnPreferenceClickListener(this);
        }
    
        boolean[] selected = new boolean[0];
    
        protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
            if (prev == null)
                return;
    
            if (human_entries == null || machine_entries == null || human_entries.length != machine_entries.length ) {
                throw new IllegalStateException(
                        "ListPreference requires an entries array and an entryValues array which are both the same length");
            }
    
            selected = new boolean[human_entries.length];
            for (int i = 0; i < human_entries.length; i++)
                selected[i] = prefSet.contains(machine_entries[i]);
    
    
            String[] stringObj = new String[human_entries.length];
            int i = 0;
            for(CharSequence ch : human_entries)
                stringObj[i++] = ch.toString();
    
    
            builder.setAdapter(new MyAdapter(getContext(), android.R.layout.simple_list_item_multiple_choice, stringObj), new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                }
            });
    
            AlertDialog mDialog = builder.create();
            mDialog.getListView().setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE);
            mDialog.getListView().setItemsCanFocus(false);
            mDialog.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view,
                                        int position, long id) {
                    // Manage selected items here
    
                    ListView mParent = (ListView)parent;
    
    
                    if (mParent.getCheckedItemCount() >= 1)
                        selected[position] = mParent.isItemChecked(position);
                    if (mParent.getCheckedItemCount() == 0)
                        mParent.setItemChecked(position, true);
                }
            });
    
    
            mDialog.show();
    
    
    
            i = 0;
            for (boolean select : selected)
                mDialog.getListView().setItemChecked(i++, select);
        }
    
        @Override
        public boolean onPreferenceClick(Preference preference) {
            AlertDialog.Builder mBuilder = new AlertDialog.Builder(getContext());
            mBuilder.setTitle(getTitle())
                    .setPositiveButton(android.R.string.ok, this)
                    .setNegativeButton(android.R.string.cancel, this);
            onPrepareDialogBuilder(mBuilder);
    
            return true;
        }
    
    
    
        @Override
        public void onClick(DialogInterface dialog, int which) {
            Toast.makeText(getContext(), "W:"+which + " | " + Arrays.toString(selected), Toast.LENGTH_SHORT).show();
    
            switch (which) {
                case -1:
                    if (isPersistent()) {
                        prefSet = new HashSet<>();
    
                        for (int i = 0; i < selected.length; i++) {
                            if (selected[i])
                                prefSet.add(machine_entries[i]);
                        }
                        getEditor().putStringSet(getKey(), prefSet).apply();
    
                        Toast.makeText(getContext(), "W:"+which + " | " + getSharedPreferences().getStringSet(getKey(),null).toString(), Toast.LENGTH_SHORT).show();
    
                    }
                    return;
            }
        }
    
    
    
        public class MyAdapter extends ArrayAdapter<String> {
    
            public MyAdapter(Context context, int textViewResourceId, String[] objects) {
                super(context, textViewResourceId, objects);
            }
    
            @Override
            public boolean isEnabled(int n) {
                return true;
            }
        }
    
        Set<String> prefSet;
    
        @Override
        protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
            super.onSetInitialValue(restorePersistedValue, defaultValue);
            prev = getSharedPreferences();
    
            if(restorePersistedValue) {
                prefSet = prev.getStringSet(getKey(), new HashSet<String>());
            } else {
                try {
                    prefSet = (Set<String>)defaultValue;
                    if(isPersistent())
                        getEditor().putStringSet(getKey(), prefSet);
                } catch (ClassCastException e) {
                    Log.e("ERROR_CAST", "Error casting the default value to Set<String>.");
                }
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      一个非常简单的解决方案是设置一个 setOnPreferenceChangeListener,如果新值为空,则返回 false。
      所有代码都放在 onCreatePreferences 中。

      MultiSelectListPreference infoPreference = findPreference("information");
      
      infoPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
                  @Override
                  public boolean onPreferenceChange(Preference preference, Object newValue) {
                      if (size(newValue) == 0){
                          return false;
                      }
                      return true;
                  }
              });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-15
        • 1970-01-01
        • 1970-01-01
        • 2014-12-23
        • 2018-05-11
        • 1970-01-01
        相关资源
        最近更新 更多