辛苦堆砌,转载请注明出处,谢谢!
最近工作用到了自动补全,这里做一个简单记录,首先上我们的布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
android:padding="20dp"
tools:context="com.yjp.autocompletetextviewdemo.MainActivity">
<AutoCompleteTextView
android:id="@+id/auto_complete_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="2"
android:layout_gravity="top" />
</FrameLayout>
只有我们的主角,这样更能突出主题,需要注意的是我们通过android:completionThreshold设置了只有输入两个以上文字,才会弹出自动补全框。其他属性可以从官方文档了解一下。
我们的示例主要通过在SQLite中模糊搜索来实现自动补全功能,先看看我们的SQLiteHelper
package com.yjp.autocompletetextviewdemo;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DbHelper extends SQLiteOpenHelper {
//大学表
public static final String SCHOOLS_TABLE_NAME = "table_schools";
public static final String COL_SCHOOL_NAME = "school_name";
private static final String DB_NAME = "auto_complete_text_view_app_db";
private static final int DB_VERSION = 1;
private static final String STRING_CREATE_SCHOOL_TABLE =
"CREATE TABLE " + SCHOOLS_TABLE_NAME + " (_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ COL_SCHOOL_NAME + " TEXT);";
public DbHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(STRING_CREATE_SCHOOL_TABLE);
//伪造一些数据
ContentValues cv = new ContentValues(1);
cv.put(COL_SCHOOL_NAME, "大连理工大学");
db.insert(SCHOOLS_TABLE_NAME, COL_SCHOOL_NAME, cv);
cv.put(COL_SCHOOL_NAME, "太原理工大学");
db.insert(SCHOOLS_TABLE_NAME, COL_SCHOOL_NAME, cv);
cv.put(COL_SCHOOL_NAME, "天津理工大学");
db.insert(SCHOOLS_TABLE_NAME, COL_SCHOOL_NAME, cv);
cv.put(COL_SCHOOL_NAME, "河北工业大学");
db.insert(SCHOOLS_TABLE_NAME, COL_SCHOOL_NAME, cv);
cv.put(COL_SCHOOL_NAME, "天津大学");
db.insert(SCHOOLS_TABLE_NAME, COL_SCHOOL_NAME, cv);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + STRING_CREATE_SCHOOL_TABLE);
}
}
一个很简单的例子,数据库除了_id列只有一列,表示大学,而且我们伪造了一些数据。
然后看看我们需要一个CursorAdapter来给我们的AutoCompleteTextView使用,如下所示
package com.yjp.autocompletetextviewdemo;
import android.content.Context;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.TextView;
public class AutoCompleteAdapter extends CursorAdapter {
public AutoCompleteAdapter(Context context) {
super(context, null, 0);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
TextView view = (TextView) inflater.inflate(
android.R.layout.simple_dropdown_item_1line, parent, false);
return view;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
((TextView) view).setText(cursor.getString(cursor.getColumnIndex(DbHelper.COL_SCHOOL_NAME)));
}
}
依然很简单,我们使用了Android提供的布局,显示我们自动补全的弹出框的行,这也是AutoCompleteTextView默认使用的,如果应用场景不像我这里描述的复杂,只要AutoCompleteTextView调用setAdapter设置一个ArrayAdapter即可,ArrayAdapter关联的数据就会显示在弹出框中。
最后,看看我们的MainActivity
package com.yjp.autocompletetextviewdemo;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AutoCompleteTextView;
import android.widget.FilterQueryProvider;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private AutoCompleteTextView mAutoCompleteTextView;
//一定要使用一个成员变量,不然DbHelper内存回收会导致DB无法使用
private DbHelper mDbHelper;
private SQLiteDatabase mDb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAutoCompleteTextView = (AutoCompleteTextView) findViewById(R.id.auto_complete_text_view);
//实际上设置的是弹出的列表的OnItemClickListener
//另外千万注意,不要使用OnItemSelectedListener
//看源码中该监听器虽然可以设置,但是没有用到
mAutoCompleteTextView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//这里设置文本值,否则默认显示赋值的文本是Cursor的toString()
TextView textView = (TextView) view;
mAutoCompleteTextView.setText(textView.getText());
}
});
AutoCompleteAdapter adapter = new AutoCompleteAdapter(this);
//这里设置FilterQueryProvider可以自定义自己的Cursor创建逻辑
//而不是使用默认设置给Adapter的Cursor,实现动态处理
adapter.setFilterQueryProvider(new FilterQueryProvider() {
@Override
public Cursor runQuery(CharSequence constraint) {
if (constraint == null || constraint.length() == 0) {
return null;
}
//模糊查找,千万加入_id列,否则无法正常使用
return mDb.rawQuery("SELECT _id," + DbHelper.COL_SCHOOL_NAME
+ " FROM " + DbHelper.SCHOOLS_TABLE_NAME
+ " WHERE " + DbHelper.COL_SCHOOL_NAME
+ " LIKE \'%" + constraint.toString() +"%\'", null);
}
});
mAutoCompleteTextView.setAdapter(adapter);
}
@Override
protected void onStart() {
super.onStart();
mDbHelper = new DbHelper(this);
//使用getWritableDatabase,如果表不存在会自动创建
mDb = mDbHelper.getWritableDatabase();
}
@Override
protected void onStop() {
super.onStop();
//资源回收
mDb.close();
mDbHelper.close();
}
}
注释已经尽可能详细了,大家可以看一下,这样,我们就实现了AutoCompleteTextView的自动补全。如下图所示
可以看到,实现了我们最初的设想,另外,从这次使用中,也总结了一些经验,遇到问题,查看官方文档,有些文档中没有写的,自己去尝试。当时遇到问题,点选提示框中的一项时,发现没有显示提示框条目中的内容,而是显示了Cursor的地址信息,很显然是Cursor的toString的结果,所以想到,需要对点选之后的内容进行转换,当时尝试设置OnItemSelectedListener,但是发现没有用处,之后查看AutoCompleteTextView源码才发现,这个监听器,实现中使用一个成员变量保存了,但是没有任何地方调用,不过发现OnItemClickListener被调用,因此改而使用OnItemClickListener。