2011-04-25 5 views
62

사용자 지정 개체 어댑터를 사용하는 ListView 필터링을 구현하려고하지만 유용한 샘플을 찾을 수 없습니다. 포함 된 코드는 매우 단순하므로 일반적인 ArrayAdapter를 사용할 수 없다는 것을 명심하십시오. 나는 ListView 위에 EditText가 있는데, 사용자가 EditText 위젯에 텍스트를 입력하면 EditText에 쓰여진 텍스트로 ListView를 필터링하고 싶다. 제안 사항을 보내 주시면 감사하겠습니다. 활동에사용자 지정 (개체) 어댑터로 ListView 필터링

1) : 당신은 몇 가지를 할 필요가

public class User { 
    private int UserId; 
    private String FirstName; 
    private String LastName; 

    public int getUserId() { 
     return UserId; 
    } 
    public void setUserId(int UserId) { 
     this.UserId = UserId; 
    } 
    public String getFirstName() { 
     return FirstName; 
    } 
    public void setFirstName(String FirstName) { 
     this.FirstName = FirstName; 
    } 
    public String getLastName() { 
     return LastName; 
    } 
    public void setLastName(String LastName) { 
     this.LastName = LastName; 
    } 
} 

답변

70

: 사용자 클래스 다음

public class management_objects extends Activity { 

private static List<User> UserList; 
private EfficientAdapter adapter = null; 
private ListView objectListView = null; 
private EditText SearchText = null; 

private static class EfficientAdapter extends BaseAdapter implements Filterable{ 
    private LayoutInflater mInflater; 

    public EfficientAdapter(Context context) { 
     mInflater = LayoutInflater.from(context); 
    } 

    public int getCount() { 
     return UserList.size(); 
    } 

    public Object getItem(int position) { 
     return position; 
    } 

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

    public View getView(int position, View convertView, ViewGroup parent) { 
     ViewHolder holder; 
     if (convertView == null) { 
      convertView = mInflater.inflate(R.layout.imagelayout_2lines, null); 
      holder = new ViewHolder(); 
      holder.text = (TextView) convertView.findViewById(R.id.managementObjectText); 
      holder.subtext = (TextView) convertView.findViewById(R.id.managementObjectSubText); 
      holder.icon = (ImageView) convertView.findViewById(R.id.managementObjectIcon); 
      convertView.setTag(holder); 
     } 
     else { 
      holder = (ViewHolder) convertView.getTag(); 
     } 

     holder.text.setText(UserList.get(position).getFirstName()); 
     holder.subtext.setText(UserList.get(position).getLastName()); 
     holder.icon.setImageResource(R.drawable.user); 

     return convertView; 
    } 

    static class ViewHolder { 
     TextView text; 
     TextView subtext; 
     ImageView icon; 
    } 

    @Override 
    public Filter getFilter() { 
     return null; 
    } 
} 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.adobjectlist); 
    Bundle extras = getIntent().getExtras(); 

    SearchText = (EditText) findViewById(R.id.SearchBox);  
    SearchText.addTextChangedListener(filterTextWatcher); 

    objectListView = (ListView) findViewById(R.id.ObjectList); 
    objectListView.setOnItemClickListener(Item_Click); 
    adapter = new EfficientAdapter(this); 
    ComputerName = extras.getString("COMPUTER_NAME"); 

    //Get User list from webservice 
    ShowUsers(); 
} 

됩니다 : 여기

는 활동 클래스의 조각입니다 사용자가 입력 한 값을 포함하는 텍스트 변경 리스너를 EditText에 등록하십시오.

mSearchValue.addTextChangedListener (searchTextWatcher);

2) searchTextWatcher을 만들고 뭔가를 한 :

private TextWatcher searchTextWatcher = new TextWatcher() { 
    @Override 
     public void onTextChanged(CharSequence s, int start, int before, int count) { 
      // ignore 
     } 

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

     @Override 
     public void afterTextChanged(Editable s) { 
      Log.d(Constants.TAG, "*** Search value changed: " + s.toString()); 
      adapter.getFilter().filter(s.toString()); 
     } 
    }; 

3) 사용자 정의 어댑터를 getFilter()를 무시하고 결과를 필터링 및 데이터 세트가 변경 목록보기에 통보해야합니다. 여기에 흥미로운 예제 Filterable 인터페이스를 필요로하지 않는 사람들을 위해

public Filter getFilter() { 
    return new Filter() { 

     @Override 
     protected FilterResults performFiltering(CharSequence constraint) { 
      final FilterResults oReturn = new FilterResults(); 
      final ArrayList<station> results = new ArrayList<station>(); 
      if (orig == null) 
       orig = items; 
      if (constraint != null) { 
       if (orig != null && orig.size() > 0) { 
        for (final station g : orig) { 
         if (g.getName().toLowerCase() 
           .contains(constraint.toString())) 
          results.add(g); 
        } 
       } 
       oReturn.values = results; 
      } 
      return oReturn; 
     } 

     @SuppressWarnings("unchecked") 
     @Override 
     protected void publishResults(CharSequence constraint, 
       FilterResults results) { 
      items = (ArrayList<station>) results.values; 
      notifyDataSetChanged(); 
     } 
    }; 
} 

public void notifyDataSetChanged() { 
    super.notifyDataSetChanged(); 
    notifyChanged = true; 
} 
+4

3)에서 "오버라이드"하는 이유는 무엇입니까? BaseAdapter에는 getFilter()가 없습니다. – Ixx

+4

좋은 캐치 - 필요하지 않습니다. 내 사용자 정의 어댑터 클래스 (실제로 AmazingListView 오픈 소스 위젯에서 AmazingAdapter를 상속)는 getFilter()가 필요한 android.widget.Filterable 인터페이스를 구현합니다. – DustinB

+24

[이 튜토리얼] (http://www.survivingwithandroid.com/2012/10/android-listview-custom-filter-and.html)이 도움이되었습니다. 대답에는 불분명 한 점이 있거나 어쩌면 충분한 집중력으로 읽지 않았을 수도 있습니다. – Sufian

16

는 훨씬 더 간단한 해결책이있다. 또한 다른 솔루션이 실패한 경우 notifyDataSetChanged()을 올바르게 처리합니다. 생성자에 전달 된 배열 객체를 반환하는 BaseAdaptergetArray() 함수를 추가해야합니다.

public abstract class BaseFilterAdapter<T> extends BaseAdapter<T> { 

    private List<T> original; 
    private String lastFilter; 

    public BaseFilterAdapter(Context context, List<T> array) { 
     super(context, new LinkedList<T>()); 
     original = array; 
     filter(""); 
    } 

    protected abstract Boolean predicate(T element, String filter); 

    public void filter(String filter) { 
     lastFilter = filter; 
     super.getArray().clear(); 
     for (T element : original) 
      if (predicate(element, filter)) 
       super.getArray().add(element); 
     super.notifyDataSetChanged(); 
    } 

    @Override 
    public List<T> getArray() { 
     return original; 
    } 

    @Override 
    public void notifyDataSetChanged() { 
     filter(lastFilter); 
    } 
} 
+1

ORIG 변수를 사용하여 초기 인스턴스를 저장하는 탁월한 방법입니다. 잘 했어, 고마워. – radhoo

+0

많은 감사, 그것은 내가 찾고 있었던 것이다 : D +1! – Tenaciousd93

2

@Override 
    public Filter getFilter() { 
     return new Filter() { 
      @SuppressWarnings("unchecked") 
      @Override 
      protected void publishResults(CharSequence constraint, FilterResults results) { 
       Log.d(Constants.TAG, "**** PUBLISHING RESULTS for: " + constraint); 
       myData = (List<MyDataType>) results.values; 
       MyCustomAdapter.this.notifyDataSetChanged(); 
      } 

      @Override 
      protected FilterResults performFiltering(CharSequence constraint) { 
       Log.d(Constants.TAG, "**** PERFORM FILTERING for: " + constraint); 
       List<MyDataType> filteredResults = getFilteredResults(constraint); 

       FilterResults results = new FilterResults(); 
       results.values = filteredResults; 

       return results; 
      } 
     }; 
    } 
+0

내 BaseAdapter 클래스에서 재정의 할 getArray 메소드가 없습니다. –

1

기본 클래스에 toString override를 추가하십시오. 예 :

@Override 
public String toString() { 
    return this.name; 
} 

위의 내용은 목록을 문자열 목록으로 만듭니다. 따라서 다음을 사용할 수 있습니다 :

your_edit_text.addTextChangedListener(new TextWatcher() { 

    @Override 
    public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { 
     YourActivity.this.YourAdapter.getFilter().filter(arg0); 
    } 

    @Override 
    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { 
    } 

    @Override 
    public void afterTextChanged(Editable arg0) {  
    } 
}); 
관련 문제