Android自定義字母索引

 Android字母索引這個功能還是很常見的,例如:電話聯繫人,城市選擇等一些功能都會用到。輪子已造好直接使用, Github源碼 。

先看效果圖:

自定義分析:
1、自定義View用 Paint 畫筆繪製右邊的 [ A - Z ] 

public class SideBarSortView extends View {
    private Canvas mCanvas;
    private int mSelectIndex = 0;
    private float mTextSize;
    private int mTextColor;
    private float mTextSizeChoose;
    private int mTextColorChoose;

    public void setmTextSize(float mTextSize) {
        this.mTextSize = mTextSize;
    }

    public void setmTextColor(int mTextColor) {
        this.mTextColor = mTextColor;
    }

    public void setmTextSizeChoose(float mTextSizeChoose) {
        this.mTextSizeChoose = mTextSizeChoose;
    }

    public void setmTextColorChoose(int mTextColorChoose) {
        this.mTextColorChoose = mTextColorChoose;
    }
    //這裏也可以傳入數組方式
    public static String[] mList = {"A", "B", "C", "D", "E", "F", "G", "H", "I",
            "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
            "W", "X", "Y", "Z","#"};
    public Paint paint = new Paint();
    public SideBarSortView(Context context) {
        super(context);
    }
    public SideBarSortView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        this.mCanvas=canvas;
        paintText();
    }

    private void paintText(){
        //計算每一個字母的高度,總告訴除以字母集合的高度就可以
        int height = (getHeight()) / mList.length;
        for (int i = 0; i < mList.length; i++) {
            if(i==mSelectIndex){
                paint.setColor(mTextColorChoose);
                paint.setTextSize( mTextSizeChoose);
            }else {
                paint.setColor(mTextColor);
                paint.setTextSize( mTextSize);
            }
            paint.setAntiAlias(true);//設置抗鋸齒
            paint.setTypeface(Typeface.DEFAULT_BOLD);
            //計算每一個字母x軸
            float paintX = getWidth() / 2F - paint.measureText(mList[i]) / 2;
            //計算每一個字母Y軸
            int paintY = height * i + height;
            //繪畫出來這個TextView
            mCanvas.drawText(mList[i], paintX, paintY, paint);
            //畫完一個以後重置畫筆
            paint.reset();
        }
    }
}



2、onTouch()事件 實現選中的字母變色、中間高亮字母,並設置回調監聽來聯動Listview的item位置
 

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                int index = (int) (event.getY() / getHeight() * mList.length);
                if (index >= 0 && index < mList.length) {
                    if(mClickListener!=null){
                        //滑動A-Z字母聯動外層數據
                        mClickListener.onSideBarScrollUpdateItem(mList[index]);
                    }
                    mSelectIndex=index;
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                if(mClickListener!=null){
                    mClickListener.onSideBarScrollEndHideText();
                }
                break;
        }
        return true;
    }


3、滑動結束設置隱藏中間高亮字母控件
 

   case MotionEvent.ACTION_UP:
   case MotionEvent.ACTION_CANCEL:
                if(mClickListener!=null){
                    //隱藏高亮文字
                    mClickListener.onSideBarScrollEndHideText();
                }
                break;


4、外層聯動滾動控件(eg:Listview)監聽滑動事件設置右邊字母位置
 

    //自定義字母控件SideBarSortView
    public void onitemScrollUpdateText(String word) {
        for (int i = 0; i < mList.length; i++) {
            if(mList[i].equals(word)&& mSelectIndex != i ){
                mSelectIndex = i;
                invalidate();
            }
        }
    }
  //自定義組合控件SideBarLayout(字母+高亮TextView)
  public void OnItemScrollUpdateText(String word) {
        if(mListener!=null){
            mSortView.onitemScrollUpdateText(word);
        }
    }


然後在 Activity 實現一下Recyclerview聯動使用
(1)xml佈局使用控件

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#FFFFFF"
            android:divider="@null"
            android:overScrollMode="never"
            android:scrollbars="none" />
        //字體顏色、大小爲自定義
        <com.lzj.sidebar.SideBarLayout
            android:id="@+id/sidebar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:sidebarSelectTextColor="@color/hotpink"
            app:sidebarUnSelectTextColor="@color/colorPrimary"
            app:sidebarSelectTextSize="12sp"
            app:sidebarUnSelectTextSize="10sp"
            app:sidebarWordBackground="@drawable/sort_text_bg"
            app:sidebarWordTextColor="@color/darkred"
            app:sidebarWordTextSize="45sp">

        </com.lzj.sidebar.SideBarLayout>
    </FrameLayout>


(2)MainActivity初始化數據,使用pinyin4j:2.5.1進行漢字轉拼音,具體實現根據公司業務來定
(3)RecyclerView實現的聯動,參考如下:

 //側邊欄滑動 --> item
        sidebarView.setSideBarLayout(new SideBarLayout.OnSideBarLayoutListener() {
            @Override
            public void onSideBarScrollUpdateItem(String word) {
                //循環判斷點擊的拼音導航欄和集合中姓名的首字母,如果相同recyclerView就跳轉指定位置
                for (int i = 0; i < mList.size(); i++) {
                    if (mList.get(i).getWord().equals(word)) {
                        recyclerView.smoothScrollToPosition(i);
                        break;
                    }
                }
            }
        });
        //item滑動 --> 側邊欄
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int scrollState) {
                super.onScrollStateChanged(recyclerView, scrollState);
                mScrollState = scrollState;
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (mScrollState != -1) {
                    //第一個可見的位置
                    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
                    //判斷是當前layoutManager是否爲LinearLayoutManager
                    // 只有LinearLayoutManager纔有查找第一個和最後一個可見view位置的方法
                    int firstItemPosition=0;
                    if (layoutManager instanceof LinearLayoutManager) {
                        LinearLayoutManager linearManager = (LinearLayoutManager) layoutManager;
                        //獲取第一個可見view的位置
                        firstItemPosition = linearManager.findFirstVisibleItemPosition();
                    }

                    sidebarView.OnItemScrollUpdateText(mList.get(firstItemPosition).getWord());
                    if (mScrollState == RecyclerView.SCROLL_STATE_IDLE) {
                        mScrollState = -1;
                    }
                }
            }
        });


(4)在EditText輸入框的afterTextChanged()方法實現正則匹配規則,參考如下:
   

 @Override
    public void afterTextChanged(Editable s) {
        if (mList == null || mList.size() <= 0) {
            return;
        }
        String keyWord = s.toString();
        Log.i("test","------------key="+keyWord);
        if (!keyWord.equals("")) {
            if (matcherSearch(keyWord, mList).size() > 0) {
                sidebarView.OnItemScrollUpdateText(matcherSearch(keyWord, mList).get(0).getWord());
            }
            mSortAdaper.setNewData(matcherSearch(keyWord, mList));
            mSortAdaper.notifyDataSetChanged();
        } else {
            sidebarView.OnItemScrollUpdateText(mList.get(0).getWord());
            mSortAdaper.setNewData(mList);
            mSortAdaper.notifyDataSetChanged();
        }
    }
  //正則匹配參考 先首字母
   public List<SortBean> matcherSearch(String keyword, List<SortBean> list) {
        List<SortBean> results = new ArrayList<>();
        String patten = Pattern.quote(keyword);
        Pattern pattern = Pattern.compile(patten, Pattern.CASE_INSENSITIVE);
        for (int i = 0; i < list.size(); i++) {
            //根據首字母
            Matcher matcherWord = pattern.matcher((list.get(i)).getWord());
            //根據拼音
            Matcher matcherPin = pattern.matcher((list.get(i)).getPinyin());
            //根據簡拼
            Matcher matcherJianPin = pattern.matcher((list.get(i)).getJianpin());
            //根據名字
            Matcher matcherName = pattern.matcher((list.get(i)).getName());
            if (matcherWord.find() || matcherPin.find() || matcherName.find() || matcherJianPin.find()) {
                results.add(list.get(i));
            }
        }

        return results;
    }


結尾


各位看官如果本文對你有幫助,請點個贊吧。
Androidx版本,請前往Github源碼。


implementation 'com.github.lzjin:SideBarView:1.0'

 

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