繁体   English   中英

在 Android MultiSelectListPreference 中至少选择一项

[英]Have at least one item selected in Android MultiSelectListPreference

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

到目前为止,我通过使用超类强制读取那里的私有变量来编写我自己的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);
    }
}

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

但总结一下我所做的:我创建了自己的 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所有那些准备好的函数,比如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>.");
            }
        }
    }
}

一个非常简单的解决方案是设置一个 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;
            }
        });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM