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'

 

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