简体   繁体   中英

Implement SearchView in a multichoice dialog- Android

I implemented a multi choice dialog to let the user pick multiple items. I want to implement a searchview within the dialog. But, the problem is: since multi choice dialog deals with arrays, I am unable to modify the list view based on the search results. I have used this implementation in several activities in the project. I want to include search views in all those multi choice dialogs. So, I am trying to fix it this way(within the multichoice dialog) rather than opting for a different approach ie, setting a layout which contains a search view and a custom listview to a dialog. This code throws ArrayIndexOutOfBoundsException since, the number of items in the checkedColours and buildingNames arrays differ from the initial length when I attempt to modify the listview. Can we make the search view working this way? If this approach doesn't seem to work, please suggest a few tips to follow the other approach (using a layout with searchview and custom listview in a dialog). Any help regarding this is appreciated. Thank you in advance.

The dialog looks like the image in this link

protected void showSelectBuildingsDialog(final ArrayList<ResourceModel> buildings) {

    final boolean[] checkedColours = new boolean[buildings.size()+1];
    final HashMap<String,Boolean> tempCheckBuilding=new HashMap<String, Boolean>();
    int count = buildings.size();
    checkedColours[0]=all;
    String s="";
    for(int i = 0; i < count; i++) {
        if(flag) {
            for(int j=0;j<sm.getServiceResourceMaps().size();j++) {
                if(sm.getServiceResourceMaps().get(j).getResource()!=null) {
                    if (buildings.get(i).getId() == sm.getServiceResourceMaps().get(j).getResource().getId()) {
                        checkedColours[i + 1] = true;
                        if (!s.contains(buildings.get(i).getResourceCode())) {
                            if(s.trim().length()==0)
                                s += buildings.get(i).getResourceCode();
                            else
                                s += ", "+buildings.get(i).getResourceCode();
                            tempCheckBuilding.put(buildings.get(i).getResourceCode(), true);
                        }
                    }
                }
            }
        } else
            checkedColours[i+1]=checkBuilding.get(resourcemodel.get(i).getResourceCode());

    }
    if(flag) {
        chooseBuildings.setText(s);

    }

    final DialogInterface.OnMultiChoiceClickListener coloursDialogListener = new DialogInterface.OnMultiChoiceClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which, boolean isChecked) {
            ListView list = ((AlertDialog) dialog).getListView();
            if(isChecked) {
                if(which==0) {
                    checkedColours[0] = true;
                    all=true;
                    selectedBuildings.clear();

                    for (int i=0; i < list.getCount(); i++) {

                        checkedColours[i]=true;
                        list.setItemChecked(i, true);
                        if(i>0)
                            tempCheckBuilding.put(resourcemodel.get(i-1).getResourceCode(),true);
                    }
                    for(int i=0;i<buildings.size();i++) {
                        selectedBuildings.add(buildings.get(i));
                    }
                } else {
                    boolean flag=true;
                    for(int i=1;i<checkedColours.length;i++) {
                        if(checkedColours[i]==false)
                            flag=false;
                    }
                    if(flag)
                        list.setItemChecked(0,true);
                    selectedBuildings.add(buildings.get(which - 1));
                    checkedColours[which]=true;
                    tempCheckBuilding.put(resourcemodel.get(which - 1).getResourceCode(), true);
                }
            } else {
                if(which==0) {
                    checkedColours[0] = false;
                    all=false;
                    for (int i=0; i < list.getCount(); i++) {

                        checkedColours[i]=false;
                        list.setItemChecked(i, false);
                        if(i>0)
                            tempCheckBuilding.put(resourcemodel.get(i-1).getResourceCode(),false);
                    }
                    for(int i=0;i<buildings.size();i++) {
                        selectedBuildings.remove(buildings.get(i));
                    }
                } else {
                    checkedColours[0]=false;
                    list.setItemChecked(0,false);
                    selectedBuildings.remove(buildings.get(which - 1));
                    tempCheckBuilding.put(resourcemodel.get(which-1).getResourceCode(), false);
                    checkedColours[which]=false;
                }
            }

        }

    };

    final AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("Select Buildings");
    final String[] buildingNames=new String[buildings.size()+1];
    buildingNames[0]="Select All Buildings";
    for(int i=0;i<buildings.size();i++) {
        buildingNames[i+1]=buildings.get(i).getResourceCode();
    }
    builder.setPositiveButton("Ok",
            new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    for(String key:tempCheckBuilding.keySet()) {
                        checkBuilding.put(key,tempCheckBuilding.get(key));
                    }
                    onChangeSelectedBuildings();
                    chooseLevels.setText(null);
                    chooseUnits.setText(null);

                    if(chooseBuildings.getText().toString().trim().length()!=0) {
                       //proceed by calling appropriate method
                        }
                    }
                }
            });
    builder.setNegativeButton("Cancel",
            new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                }
            });
    builder.setCancelable(true);
    builder.setMultiChoiceItems(buildingNames, checkedColours, coloursDialogListener);
    final SearchView searchView=new SearchView(this);
    builder.setView(searchView); // setting a searchView to the multi choice dialog
    final AlertDialog dialog = builder.create();
    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
//I want to modify the listview in this method, but since 'coloursDialogListener' is dealing with arrays such as 'checkedColours, buildingNames etc, 
//I can't do so. I tried setting an adapter to the listview, but it doesn't seem to help for this reason.
            ListView listView=((AlertDialog)dialog).getListView();
            List<String> list=new ArrayList<String>();
            List<Boolean> checkList=new ArrayList<Boolean>();
            list.add(buildingNames[0]);
            checkList.add(checkedColours[0]);
            try {
                for (int i = 1; i < buildingNames.length;i++) {
                    listView.getChildAt(i).setVisibility(View.GONE);
                    Log.d("test i",""+i);
                    if (buildingNames[i].contains(query)) {
                        listView.getChildAt(i).setVisibility(View.VISIBLE);
                        list.add(buildingNames[i]);
                        if (i < checkedColours.length)
                            checkList.add(checkedColours[i]);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } 
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            return false;
        }
    });
    ListView list;
    if(checkedColours[0]) {
        selectedBuildings.clear();
        list = ((AlertDialog) dialog).getListView();
        for (int i=0; i < list.getCount(); i++) {
            list.setItemChecked(i, true);
        }
        for(int i=0;i<buildings.size();i++) {
            selectedBuildings.add(buildings.get(i));
        }
    } else {
        list = ((AlertDialog) dialog).getListView();
        for (int i=0; i < list.getCount(); i++) {
            list.setItemChecked(i, false);
        }
        for(int i=0;i<buildings.size();i++) {
            selectedBuildings.remove(buildings.get(i));
        }
    }
    if(all)
        list.setItemChecked(0,true);
    else
        list.setItemChecked(0,false);
    dialog.show();
}

This is the crash log:

java.lang.ArrayIndexOutOfBoundsException: length=3; index=3
at android.support.v7.app.AlertController$AlertParams$1.getView(AlertController.java:891)
at android.widget.AbsListView.obtainView(AbsListView.java:2346)
at android.widget.ListView.measureHeightOfChildren(ListView.java:1281)
at android.widget.ListView.onMeasure(ListView.java:1188)
at android.view.View.measure(View.java:18809)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:18809)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18809)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:135)
at android.view.View.measure(View.java:18809)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:18809)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:18809)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18809)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2643)
at android.view.View.measure(View.java:18809)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2112)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1203)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1464)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1119)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6060)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:606)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:746)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5443)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)

May It will help you all:

MultiSelectSpinner is allows to Select Multiple Items from Spinner and SEARCH/ FILTER Item from Spinner Items.

public class MultiSpinnerSearch extends Spinner implements OnCancelListener {

private List<KeyPairBoolData> items;
//private boolean[] selected;
private String defaultText;
private MultiSpinnerSearchListener listener;
MyAdapter adapter;

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

public MultiSpinnerSearch(Context arg0, AttributeSet arg1) {
    super(arg0, arg1);
}

public MultiSpinnerSearch(Context arg0, AttributeSet arg1, int arg2) {
    super(arg0, arg1, arg2);
}

@Override
public void onCancel(DialogInterface dialog) {
    // refresh text on spinner

    StringBuffer spinnerBuffer = new StringBuffer();

    for (int i = 0; i < items.size(); i++) {
        if (items.get(i).isSelected() == true) {
            spinnerBuffer.append(items.get(i).getName());
            spinnerBuffer.append(", ");
        }
    }

    String spinnerText = "";
    spinnerText = spinnerBuffer.toString();
    if (spinnerText.length() > 2)
        spinnerText = spinnerText.substring(0, spinnerText.length() - 2);
    else
        spinnerText = defaultText;

    ArrayAdapter<String> adapterSpinner = new ArrayAdapter<String>(getContext(),
            R.layout.textview_for_spinner,
            new String[] { spinnerText });
    setAdapter(adapterSpinner);

    if(adapter != null)
        adapter.notifyDataSetChanged();

    listener.onItemsSelected(items);
}

@Override
public boolean performClick() {

    AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
    builder.setTitle(defaultText);

    LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE );

    View view = inflater.inflate(R.layout.alert_dialog_listview_search, null);
    builder.setView(view);

    final ListView listView = (ListView) view.findViewById(R.id.alertSearchListView);
    listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
    listView.setFastScrollEnabled(false);
    adapter = new MyAdapter(getContext(), items);
    listView.setAdapter(adapter);

    EditText editText = (EditText) view.findViewById(R.id.alertSearchEditText);
    editText.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            adapter.getFilter().filter(s.toString());
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        @Override
        public void afterTextChanged(Editable s) {  
        }
    });

    //builder.setMultiChoiceItems(items.toArray(new CharSequence[items.size()]), selected, this);
    builder.setPositiveButton(android.R.string.ok,
            new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            Log.i("TAG", " ITEMS : " + items.size() );
            dialog.cancel();
        }
    });

    builder.setOnCancelListener(this);
    builder.show();
    return true;
}

public void setItems(List<KeyPairBoolData> items, String allText, int position,
        MultiSpinnerSearchListener listener) {

    this.items = items;
    this.defaultText = allText;
    this.listener = listener;

    ArrayAdapter<String> adapterSpinner = new ArrayAdapter<String>(getContext(),
            R.layout.textview_for_spinner,
            new String[] { defaultText });
    setAdapter(adapterSpinner);

    if(position != -1)
    {
        items.get(position).setSelected(true);
        //listener.onItemsSelected(items);
        onCancel(null);
    }
}

public interface MultiSpinnerSearchListener {
    public void onItemsSelected(List<KeyPairBoolData> items);
}

//  // Adapter Class            
public class MyAdapter extends BaseAdapter implements Filterable {

    List<KeyPairBoolData> arrayList;      
    List<KeyPairBoolData> mOriginalValues; // Original Values
    LayoutInflater inflater;

    public MyAdapter(Context context, List<KeyPairBoolData> arrayList) {
        this.arrayList = arrayList;
        inflater = LayoutInflater.from(context);
    }

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

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

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

    private class ViewHolder {
        TextView textView;
        CheckBox checkBox;
    }

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

        ViewHolder holder = null;

        if (convertView == null) {

            holder = new ViewHolder();
            convertView = inflater.inflate(R.layout.alert_dialog_listview_search_subview, null);
            holder.textView = (TextView) convertView.findViewById(R.id.alertTextView);
            holder.checkBox = (CheckBox) convertView.findViewById(R.id.alertCheckbox);

            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        final KeyPairBoolData data = arrayList.get(position);

        holder.textView.setText(data.getName());
        holder.checkBox.setChecked(data.isSelected());

        convertView.setOnClickListener(new View.OnClickListener()
        {
            public void onClick(View v)
            {
                ViewHolder temp = (ViewHolder) v.getTag();
                temp.checkBox.setChecked(!temp.checkBox.isChecked());

                int len = arrayList.size();
                for (int i = 0; i < len; i++)
                {
                    if (i == position)
                    {
                        data.setSelected(!data.isSelected());
                        Log.i("TAG", "On Click Selected : " + data.getName() + " : " + data.isSelected());
                        break;
                    }
                }
            }
        });

        holder.checkBox.setTag(holder);

        return convertView;
    }

    @SuppressLint("DefaultLocale")
    @Override
    public Filter getFilter() {
        Filter filter = new Filter() {

            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint,FilterResults results) {

                arrayList = (List<KeyPairBoolData>) results.values; // has the filtered values
                notifyDataSetChanged();  // notifies the data with new filtered values
            }

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults results = new FilterResults();        // Holds the results of a filtering operation in values
                List<KeyPairBoolData> FilteredArrList = new ArrayList<KeyPairBoolData>();

                if (mOriginalValues == null) {
                    mOriginalValues = new ArrayList<KeyPairBoolData>(arrayList); // saves the original data in mOriginalValues
                }

                /********
                 * 
                 *  If constraint(CharSequence that is received) is null returns the mOriginalValues(Original) values
                 *  else does the Filtering and returns FilteredArrList(Filtered)  
                 *
                 ********/
                if (constraint == null || constraint.length() == 0) {

                    // set the Original result to return  
                    results.count = mOriginalValues.size();
                    results.values = mOriginalValues;
                } else {
                    constraint = constraint.toString().toLowerCase();
                    for (int i = 0; i < mOriginalValues.size(); i++) {
                        Log.i("TAG", "Filter : " + mOriginalValues.get(i).getName() + " -> " + mOriginalValues.get(i).isSelected());
                        String data = mOriginalValues.get(i).getName();
                        if (data.toLowerCase().contains(constraint.toString())) {
                            FilteredArrList.add(mOriginalValues.get(i));
                        }
                    }
                    // set the Filtered result to return
                    results.count = FilteredArrList.size();
                    results.values = FilteredArrList;
                }
                return results;
            }
        };
        return filter;
    }
}

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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