2017-04-13 133 views
1

我有一个列表视图,上面有一个搜索EditText。列表视图中的每一行都由几个文本和图片组成。当用户在搜索EditText中输入关键字时,我希望用包含关键字的行更新列表视图。我已经借用this的实现如下。使用自定义适配器在ListView中搜索关键字

我的自定义适配器:

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; } 

} 

在我的活动:

​​

我的动态XML文件:

<?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> 

不幸的是,过滤的行为是不正确的。虽然我可以在日志中看到关键字与每行内容之间的比较是否正确完成,并且只有匹配关键字被添加到已过滤列表中,但更新列表并不正确。当我输入列表中的关键字时,它会显示列表中的前几个项目(其中一些与关键字无关)并删除其余项目。当我输入不在列表中的关键字时,它将清除列表视图。因此,这种行为是奇怪的和意外的。有人可以提出解决方案吗?

回答

0

还有一种方法 - 通过Sql的LIKE请求将所有可能的值保存到数据库搜索匹配值中。我用它在很长的城市列表中实现搜索。 这里是这样做的代码片段(prject使用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

我通过创建列表值的副本解决了我的问题。无论用户何时输入关键字,该副本都将被清除,然后仅使用包含关键字的行从原始列表填充该副本。最后,我用复制列表中的新值重新设置适配器。像下面这样,

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




      } 

这是一个简单的方法,我觉得它非常直观。

相关问题