Множественный выбор с возможностью поиска ListView - PullRequest
11 голосов
/ 26 февраля 2011

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

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

Когда вы фильтруете чье-либо имя и выбираете имя, когда вы либо возвращаетесь назад из EditText, либо продолжаете печатать, правильная позиция выбранного вами имени не сохраняется. Например, если я начну печатать «Адам», доберусь до «Ады» и выберу его, если я нажму клавишу «назад», чтобы набрать «Кэрол», будет выбрана любая позиция, в которой была «Ада». Он собирает место, в котором находился «Адам», по щелчку (скажем, 2) и, когда список восстанавливается, проверяет эту позицию (2), даже если Адама там больше нет. Мне нужен способ собрать имя ... затем, когда список восстанавливается или ищется снова, проверяется ИМЯ Адама, а не ПОЛОЖЕНИЕ, в котором Адам был ранее. У меня нет абсолютно никаких идей, кроме как создавать тонны массивов, и я действительно могу использовать некоторую помощь. Ниже приведен код, который я использую:

    @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);

        }

    };

Ответы [ 2 ]

10 голосов
/ 13 сентября 2012

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

В итоге я создал 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 при изменении фильтра.

4 голосов
/ 06 июля 2016

Вы можете создать Android проект и добавить следующие файлы:

Рез / 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>
...