AutoCompleteAdapter:支持AutoCompleteTextView的本地搜索Adapter
class AutoCompleteAdapter extends BaseAdapter implements Filterable {
private static final int MODE_NONE = 0x000; // 0000b
public static final int MODE_CONTAINS = 0x001; // 0001b
public static final int MODE_STARTSWITH = 0x002; // 0010b
public static final int MODE_SPLIT = 0x004; // 0100b
private static final String SPLIT_SEPARATOR = "[,.\\s]+"; // 分隔符孵延,默認(rèn)為空白符宜肉、英文逗號(hào)糙麦、英文句號(hào)
private static boolean isFound = false; // 當(dāng)MODE_STARTSWITH模式匹配成功時(shí)掏呼,不再進(jìn)行MODE_SPLIT模式的匹配
private int defaultMode = MODE_CONTAINS; // 0110b
private LayoutInflater inflater;
private ArrayFilter mArrayFilter;
private List<M_Lesson> mOriginalValues; // 所有的item
private List<M_Lesson> mObjects; // 過(guò)濾后的item
private final Object mLock = new Object(); // 同步鎖
private int maxMatch = -1; // 最多顯示的item數(shù)目,負(fù)數(shù)表示全部
private int simpleItemHeight; // 單行item的高度值裙盾,故需要在XML中固定父布局的高度值
private char previewChar = '@'; // 默認(rèn)字符
private boolean isSupportPreview = false; // 是否可以使用@符號(hào)進(jìn)行預(yù)覽全部提示內(nèi)容
public AutoCompleteAdapter(Context context, List<M_Lesson> mOriginalValues) {
this(context, mOriginalValues, -1);
}
public AutoCompleteAdapter(Context context, List<M_Lesson> mOriginalValues, int maxMatch) {
this.mOriginalValues = mOriginalValues;
// 初始化時(shí)將其設(shè)置成mOriginalValues,避免在未進(jìn)行數(shù)據(jù)保存時(shí)執(zhí)行刪除操作導(dǎo)致程序的崩潰
this.mObjects = mOriginalValues;
this.maxMatch = maxMatch;
inflater = LayoutInflater.from(context);
initViewHeight();
}
private void initViewHeight() {
View view = inflater.inflate(R.layout.app_item_jiaoan_createdialog_drop_list, null);
view.measure(0, 0);
// 其他方法獲取的高度值會(huì)因View尚未被繪制而獲取到0
simpleItemHeight = view.getMeasuredHeight();
}
public int getSimpleItemHeight() {
return simpleItemHeight; // 5 * 2 + 28(dp) => 103(px)
}
public void setSupportPreview(boolean isSupportPreview) {
this.isSupportPreview = isSupportPreview;
}
public void setSupportPreview(boolean isSupportPreview, char previewChar) {
this.isSupportPreview = isSupportPreview;
this.previewChar = previewChar;
}
@Override
public int getCount() {
return mObjects.size();
}
@Override
public M_Lesson getItem(int position) {
return mObjects.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.app_item_jiaoan_createdialog_drop_list, parent, false);
holder.tv = convertView.findViewById(R.id.tv_simple_item);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tv.setText(mObjects.get(position).getLessonname());
return convertView;
}
private static class ViewHolder {
TextView tv;
}
public void setDefaultMode(int defaultMode) {
this.defaultMode = defaultMode;
}
public void add(M_Lesson item) {
mOriginalValues.add(item);
notifyDataSetChanged(); //
}
public void clear() {
if (mOriginalValues != null && !mOriginalValues.isEmpty()) {
mOriginalValues.clear();
notifyDataSetChanged(); //
}
}
// Interface
public interface OnFilterResultsListener {
void onFilterResultsListener(int count);
}
private OnFilterResultsListener mFilterListener;
public void setOnFilterResultsListener(OnFilterResultsListener listener) {
this.mFilterListener = listener;
}
@Override
public Filter getFilter() {
if (mArrayFilter == null) {
mArrayFilter = new ArrayFilter(mFilterListener);
}
return mArrayFilter;
}
private class ArrayFilter extends Filter {
private OnFilterResultsListener listener;
public ArrayFilter(OnFilterResultsListener listener) {
this.listener = listener;
}
@Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();
if (mOriginalValues == null) {
synchronized (mLock) {
mOriginalValues = new ArrayList<>(mObjects);
}
}
if (prefix == null || prefix.length() == 0) {
synchronized (mLock) {
ArrayList<M_Lesson> list = new ArrayList<>(mOriginalValues);
results.values = list;
results.count = list.size();
}
} else {
if (isSupportPreview) {
int index = prefix.toString().indexOf(String.valueOf(previewChar));
if (index != -1) {
prefix = prefix.toString().substring(index + 1);
}
}
String prefixString = prefix.toString().toLowerCase(); // prefixString
final int count = mOriginalValues.size(); // count
final ArrayList<M_Lesson> newValues = new ArrayList<>(count); // newValues
for (int i = 0; i < count; i++) {
final String value = mOriginalValues.get(i).getLessonname(); // value
final String valueText = String.valueOf(value).toLowerCase(); // valueText
// 1. 匹配所有
if ((defaultMode & MODE_CONTAINS) != MODE_NONE) {
if (valueText.contains(prefixString)) {
newValues.add(mOriginalValues.get(i));
}
} else { // support: defaultMode = MODE_STARTSWITH | MODE_SPLIT
// 2. 匹配開(kāi)頭
if ((defaultMode & MODE_STARTSWITH) != MODE_NONE) {
if (valueText.startsWith(prefixString)) {
newValues.add(mOriginalValues.get(i));
isFound = true;
}
}
// 3. 分隔符匹配,效率低
if (!isFound && (defaultMode & MODE_SPLIT) != MODE_NONE) {
final String[] words = valueText.split(SPLIT_SEPARATOR);
for (String word : words) {
if (word.startsWith(prefixString)) {
newValues.add(mOriginalValues.get(i));
break;
}
}
}
if (isFound) { // 若在MODE_STARTSWITH模式中匹配呀潭,則再次復(fù)位進(jìn)行下一次判斷
isFound = false;
}
}
if (maxMatch > 0) { // 限制顯示item的數(shù)目
if (newValues.size() > maxMatch - 1) {
break;
}
}
} // for (int i = 0; i < count; i++)
results.values = newValues;
results.count = newValues.size();
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
//noinspection unchecked
mObjects = (List<M_Lesson>) results.values;
// 由于當(dāng)刪除提示框中的記錄行時(shí),而AutoCompleteTextView此時(shí)內(nèi)容又不改變至非,故不會(huì)觸發(fā)FilterResults事件
// 導(dǎo)致刪除記錄行時(shí)钠署,提示框的高度不會(huì)發(fā)生相應(yīng)的改變
// 解決方法:需要在ImageView的點(diǎn)擊監(jiān)聽(tīng)器中也調(diào)用OnFilterResultsListener.onFilterResultsListener()
// 來(lái)共同完成
if (listener != null) {
listener.onFilterResultsListener(results.count);
}
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}
}