10

OK Tengo una opción múltiple ListView que funciona bien. Verifico los cuadros para los contactos (mantenidos en una cadena []) y puedo devolver los valores correctamente. Debido a que algunas personas tienen muchos contactos, quería crear una barra de búsqueda similar a la de stock para la guía telefónica Android. Creé un EditText y lo alineé sobre mi lista. Encontré el código de filtrado aquí en StackOverflow y funciona de maravilla.Multiple Choice Searchable ListView

Mi Problema:

Cuando filtra nombre de alguien, y selecciona el nombre, cuando cualquiera de retroceso de la EditarTexto o siga escribiendo, la posición correcta del nombre que ha seleccionado no se salva. Por ejemplo, si comienzo a escribir "Adam" y llego a "Ada" y lo selecciono, si hago un retroceso para escribir "Carol", se selecciona la posición en la que estaba "Ada". Reúne el lugar donde estaba "Adán" desde el clic (digamos 2) y cuando se restaura la lista, verifica esa posición (2) a pesar de que Adam ya no está allí. Necesito una forma de recopilar el nombre ... luego, cuando la lista se restaure o se vuelva a buscar, se verifica el NAME Adam y no la POSICIÓN en la que Adam estuvo anteriormente. No tengo más ideas que crear toneladas de matrices y realmente podría necesitar algo de ayuda. A continuación se muestra el código que estoy usando:

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

     } 

    }; 
+0

se las arregló para mantener el estado de los elementos marcados con filtros? –

+0

@JonasAlves Publiqué mi solución incompleta. Puede que no funcione para lo que necesita, y fue escrito originalmente para SDK 7 (lo escribí hace bastante tiempo) pero puede que le resulte útil – burmat

Respuesta

8

Nunca terminé encontrando un método mejor que el que voy a enumerar a continuación. Ya no uso este código, y si hay una solución mejor, espero que alguien lo haya publicado en algún lugar.

Lo que terminé haciendo fue crear un ArrayList para mantener los nombres seleccionados. Si se selecciona el nombre, el nombre se inserta en el ArrayList y, si no está seleccionado, aparece en la lista. Cuando se selecciona afterTextChanged, la lista se repite y los nombres se verifican si están actualmente listados en el adaptador. Cuando termine con el proceso de selección y desee continuar, borro el EditText para borrar el filtro, completando así la lista completa en el ListView y configurando todos los contactos seleccionados si existen en el ArrayList.

Nota, yo uso un adaptador personalizado para una lista de contactos que sólo los nombres de la lista, por lo que esta solución puede conseguir más confuso si se utiliza otro tipo de datos, y miro a este método como una solución hackeado:

/** 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 

usted no desea utilizar índices cuando se utilizan los filtros porque el índice 1 podría ser algo en uno ListView, y que podría ser otro elemento ListView cuando se cambia el filtro.

3

Puede crear proyecto androide y agregar estos archivos:

res/esquema de trazado> 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="" 
      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> 

res/esquema de trazado> 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>