android通過拼音搜尋中文的功能實現程式碼
好幾年沒寫部落格了,很多知識不記是真的會忘記,以後還是保持寫部落格的習慣吧。堅持不一定成功,但放棄一定很舒服!(開玩笑(#^.^#))
迴歸正題,今天我要記錄的是拼音搜尋功能,我記得16年的時候做過這個功能。現在已經忘記很多細節了,所以這次好好寫一寫!
第一步:準備
- 第三方包——中文轉拼音,pinyin4j-2.5.0.jar,官網http://pinyin4j.sourceforge.net/
- Filterable.java 過濾介面
第二步:分析功能並實現
- 很明顯,這是兩個功能,一個是中文轉拼音,一個是查詢過濾
- 下面我們先實現主要功能,查詢過濾
- 建立佈局檔案 activity_main.xml,實現如下:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" android:padding="16dp"> <EditText android:id="@+id/etSearchName" android:layout_width="match_parent" android:layout_height="50dp" android:hint="請輸入拼音" android:padding="5dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" app:layout_constraintTop_toBottomOf="@+id/etSearchName" /> </androidx.constraintlayout.widget.ConstraintLayout>
就一個搜尋框和列表控制元件
接著建立列表介面卡 SearchAdapter.java,實現了過濾器類Filterable
public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.MyViewHolder> implements Filterable { private Context context; private List<String> list; //儲存原有的資料 private List<String> originalList; private OnItemListener onItemListener; void setOnItemListener(OnItemListener onItemListener){ this.onItemListener = onItemListener; } private SearchFilter filter; SearchAdapter(Context context,List<String> list){ this.context =context; this.list = list; originalList = list; } @NonNull @Override public SearchAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent,int viewType) { View view = LayoutInflater.from(context).inflate(R.layout.item_rv_search,parent,false); return new MyViewHolder(view); } @Override public void onBindViewHolder(@NonNull SearchAdapter.MyViewHolder holder,final int position) { holder.tvName.setText(list.get(position)); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (onItemListener!=null){ onItemListener.onItem(list.get(position)); } } }); } @Override public int getItemCount() { return list==null?0:list.size(); } @Override public Filter getFilter() { if (filter==null){ filter = new SearchFilter(); } return filter; } class MyViewHolder extends RecyclerView.ViewHolder{ private TextView tvName; MyViewHolder(@NonNull View itemView) { super(itemView); tvName = itemView.findViewById(R.id.tvName); } } interface OnItemListener{ void onItem(String name); } class SearchFilter extends Filter{ @Override protected FilterResults performFiltering(CharSequence constraint) { //輸入框傳來的資料 constraint //用於儲存過濾的結果 FilterResults filterResults = new FilterResults(); if (constraint==null || constraint.length()==0){ filterResults.values = originalList; filterResults.count = originalList.size(); }else { List<String> fList = new ArrayList<>(); String cons = constraint.toString().trim().toLowerCase(); for (String s : originalList) { //從首位開始匹配 if (s.startsWith(cons)){ fList.add(s); } } filterResults.values = fList; filterResults.count = fList.size(); } return filterResults; } @Override protected void publishResults(CharSequence constraint,FilterResults results) { list = (List<String>) results.values; notifyDataSetChanged(); } } }
這段程式碼,重點是SearchFilter類的兩個方法
- performFiltering(CharSequence constraint) 接收輸入資料,在這個方法實現處理邏輯
- publishResults(CharSequence constraint,FilterResults results) 接收過濾後的結果
注意點:originalList 這個集合是用來儲存原有資料的。因為list會隨著搜尋結果而變化,我們每次的過濾都是需要用到原有的資料。
介面卡寫好了,下面看看怎麼使用它
private RecyclerView recyclerView; private SearchAdapter adapter; private List<String> list; private EditText etSearchName; public static final String[] str = new String[]{ "陳天麗","黃正","徐明","李自成","林子祥","周星星","周潤發","林星辰","林青霞","李賽鳳","劉德華","胡歌","霍建華","林心如","趙薇","趙四","趙本山","郭德綱" }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); etSearchName = findViewById(R.id.etSearchName); recyclerView = findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(this)); list = new ArrayList<>(); list.addAll(Arrays.asList(str)); adapter = new SearchAdapter(this,list); recyclerView.setAdapter(adapter); adapter.setOnItemListener(new SearchAdapter.OnItemListener() { @Override public void onItem(String name) { etSearchName.setText(name); } }); etSearchName.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s,int start,int count,int after) { } @Override public void onTextChanged(CharSequence s,int before,int count) { adapter.getFilter().filter(etSearchName.getText().toString().trim()); } @Override public void afterTextChanged(Editable s) { } }); }
一頓RecyclerView的常規操作
這裡需要注意的是這段程式碼adapter.getFilter().filter(etSearchName.getText().toString().trim()); 這裡就呼叫了我們寫好的過濾器。
到此,我們的搜尋過濾功能已經實現了。
看看執行效果:
接下來說說中文轉拼音
首先需要修改資料來源型別
- 之前的資料來源只是String集合,現在加了拼音,那就不能只用String了。建個實體UserName,欄位有pinyin和name;
- 通過pinyin4j.jar包把中文轉成拼音,然後儲存到UserName集合,程式碼如下:
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);//不顯示音標 format.setVCharType(HanyuPinyinVCharType.WITH_V);//“ü”輸出V format.setCaseType(HanyuPinyinCaseType.LOWERCASE);//拼音輸出小寫 userNameList = new ArrayList<>(); for (String name : list) { StringBuffer stringBuffer = new StringBuffer(); for (int j=0;j<name.length();j++){ char c = name.charAt(j); String[] cStrHY = new String[0]; try { cStrHY = PinyinHelper.toHanyuPinyinStringArray(c,format); } catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) { badHanyuPinyinOutputFormatCombination.printStackTrace(); } stringBuffer.append(cStrHY[0]); } UserName userName = new UserName(); userName.setPinyin(stringBuffer.toString()); userName.setName(name); userNameList.add(userName); }
PinyinHelper類有很多轉換的方法,我選擇了toHanyuPinyinStringArray,將單個字元轉成拼音
值得注意的是,HanyuPinyinOutputFormat類,可以用你輸出不同的拼音格式
setToneType 設定音標的顯示方式:
HanyuPinyinToneType.WITH_TONE_MARK:在拼音字母上顯示音標,如“zhòng”
HanyuPinyinToneType.WITH_TONE_NUMBER:在拼音字串後面通過數字顯示,如“zhong4”
HanyuPinyinToneType.WITHOUT_TONE:不顯示音標
setCaseType 設定拼音大小寫:
HanyuPinyinCaseType.LOWERCASE:返回的拼音為小寫字母
HanyuPinyinCaseType.UPPERCASE:返回的拼音為大寫字母
setVCharType 設定拼音字母“ü”的顯示方式
漢語拼音中的“ü”不能簡單的通過英文來表示,所以需要單獨定義“ü”的顯示格式
HanyuPinyinVCharType.WITH_U_UNICODE:預設的顯示方式,輸出“ü”
HanyuPinyinVCharType.WITH_V:輸出“v”
HanyuPinyinVCharType.WITH_U_AND_COLON:輸出“u:”
所以過濾的判斷需要改一下,程式碼如下:
List<UserName> fList = new ArrayList<>(); String cons = constraint.toString().trim().toLowerCase(); for (UserName userName : originalList) { //從首位開始匹配 if (userName.getPinyin().startsWith(cons)){ fList.add(userName); } } filterResults.values = fList; filterResults.count = fList.size();
看看執行效果:
總結:
這個拼音搜尋功能還有待改進
1、拼音搜尋的準確性,比如王重陽(wangzhongyang,wangchongyang)其實應該有兩種讀音,但是我現在專案只做了一種。
後續有時間再補吧,專案地址:https://github.com/tongtian00/CustonSearch
到此這篇關於android通過拼音搜尋中文的功能實現程式碼的文章就介紹到這了,更多相關android搜尋中文內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!