Многократный выбор Searchable ListView

OK У меня есть многократный выбор ListView, который отлично работает. Я проверяю флажки для контактов (хранящихся в String []) и могу вернуть значения в порядке. Поскольку у некоторых людей есть куча контактов, я хотел создать такую ​​панель поиска, как запасной для телефонной книги Android. Я создал EditText и выровнял его над моим списком. Я нашел код фильтрации здесь, в StackOverflow, и он отлично работает.

Моя проблема:

Когда вы отфильтровываете имя someones, и вы выбираете имя, когда вы либо переходите из EditText, либо продолжаете вводить текст, правильная позиция выбранного вами имени не сохраняется. Например, если я начну набирать "Адам" и перейду к "Аде" и выберем его, если я вернусь к типу в "Кэрол", любая позиция "Ада" была выбрана. Он собирает место, в котором "Адам" находился на клике (пусть говорят 2), и когда список восстанавливается, проверяет эту позицию (2), хотя Адама больше нет. Мне нужен способ для сбора имени. Затем, когда список будет восстановлен или снова просмотрен, NAME Adam проверяется, а не POSITION Adam ранее. У меня нет абсолютно никаких идей, кроме создания массивов массивов, и я могу действительно помочь. Ниже приведен код, который я использую:

    @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.contacts_list);


        myListView = (ListView)findViewById(android.R.id.list);
        search_EditText = (EditText) findViewById(R.id.search_EditText);
        search_EditText.addTextChangedListener(filterTextWatcher);

        adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_multiple_choice, ContactsList); 
        setListAdapter(adapter);

        myListView.setItemsCanFocus(false);
        getListView().setChoiceMode(2);
        myListView.setTextFilterEnabled(true);
        myListView.setFastScrollEnabled(true);
        myListView.invalidate();
}

    private TextWatcher filterTextWatcher = new TextWatcher() {
        public void afterTextChanged(Editable s) {

        }

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

        }

        public void onTextChanged(CharSequence s, int start, int before,
                int count) {

            adapter.getFilter().filter(s);

        }

    };

Ответ 1

Я никогда не получал лучшего метода, чем тот, который я приведу ниже. Я больше не использую этот код, и если есть лучшее решение, я надеюсь, что кто-то его где-то разместил.

В результате я создал ArrayList для хранения выбранных имен. Если имя выбрано, имя вставляется в ArrayList, и если оно не отмечено, оно выставляется из списка. Когда выбрано afterTextChanged, список переименовывается и имена проверяются, если они в настоящее время указаны в адаптере. Когда вы закончите процесс выбора и хотите продолжить, я очищаю EditText, чтобы очистить фильтр, поэтому заполняет полный список в ListView и устанавливает все выбранные контакты, если они существуют в ArrayList.

Примечание. Я использую пользовательский адаптер для списка контактов, который только имена списков, так что это решение может стать более запутанным, если вы используете другие типы данных, и я рассматриваю этот метод как взломанное решение:

/** Used for filter **/
private TextWatcher filterTextWatcher = new TextWatcher() {

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

        ListView listview = getListView();

        SparseBooleanArray checked = listview.getCheckedItemPositions();
        for (int i = 0; i < ContactsList.length; i++) {
            if (checked.get(i) == true) {
                Object o = getListAdapter().getItem(i);
                String name = o.toString();
                // if the arraylist does not contain the name, add it
                if (selected.contains(name)){ 
                    // Do Nothing
                } else {
                    selected.add(name);
                }
            }
        }           
    } //<-- End of beforeTextChanged

    public void onTextChanged(CharSequence s, int start, int before, int count) {           
        adapter.getFilter().filter(s);              
    } //<-- End of onTextChanged

    public void afterTextChanged(Editable s) {
        ListView listview = getListView();
        // Uncheck everything:
        for (int i = 0; i < listview.getCount(); i++){
            listview.setItemChecked(i, false);                  
        }

        adapter.getFilter().filter(s, new Filter.FilterListener() {
            public void onFilterComplete(int count) {
                adapter.notifyDataSetChanged();
                ListView listview = getListView();
                for (int i = 0; i < adapter.getCount(); i ++) {
                    // if the current (filtered) 
                    // listview you are viewing has the name included in the list,
                    // check the box
                    Object o = getListAdapter().getItem(i);
                    String name = o.toString();
                    if (selected.contains(name)) {
                        listview.setItemChecked(i, true);
                    } else {
                        listview.setItemChecked(i, false);
                    }
                }

            }
        });         
    } //<-- End of afterTextChanged

}; //<-- End of TextWatcher

Вы не хотите использовать индексы при использовании фильтров, потому что индекс 1 может быть чем-то одним ListView, и при изменении фильтра он может быть другим элементом ListView.

Ответ 2

Вы можете создать проект андроида и добавить эти файлы:

Рез/layout- > list_row.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#3c3c3c"
    android:orientation="horizontal"
    android:padding="8dp" >
    <ImageView
        android:id="@+id/contactimage"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_marginRight="8dp"
        android:background="@drawable/ic_launcher"
        android:contentDescription="@string/app_name"
        android:scaleType="centerInside" />
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_toLeftOf="@+id/contactcheck"
        android:layout_toRightOf="@+id/contactimage" >
        <TextView
            android:id="@+id/contactname"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:text="Contact Name"
            android:textColor="#000"
            android:textIsSelectable="false"
            android:textSize="18dp"
            android:textStyle="bold" />
        <TextView
            android:id="@+id/contactno"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/contactname"
            android:singleLine="true"
            android:text="09876543210"
            android:textColor="#2689e0"
            android:textIsSelectable="false"
            android:textSize="14dp" />
    </RelativeLayout>
    <CheckBox
        android:id="@+id/contactcheck"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerInParent="true"
        android:layout_marginLeft="8dp" />
</RelativeLayout>

Рез/layout- > activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <EditText
        android:id="@+id/input_search"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerInParent="true"
        android:hint="Search Contacts"
        android:textSize="18dp" />
    <LinearLayout
        android:id="@+id/data_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/ok_button"
        android:layout_below="@+id/input_search"
        android:gravity="center|top"
        android:orientation="vertical" />
    <Button
        android:id="@+id/ok_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"
        android:text=" OK "
        android:textSize="18dp" />
    <RelativeLayout
        android:id="@+id/pbcontainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#55000000"
        android:clickable="true"
        android:visibility="gone" >
        <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true" />
    </RelativeLayout>
</RelativeLayout>

ContactObject.java

package com.multiselectlistexample;
public class ContactObject {

    private String contactName;
    private String contactNo;
    private String image;
    private boolean selected;
    public String getName() {
        return contactName;
    }
    public void setName(String contactName) {
        this.contactName = contactName;
    }
    public String getNumber() {
        return contactNo;
    }
    public void setNumber(String contactNo) {
        this.contactNo = contactNo;
    }
    public String getImage() {
        return image;
    }
    public void setImage(String image) {
        this.image = image;
    }
    public boolean isSelected() {
        return selected;
    }
    public void setSelected(boolean selected) {
        this.selected = selected;
    }
}

ContactsListClass.java

package com.multiselectlistexample;
import java.util.ArrayList;
public class ContactsListClass {
    public static final ArrayList<ContactObject> phoneList = new ArrayList<ContactObject>();
}

ContactsAdapter.java

package com.multiselectlistexample;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.ContactsContract.Contacts;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;
public class ContactsAdapter extends BaseAdapter {
    Context mContext;
    LayoutInflater inflater;
    private List<ContactObject> mainDataList = null;
    private ArrayList<ContactObject> arraylist;
    public ContactsAdapter(Context context, List<ContactObject> mainDataList) {

        mContext = context;
        this.mainDataList = mainDataList;
        inflater = LayoutInflater.from(mContext);
        this.arraylist = new ArrayList<ContactObject>();
        this.arraylist.addAll(mainDataList);


    }
    static class ViewHolder {
        protected TextView name;
        protected TextView number;
        protected CheckBox check;
        protected ImageView image;
    }
    @Override
    public int getCount() {
        return mainDataList.size();
    }
    @Override
    public ContactObject getItem(int position) {
        return mainDataList.get(position);
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    public View getView(final int position, View view, ViewGroup parent) {
        final ViewHolder holder;
        if (view == null) {
            holder = new ViewHolder();
            view = inflater.inflate(R.layout.list_row, null);
            holder.name = (TextView) view.findViewById(R.id.contactname);
            holder.number = (TextView) view.findViewById(R.id.contactno);
            holder.check = (CheckBox) view.findViewById(R.id.contactcheck);
            holder.image = (ImageView) view.findViewById(R.id.contactimage);
            view.setTag(holder);
            view.setTag(R.id.contactname, holder.name);
            view.setTag(R.id.contactno, holder.number);
            view.setTag(R.id.contactcheck, holder.check);
            holder.check
                    .setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                        @Override
                        public void onCheckedChanged(CompoundButton vw,
                                boolean isChecked) {
                            int getPosition = (Integer) vw.getTag();
                            mainDataList.get(getPosition).setSelected(
                                    vw.isChecked());
                        }
                    });
        } else {
            holder = (ViewHolder) view.getTag();
        }
        holder.check.setTag(position);

        holder.name.setText(mainDataList.get(position).getName());
        holder.number.setText(mainDataList.get(position).getNumber());

        if(getByteContactPhoto(mainDataList.get(position).getImage())==null){
            holder.image.setImageResource(R.drawable.ic_launcher);
        }else{
            holder.image.setImageBitmap(getByteContactPhoto(mainDataList.get(position).getImage()));
        }



        holder.check.setChecked(mainDataList.get(position).isSelected());
        return view;
    }
    public void filter(String charText) {
        charText = charText.toLowerCase(Locale.getDefault());
        mainDataList.clear();
        if (charText.length() == 0) {
            mainDataList.addAll(arraylist);
        } else {
            for (ContactObject wp : arraylist) {
                if (wp.getName().toLowerCase(Locale.getDefault())
                        .contains(charText)) {
                    mainDataList.add(wp);
                }
            }
        }
        notifyDataSetChanged();
    }
    public Bitmap getByteContactPhoto(String contactId) {
        Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, Long.parseLong(contactId));
        Uri photoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.CONTENT_DIRECTORY);
        Cursor cursor = mContext.getContentResolver().query(photoUri,
                        new String[] {Contacts.Photo.DATA15}, null, null, null);
        if (cursor == null) {
            return null;
        }
        try {
            if (cursor.moveToFirst()) {
                byte[] data = cursor.getBlob(0);
                if (data != null) {
                    return BitmapFactory.decodeStream( new ByteArrayInputStream(data));
                }
            }
        } finally {
            cursor.close();
        }
        return null;
        }

}

MainActivity.java

package com.multiselectlistexample;
import java.util.Collections;
import java.util.Comparator;
import java.util.Locale;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Toast;
public class MainActivity extends Activity {
    Context context = null;
    ContactsAdapter objAdapter;
    ListView lv = null;
    EditText edtSearch = null;
    LinearLayout llContainer = null;
    Button btnOK = null;
    RelativeLayout rlPBContainer = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = this;
        setContentView(R.layout.activity_main);
        rlPBContainer = (RelativeLayout) findViewById(R.id.pbcontainer);
        edtSearch = (EditText) findViewById(R.id.input_search);
        llContainer = (LinearLayout) findViewById(R.id.data_container);
        btnOK = (Button) findViewById(R.id.ok_button);
        btnOK.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                getSelectedContacts();
            }
        });
        edtSearch.addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence cs, int arg1, int arg2,
                    int arg3) {
                // When user changed the Text
                String text = edtSearch.getText().toString()
                        .toLowerCase(Locale.getDefault());
                objAdapter.filter(text);
            }
            @Override
            public void beforeTextChanged(CharSequence arg0, int arg1,
                    int arg2, int arg3) {
                // TODO Auto-generated method stub
            }
            @Override
            public void afterTextChanged(Editable arg0) {
                // TODO Auto-generated method stub
            }
        });
        addContactsInList();
    }
    private void getSelectedContacts() {
        // TODO Auto-generated method stub
        StringBuffer sb = new StringBuffer();
        for (ContactObject bean : ContactsListClass.phoneList) {
            if (bean.isSelected()) {
                sb.append(bean.getName());
                sb.append(",");
            }
        }
        String s = sb.toString().trim();
        if (TextUtils.isEmpty(s)) {
            Toast.makeText(context, "Select atleast one Contact",
                    Toast.LENGTH_SHORT).show();
        } else {
            s = s.substring(0, s.length() - 1);
            Toast.makeText(context, "Selected Contacts : " + s,
                    Toast.LENGTH_SHORT).show();
        }
    }
    private void addContactsInList() {
        // TODO Auto-generated method stub
        Thread thread = new Thread() {
            @Override
            public void run() {
                showPB();
                try {
                    Cursor phones = getContentResolver().query(
                            ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                            null, null, null, null);
                    try {
                        ContactsListClass.phoneList.clear();
                    } catch (Exception e) {
                    }
                    while (phones.moveToNext()) {
                        String phoneName = phones
                                .getString(phones
                                        .getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                        String phoneNumber = phones
                                .getString(phones
                                        .getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                        String phoneImage = phones
                                .getString(phones
                                        .getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));

                        ContactObject cp = new ContactObject();


                        cp.setName(phoneName);
                        cp.setNumber(phoneNumber);
                        cp.setImage(phoneImage);
                        ContactsListClass.phoneList.add(cp);
                    }
                    phones.close();
                    lv = new ListView(context);
                    lv.setLayoutParams(new LayoutParams(
                            LayoutParams.MATCH_PARENT,
                            LayoutParams.MATCH_PARENT));
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            // TODO Auto-generated method stub
                            llContainer.addView(lv);
                        }
                    });
                    Collections.sort(ContactsListClass.phoneList,
                            new Comparator<ContactObject>() {
                                @Override
                                public int compare(ContactObject lhs,
                                        ContactObject rhs) {
                                    return lhs.getName().compareTo(
                                            rhs.getName());
                                }
                            });
                    objAdapter = new ContactsAdapter(MainActivity.this,
                            ContactsListClass.phoneList);
                    lv.setAdapter(objAdapter);
                    lv.setOnItemClickListener(new OnItemClickListener() {
                        @Override
                        public void onItemClick(AdapterView<?> parent,
                                View view, int position, long id) {
                            CheckBox chk = (CheckBox) view
                                    .findViewById(R.id.contactcheck);
                            ContactObject bean = ContactsListClass.phoneList
                                    .get(position);
                            if (bean.isSelected()) {
                                bean.setSelected(false);
                                chk.setChecked(false);
                            } else {
                                bean.setSelected(true);
                                chk.setChecked(true);
                            }
                        }
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                }
                hidePB();
            }
        };
        thread.start();
    }
    void showPB() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                rlPBContainer.setVisibility(View.VISIBLE);
                edtSearch.setVisibility(View.GONE);
                btnOK.setVisibility(View.GONE);
            }
        });
    }
    void hidePB() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                rlPBContainer.setVisibility(View.GONE);
                edtSearch.setVisibility(View.VISIBLE);
                btnOK.setVisibility(View.VISIBLE);
            }
        });
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.multiselectlistexample"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>