2017-04-13 2 views
1

J'ai une vue de la liste avec une recherche EditText ci-dessus. Chaque ligne de la liste comporte plusieurs textes et images. Lorsque l'utilisateur entre un mot-clé dans la recherche EditText, je veux que la liste soit mise à jour avec les lignes qui contiennent le mot-clé. J'ai emprunté la mise en œuvre dans la question this comme ci-dessous.Rechercher un mot clé dans ListView avec adaptateur personnalisé

Mon adaptateur personnalisé:

public class CustomAdapter extends BaseAdapter implements Filterable { 

    private LayoutInflater inflater; 
    private ArrayList<CustomObject> objects;//mOriginalValues 
    private Activity activity; 
    private ArrayList<Bitmap> newsImageList; 
    private Context context; 
    private ArrayList<CustomObject> filteredObjects; // Values to be displayed after filtering 


    private class ViewHolder { 
     TextView titleTextView; 
     TextView dateTextView; 
     TextView bodyTextView; 
     ImageView logoView; 
     ImageView newsImageView; 
     ProgressBar progressBar; 
    } 


    public CustomAdapter(Context context, ArrayList<CustomObject> objects, Activity activity) { 
     // super(context, R.layout.news_item, objects); 

     inflater = LayoutInflater.from(context); 
     this.objects = objects; 
     this.filteredObjects=objects; 
     this.activity= activity; 
     this.newsImageList= new ArrayList<Bitmap>(); 
     this.context= context; 

     for(int i=0; i<objects.size(); i++) 
      newsImageList.add(null); 


    } 

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

    @Override 
    public CustomObject getItem(int position) { 
     return filteredObjects.get(position); 
    } 

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

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

     System.out.println("IN GET VIEW"); 

     ViewHolder holder = null; 
     if(convertView == null) { 
      holder = new ViewHolder(); 
      convertView = inflater.inflate(R.layout.news_item, null); 

      holder.titleTextView = (TextView) convertView.findViewById(R.id.txtTitle); 
      holder.dateTextView = (TextView) convertView.findViewById(R.id.txtDate); 
      holder.bodyTextView = (TextView) convertView.findViewById(R.id.txtBody); 
      holder.logoView= (ImageView) convertView.findViewById(R.id.source_imageView); 
      holder.newsImageView= (ImageView) convertView.findViewById(R.id.news_imageView); 
      holder.progressBar= (ProgressBar) convertView.findViewById(R.id.img_progress_bar); 


      convertView.setTag(holder); 
     } else { 
      holder = (ViewHolder) convertView.getTag(); 
     } 
     holder.titleTextView.setText(objects.get(position).getTitle()); 
     holder.dateTextView.setText(objects.get(position).getDate()); 
     holder.bodyTextView.setText(objects.get(position).getBody()); 

     //for the source logo 
     String uri = "@drawable/"+objects.get(position).getSource_logo()+"_logo"; 
     int imageResource = activity.getResources().getIdentifier(uri, null, activity.getPackageName()); 
     Drawable res =activity.getResources().getDrawable(imageResource); 
     holder.logoView.setImageDrawable(res); 



     //the news image 
     String newsImageURL = objects.get(position).getNewsImageURL(); 

     if(newsImageURL!=null) { 
      // show The Image in a ImageView 

      //pre-execute 
      holder.progressBar.setVisibility(View.VISIBLE); 
      holder.newsImageView.setVisibility(View.VISIBLE); 
      RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) holder.bodyTextView.getLayoutParams(); 
      params.addRule(RelativeLayout.BELOW, R.id.relative_container); 

      Picasso.with(context).load(newsImageURL).into(holder.newsImageView);//EXECUTE in background 

      holder.progressBar.setVisibility(View.INVISIBLE);//post-execute 

     } 
     else 
     { 
      System.out.println("NO IMAGE"); 
      //adjusting the view 
      holder.progressBar.setVisibility(View.INVISIBLE); 
      holder.newsImageView.setVisibility(View.GONE); 
      RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) holder.bodyTextView.getLayoutParams(); 
      params.addRule(RelativeLayout.BELOW, R.id.txtDate); 
     } 


     return convertView; 
    } 



    @Override 
    public Filter getFilter() { 
     Filter filter = new Filter() { 

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

       filteredObjects = (ArrayList<CustomObject>) results.values; // has the filtered values 
       notifyDataSetChanged(); // notifies the data with new filtered values 
      } 

      @Override 
      protected FilterResults performFiltering(CharSequence constraint) { 

       System.out.println("FILTERING with the keyword:"+ constraint); 

       FilterResults results = new FilterResults();  // Holds the results of a filtering operation in values 
       ArrayList<Object> FilteredArrList = new ArrayList<Object>(); 

       if (objects == null) { 
        objects = new ArrayList<CustomObject>(filteredObjects); // 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 = objects.size(); 
        results.values = objects; 
       } else { 
        constraint = constraint.toString().toLowerCase(); 
        for (int i = 0; i < objects.size(); i++) { 

         System.out.println("loop "+i); 

         String title = objects.get(i).getTitle(); 
         String date = objects.get(i).getDate(); 
         String body = objects.get(i).getBody(); 
         String source_logo = objects.get(i).getSource_logo(); 
         String newsImageURL = objects.get(i).getNewsImageURL(); 

         System.out.println("title of this item:"+title+", key word:"+constraint.toString()); 
         if (title.contains(constraint.toString()) || date.contains(constraint.toString()) || body.contains(constraint.toString())) { 
          System.out.println("FOUND!"); 
          FilteredArrList.add(new CustomObject(title,date, body, source_logo, newsImageURL)); 
         } 
        } 
        // set the Filtered result to return 
        results.count = FilteredArrList.size(); 
        results.values = FilteredArrList; 
       } 
       return results; 
      } 


     }; 
     return filter; 
    } 

} 

class CustomObject { 

    private String title; 
    private String date; 
    private String body; 
    private String source_logo; 
    private String newsImageURL; 

    public CustomObject(String prop1, String prop2, String prop3, String prop4, String prop5) { 
     this.title = prop1; 
     this.date = prop2; 
     this.body=prop3; 
     this.source_logo=prop4; 
     this.newsImageURL=prop5; 
    } 

    public String getTitle() { 
     return title; 
    } 

    public String getDate() { 
     return date; 
    } 

    public String getBody(){ 
     return body; 
    } 

    public String getSource_logo() 
    { 
     return source_logo; 
    } 

    public String getNewsImageURL(){ return newsImageURL; } 

} 

Dans mon activité:

listView = (ListView) activity.findViewById(R.id.activity_main_listview);//news list view (title, date, body per item) 
      searchEditText = (EditText) activity.findViewById(R.id.news_search_editText); 

      // Add Text Change Listener to EditText 
      searchEditText.addTextChangedListener(new TextWatcher() { 

       @Override 
       public void onTextChanged(CharSequence s, int start, int before, int count) { 
        // Call back the Adapter with current character to Filter 
        System.out.println("TEXT CHANGED!"); 
        customAdapter.getFilter().filter(s.toString()); 
        //listView.setAdapter(customAdapter); 
       } 

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

       @Override 
       public void afterTextChanged(Editable s) { 

        //customAdapter.getFilter().filter(s.toString()); 
       } 
      }); 


      //preparing the news titles, dates, first part of bodies, and source logo. 
      ArrayList<CustomObject> objects = new ArrayList<CustomObject>(); 
      for (int i = 0; i < titleList.size(); i++) 
       objects.add(new CustomObject(titleList.get(i), dateList.get(i), reduceTextLetters(textList.get(i), 150) + "...", sourceList.get(i), imageURLList.get(i))); 

      customAdapter = new CustomAdapter(activity, objects, activity); 
      listView.setAdapter(customAdapter); 

Mon fichier XML d'activité:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    > 

    <RelativeLayout 
     android:orientation="vertical" android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:layout_alignParentTop="true" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentStart="true"> 

     <EditText 
      android:id="@+id/news_search_editText" 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:hint="البحث" 
      /> 

     <android.support.v4.widget.SwipeRefreshLayout 
      android:id="@+id/activity_main_swipe_refresh_layout" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:layout_below="@id/news_search_editText"> 

     <ListView 
      android:id="@+id/activity_main_listview" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      > 
     </ListView> 


     </android.support.v4.widget.SwipeRefreshLayout> 


    </RelativeLayout> 

    <Button 
     android:text="تحديث ↑" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:id="@+id/refresh_button" 
     android:background="@drawable/button_refresh" 
     android:layout_alignParentTop="true" 
     android:layout_centerInParent="true" 
     android:layout_gravity="center" 
     android:layout_marginTop="50dp" 
     /> 

</RelativeLayout> 

Malheureusement, le comportement du filtrage est incorrect. Bien que je puisse voir dans le journal que la comparaison entre le mot-clé et le contenu de chaque ligne est effectuée correctement et que seuls les mots-clés correspondants sont ajoutés à la liste filtrée, la liste mise à jour n'est pas correcte. Lorsque j'entre un mot-clé qui est dans la liste, il affiche pour moi les premiers éléments de la liste (dont certains n'ont rien à voir avec le mot-clé) et supprime le reste. Lorsque j'entre un mot-clé qui ne figure pas dans la liste, il efface la liste. Par conséquent, le comportement est étrange et inattendu. Quelqu'un peut-il suggérer une solution?

Répondre

0

Il existe une autre approche: enregistrer toutes les valeurs possibles dans les valeurs de recherche de base de données par la requête LIKE de Sql. J'ai utilisé cela pour mettre en œuvre la recherche dans une très longue liste de villes. Voici un extrait de code pour le faire (prject utilise OrmLite):

/** 
    * Query all objects from database, which field contains given substring. 
    * @param daoFetcher Function, returning Dao of necessary type 
    * @param targetColumnName Name of Table column, we're looking matches in for 
    * @param matchText text within table column we're searching for. 
    * @param <T> 
    * @return 
    */ 
    private <T> List<T> getRecordsContainingText(Func0<Dao<T, Integer>> daoFetcher, 
                String targetColumnName, 
                String matchText) throws SQLException { 
     // get dao of appropriate type by using user function 
     Dao<T, Integer> dao = daoFetcher.call(); 
     QueryBuilder<T, Integer> queryBuilder = dao.queryBuilder(); 
     // query for 'LIKE' 
     String likeQuery = "%" + matchText + "%"; 
     // form query 
     queryBuilder.where().like(targetColumnName, likeQuery); 
     PreparedQuery<T> preparedQuery = queryBuilder.prepare(); 
     List<T> result = dao.query(preparedQuery); 
     return result; 
    } 
0

Je résolu mon problème en créant une copie des valeurs de la liste. Chaque fois que l'utilisateur saisit un mot-clé, cette copie est effacée, puis remplie à partir de la liste d'origine uniquement avec les lignes contenant le mot-clé. Enfin, je réinitialise mon adaptateur avec les nouvelles valeurs dans la liste de copie. Quelque chose comme ci-dessous,

  //another way (for keyword search) 
     // Add Text Change Listener to EditText 
     searchEditText.addTextChangedListener(new TextWatcher() { 

      @Override 
      public void onTextChanged(CharSequence s, int start, int before, int count) { 
       // Call back the Adapter with current character to Filter 
       System.out.println("TEXT CHANGED!"); 
       //customAdapter.getFilter().filter(s.toString()); 
       //listView.setAdapter(customAdapter); 


       //another way (for keyword search) 

       titleList2.clear(); 
       dateList2.clear(); 
       textList2.clear(); 
       urlList2.clear(); 
       sourceList2.clear(); 
       timestampList2.clear(); 
       imageURLList2.clear(); 

       for(int i=0; i<textList.size(); i++) 
       { 
        if(s.toString().isEmpty() || textList.get(i).contains(s) || titleList.get(i).contains(s) || dateList.get(i).contains(s) || sourceList.get(i).contains(s)) 
        { 

         titleList2.add(titleList.get(i)); 
         dateList2.add(dateList.get(i)); 
         textList2.add(textList.get(i)); 
         urlList2.add(urlList.get(i)); 
         sourceList2.add(sourceList.get(i)); 
         timestampList2.add(timestampList.get(i)); 
         imageURLList2.add(imageURLList.get(i)); 

        } 

       } 


       //preparing the news titles, dates, first part of bodies, and source logo. 
       ArrayList<CustomObject> objects = new ArrayList<CustomObject>(); 
       for (int i = 0; i < titleList2.size(); i++) 
        objects.add(new CustomObject(titleList2.get(i), dateList2.get(i), reduceTextLetters(textList2.get(i), 150) + "...", sourceList2.get(i), imageURLList2.get(i))); 

       customAdapter = new CustomAdapter(activity, objects, activity); 
       listView.setAdapter(customAdapter); 




      } 

C'est une manière simple, et je la trouve très intuitive.