Android 側欄A-Z的快速滑動搜索(三)

前面的兩篇講了快速搜索的側邊#A-Z、側滑的實現。本篇將會實現模糊搜索的效果。實現模糊搜索之前我們還是先實現以下側欄點擊字母的定位效果。當我們點擊側欄字母的時候希望能定位到拼音的首字母是我們所點擊的字母,這一點本來想在前兩篇說但是一想還是跟模糊搜索一塊將吧,都是實現定位到某個位置的。這裏我們會用到一個關於拼音的工具
這裏寫圖片描述
上面的效果圖我們可以看到如果我們的列表裏面首字母含有某個字母的時候,含有相同的首字母只會在第一條數據上面顯示含有的字母標誌,其餘的則不會顯示。這個效果的實現很簡單,我們做佈局的時候其實都是同一個佈局樣式

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:textSize="16dp"
        android:background="#B51421"
        android:textColor="#FFFFFF"
        android:id="@+id/tv_first_alphabet"
        android:visibility="gone"
        android:text="A"/>
    <lyx.robert.quicksearch.view.SwipeLayout
        android:id="@+id/swp_slip"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="16dp"
        android:id="@+id/tv_contact_name"
        android:background="#FFFFFF"
        android:padding="10dp"
        />
        <include layout="@layout/layout_slip"></include>
    </lyx.robert.quicksearch.view.SwipeLayout>
</LinearLayout>

上面的佈局是關於顯示的內容的,我們會發現我們的每個條目是有兩個TextView其中一個是顯示字母的另一個纔是顯示的內容。而我們看到的卻是隻有第一個條目顯示字母,這是因爲我們會判斷,如果當前字母與上一個字母的首字母不相同的話當前條目的字母顯示,否則就要隱藏,這樣我們的效果就出來了,判斷的代碼如下

String currentAlphabet=contactBean.getPinyin().charAt(0)+"";
        if(position>0){
            String lastAlphabet = list.get(position-1).getPinyin().charAt(0)+"";
            //獲取上一個item的首字母

                if(currentAlphabet.equals(lastAlphabet)){
                        //首字母相同,需要隱藏當前item的字母的TextView
                        holder.tv_first_alphabet.setVisibility(View.GONE);
                }else {
                        //不相同就要顯示當前的首字母
                        holder.tv_first_alphabet.setVisibility(View.VISIBLE);
                        holder.tv_first_alphabet.setText(currentAlphabet);
                    }
        }else {
            holder.tv_first_alphabet.setVisibility(View.VISIBLE);
            holder.tv_first_alphabet.setText(currentAlphabet);
        }

下面來說一下我們的模糊搜索,所謂的模糊搜索不過就是當我們不知道全名稱的時候可以輸入一部分來進行搜索。比如張先生,我們可以通過全拼ZHANGXIANSHENG來搜索,也可以通過簡拼ZXS來搜索,不過此搜索不是特別精確,因爲如果你的列表裏面含有的聯繫人含有ZXS也能搜索出來,我們也可以輸入漢字張先生來搜索。我們先來說一下全拼搜索,當然模糊搜索也是離不了拼音工具的

package lyx.robert.quicksearch.utils;

import android.text.TextUtils;

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

public class PinYinUtil {
    /**
     * 獲取漢字的拼音,會銷燬一定的資源,所以不應該被頻繁調用
     * @param chinese
     */
    public static String getPinyin(String chinese){
        if(TextUtils.isEmpty(chinese)) return null;

        //用來設置轉化的拼音的大小寫,或者聲調
        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
        format.setCaseType(HanyuPinyinCaseType.UPPERCASE);//設置轉化的拼音是大寫字母
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);//設置轉化的拼音不帶聲調

        //1.由於只能對單個漢字轉化,所以需要將字符串轉化爲字符數組,然後對每個字符轉化,最後拼接起來
        char[] charArray = chinese.toCharArray();
        String pinyin = "";
        for (int i = 0; i < charArray.length; i++) {
            //2.過濾空格
            if(Character.isWhitespace(charArray[i]))continue;

            //3.需要判斷是否是漢字
            //漢字佔2個字節,一個字節範圍是-128~127,那麼漢字肯定大於127
            if(charArray[i]>127){
                //可能是漢字
                try {
                    //由於多音字的存在,比如單  dan shan,
                    String[] pinyinArr = PinyinHelper.toHanyuPinyinStringArray(charArray[i],format);
                    if(pinyinArr!=null){
                        pinyin += pinyinArr[0];//此處即使有多音字,那麼也只能取第一個拼音
                    }else {
                        //說明沒有找到對應的拼音,漢字有問題,或者可能不是漢字,則忽略
                    }
                } catch (BadHanyuPinyinOutputFormatCombination e) {
                    e.printStackTrace();
                    //說明轉化失敗,不是漢字,比如O(∩_∩)O~,那麼則忽略
                }
            }else {
                //肯定不是漢字,應該是鍵盤上能夠直接輸入的字符,這些字符能夠排序,但不能獲取拼音
                //所以可以直接拼接
                pinyin += charArray[i];
            }
        }
        return pinyin;
    }

}

根據上面的工具我們可以獲取列表裏面的每個聯繫人的拼音的全拼,全拼很簡單。那麼簡拼又是如何實現的呢?簡拼就是獲取每個名字的每個字的首字母,我們可以根據每個名字的長度,循環取出名字裏面的每個字的拼音,然後獲取拼音的第一個字母即可

public PinYinStyle parsePinYinStyle(String content) {
        PinYinStyle pinYinStyle = new PinYinStyle();
        if (content != null && content.length() > 0) {
            //其中包含的中文字符
            String[] enStrs = new String[content.length()];
            for (int i=0;i<content.length();i++){
                enStrs[i] = PinYinUtil.getPinyin(String.valueOf(content.charAt(i)));
            }
            for (int i = 0, length = enStrs.length; i < length; i++) {
                if (enStrs[i].length() > 0) {
                    //拼接簡拼
                    pinYinStyle.briefnessSpell += enStrs[i].charAt(0);
                }
            }
        }
        return pinYinStyle;
    }

剩下的就是關於懸浮提示的實現了。懸浮提示就是根據我們點擊的某個字母然後將首字母以我們點擊的字母開頭的依次顯示出來。

for (int i = 0; i < contactList.size(); i++) {
                    String firstAlphabet = contactList.get(i).getPinyin().toString().trim().charAt(0)+"";

                    if(letter.equals(firstAlphabet)){
                        //說明找到了,那麼應該講當前的item放到屏幕頂端
                        tv_notice.setText(letter);
                        if(!alphabetList.contains(String.valueOf(contactList.get(i).getName().trim().charAt(0)))){
                            alphabetList.add(String.valueOf(contactList.get(i).getName().trim().charAt(0)));
                        }
                    }

MainActivity.class

package lyx.robert.quicksearch.activities;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.nineoldandroids.view.ViewPropertyAnimator;

import lyx.robert.quicksearch.Bean.ContactBean;
import lyx.robert.quicksearch.adapter.ContactAdapter;
import lyx.robert.quicksearch.utils.PinYinUtil;
import lyx.robert.quicksearch.view.SideLetterBar;
import lyx.robert.quicksearch.R;
import lyx.robert.quicksearch.Bean.PinYinStyle;
import lyx.robert.quicksearch.utils.SwipeManager;
import lyx.robert.quicksearch.adapter.AlphabetAdp;
import lyx.robert.quicksearch.view.ClearEditText;


public class MainActivity extends Activity {
    private SideLetterBar sideLetterBar;
    private ListView lv_contact;
    private ListView lv_alphabet;
    private TextView tv_alphabet;
    private TextView tv_notice;
    private ClearEditText et_clear;
    private List<String>alphabetList;
    RelativeLayout rel_notice;
    ContactAdapter adapter ;
    private String[] data = new String[] {
            "15129372345","15129372334","15129372335","15129372343","15129372347","151293723423",
            //A
            "安先生", "敖先生", "艾先生", "愛先生",
            //B
            "巴先生", "白先生", "鮑先生","包先生", "班先生", "畢先生","邊先生", "卞先生", "薄先生",
            //C
            "蔡先生", "岑先生", "曹先生","陳先生", "程先生", "褚先生","昌先生", "車先生", "常先生",
            //D
            "戴先生", "狄先生", "竇先生","董先生", "杜先生","杜先生","杜先生", "丁先生","鄧先生", "段先生", "黨先生",
            //E
            "鄂先生",
            //F
            "費先生", "範先生","樊先生", "方先生", "房先生","豐先生", "封先生", "馮先生","法先生",
            //G
            "蓋先生", "甘先生", "高先生"," 葛先生", "耿先生", "古先生","顧先生", "關先生", "郭先生",
            //H
            "海先生", "郝先生", "韓先生","何先生", "賀先生", "胡先生","扈先生", "黃先生", "華先生",
            //J
            "姬先生", "季先生", "紀先生","金先生", "焦先生", "姜先生","賈先生", "郟先生", "靳先生",
            //K
            "寇先生", "孔先生", "康先生","柯先生", "況先生", "亢先生","夔先生", "蒯先生", "隗先生",
            //L
            "李先生", "郎先生", "魯先生","柳先生", "雷先生", "劉先生","林先生", "藍先生", "呂先生",
            //M
            "馬先生", "滿先生", "苗先生","穆先生", "毛先生", "麻先生","孟先生", "梅先生", "莫先生",
            //N
            "那先生", "能先生", "倪先生","年先生", "寧先生", "聶先生","牛先生", "農先生", "聶先生",
            //O
            "歐先生", "歐陽先生",
            //P
            "潘先生", "龐先生", "裴先生","彭先生", "皮先生", "濮先生","蓬先生", "逄先生", "浦先生",
            //Q
            "戚先生", "齊先生", "祁先生","喬先生", "屈先生", "錢先生","秦先生", "邱先生", "裘先生",
            //R
            "冉先生", "饒先生", "任先生","阮先生", "芮先生", "戎先生","容先生", "榮先生", "融先生",
            //S
            "宋先生", "舒先生", "蘇先生","孫先生", "索先生", "沈先生","邵先生", "施先生", "石先生",
            //T
            "邰先生", "譚先生", "陶先生","唐先生", "湯先生", "田先生","佟先生", "屠先生", "滕先生",
            //W
            "萬先生", "鄔先生", "烏先生","吳先生", "伍先生", "武先生","王先生", "韋先生", "魏先生",
            //X
            "奚先生", "席先生", "習先生","夏先生", "蕭先生", "熊先生","項先生", "徐先生", "許先生",
            //Y
            "燕先生", "鄢先生", "顏先生","閆先生", "閻先生", "晏先生","姚先生", "楊先生", "葉先生",
            //Z
            "翟先生", "張先生", "章先生","趙先生", "甄先生", "曾先生","周先生", "鄭先生", "祝先生",
            };

    private ArrayList<ContactBean> contactList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        contactList = dataList();
        //2.對數據進行排序
        initView();
        initEvent();
        initData();
    }
    private void initView() {
        sideLetterBar = (SideLetterBar) findViewById(R.id.sideLetterBar);
        lv_contact = (ListView) findViewById(R.id.lv_contact);
        lv_alphabet = (ListView) findViewById(R.id.lv_alphabet);
        tv_notice = (TextView) findViewById(R.id.tv_notice);
        rel_notice = (RelativeLayout) findViewById(R.id.rel_notice);
        et_clear = (ClearEditText) findViewById(R.id.et_clear);
        tv_alphabet = (TextView) findViewById(R.id.tv_alphabet);
        rel_notice.post(new Runnable() {
            @Override
            public void run() {
                tv_notice.getHeight();
                RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) rel_notice.getLayoutParams();
                params.height = tv_notice.getHeight()*5;
                params.width = tv_notice.getWidth();
                rel_notice.setLayoutParams(params);
            }
        });
    }
    private void initEvent() {
        sideLetterBar.setOnTouchLetterListener(new SideLetterBar.OnTouchLetterListener() {
            @Override
            public void onTouchLetter(String letter) {
                alphabetList.clear();
                ViewPropertyAnimator.animate(rel_notice).alpha(1f).setDuration(0).start();
                //根據當前觸摸的字母,去集合中找那個item的首字母和letter一樣,然後將對應的item放到屏幕頂端
                for (int i = 0; i < contactList.size(); i++) {
                    String firstAlphabet = contactList.get(i).getPinyin().charAt(0)+"";
                    if(letter.equals(firstAlphabet)){
                        lv_contact.setSelection(i);
                        rel_notice.setVisibility(View.VISIBLE);
                        break;
                    }
                    if(letter.equals("#")){
                        lv_contact.setSelection(0);
                        rel_notice.setVisibility(View.GONE);
                    }
                }
                for (int i = 0; i < contactList.size(); i++) {
                    String firstAlphabet = contactList.get(i).getPinyin().toString().trim().charAt(0)+"";

                    if(letter.equals(firstAlphabet)){
                        //說明找到了,那麼應該講當前的item放到屏幕頂端
                        tv_notice.setText(letter);
                        if(!alphabetList.contains(String.valueOf(contactList.get(i).getName().trim().charAt(0)))){
                            alphabetList.add(String.valueOf(contactList.get(i).getName().trim().charAt(0)));
                        }
                    }

                }
                showCurrentWord(letter);
                //顯示當前觸摸的字母

                AlphabetAdp alphabetAdp = new AlphabetAdp(MainActivity.this,alphabetList);
                lv_alphabet.setAdapter(alphabetAdp);
                alphabetAdp.notifyDataSetChanged();
            }
        });
        lv_contact.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView absListView, int scrollState) {
                if(scrollState== AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL){
                    //如果垂直滑動,則需要關閉已經打開的layout
                    SwipeManager.getInstance().closeCurrentLayout();
                }

            }

            @Override
            public void onScroll(AbsListView absListView, int firstVisibleItem,
                                 int visibleItemCount, int totalItemCount) {
                int pos = lv_contact.getFirstVisiblePosition();
                if (contactList.size()>0){
                    tv_alphabet.setVisibility(View.VISIBLE);
                    String text = contactList.get(pos).getPinyin().charAt(0)+"";
                    Pattern p = Pattern.compile("[0-9]*");
                    Matcher m1 = p.matcher(text);
                    if(m1.matches()){
                        tv_alphabet.setText("#");
                    }else {
                        tv_alphabet.setText(text);
                    }
                }else {
                    tv_alphabet.setVisibility(View.GONE);
                }
            }
        });
        et_clear.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                //當輸入框裏面的值爲空,更新爲原來的列表,否則爲過濾數據列表
                fuzzySearch(s.toString());
            }

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

            }

            @Override
            public void afterTextChanged(Editable s) {
            }
        });
        lv_alphabet.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
                String alphabet = alphabetList.get(position).trim();
                setIsVisiable();
                for (int i = 0;i<contactList.size();i++){
                    if (alphabet.equals(String.valueOf(contactList.get(i).getName().trim().charAt(0)))){
                        int pos = i%lv_contact.getChildCount();
                        int childCount = lv_contact.getChildCount();
                        if(position==0&&pos-position==1||childCount-pos==1){
                            lv_contact.setSelection(i);
                        }else {
                            lv_contact.setSelection(i-1);
                        }
                        break;
                    }
                }
            }
        });
    }
    private void initData() {

        //3.設置Adapter
        adapter = new ContactAdapter(this,contactList);
        lv_contact.setAdapter(adapter);
        alphabetList = new ArrayList<>();
    }

    protected void showCurrentWord(String letter) {
        tv_notice.setText(letter);
        setIsVisiable();
    }
    private Handler handler = new Handler();
    private void setIsVisiable(){
        handler.removeCallbacksAndMessages(null);
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                ViewPropertyAnimator.animate(rel_notice).alpha(0f).setDuration(1000).start();
            }
        }, 4000);
}
    private ArrayList <ContactBean> dataList() {
        // 虛擬數據
        ArrayList <ContactBean> mSortList = new ArrayList<ContactBean>();
        for(int i=0;i<data.length;i++){
            ContactBean bean = new ContactBean(data[i]);
            bean.pinYinStyle = parsePinYinStyle(data[i]);
            mSortList.add(bean);
        }
        Collections.sort(mSortList);
        return mSortList;
    }
    private void fuzzySearch(String str) {
        ArrayList<ContactBean> filterDateList = new ArrayList<ContactBean>();
        // 虛擬數據
        if (TextUtils.isEmpty(str)){
            sideLetterBar.setVisibility(View.VISIBLE);
            filterDateList = dataList();
        }else {
            filterDateList.clear();
            sideLetterBar.setVisibility(View.GONE);
            for(ContactBean contactBean : dataList()){
                String name = contactBean.getName();
                Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
                Matcher m = p.matcher(str);
                if(m.matches()){
                    str = PinYinUtil.getPinyin(str);
                }
                if(PinYinUtil.getPinyin(name).contains(str.toUpperCase())|| contactBean.pinYinStyle.briefnessSpell.toUpperCase().contains(str.toUpperCase())
                        || contactBean.pinYinStyle.completeSpell.toUpperCase().contains(str.toUpperCase())){
                    filterDateList.add(contactBean);
                }
            }
        }
        contactList = filterDateList;
        adapter = new ContactAdapter(this,filterDateList);
        lv_contact.setAdapter(adapter);
        adapter.notifyDataSetChanged();
    }
    public PinYinStyle parsePinYinStyle(String content) {
        PinYinStyle pinYinStyle = new PinYinStyle();
        if (content != null && content.length() > 0) {
            //其中包含的中文字符
            String[] enStrs = new String[content.length()];
            for (int i=0;i<content.length();i++){
                enStrs[i] = PinYinUtil.getPinyin(String.valueOf(content.charAt(i)));
            }
            for (int i = 0, length = enStrs.length; i < length; i++) {
                if (enStrs[i].length() > 0) {
                    //拼接簡拼
                    pinYinStyle.briefnessSpell += enStrs[i].charAt(0);
                }
            }
        }
        return pinYinStyle;
    }
}

點擊前往csdn下載源碼

點擊前往GitHub下載源碼

帥哥/美女,如果對您有幫助在GitHub上面點下star唄哦!再csdn上面給個好評也行啊!也不枉費我忙活了這些時間了。謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章