仿微信通訊錄字母排序列表

先看下效果圖


Gif_20180425_103334.gif

在這里我們先分析下效果,左邊是一個(gè)按照字母排序的并有子列表,右邊是直接一個(gè)字母的排列,屏幕中間有一個(gè)顯示你點(diǎn)擊了右邊的那個(gè)字母的顯示。
在這里我們先去處理右邊的字母列表。我們先去自定義一個(gè)view,把26個(gè)字母和“#”放到一個(gè)數(shù)組里面,再用畫(huà)筆在ondraw()里面畫(huà)出來(lái)。

   @Override
    protected void onDraw(Canvas canvas) {
        // 畫(huà)26個(gè)字母

        int itemHeight = (getHeight() - getPaddingTop() - getPaddingBottom()) / mLetters.length;

        for (int i = 0; i < mLetters.length; i++) {
            // 知道每個(gè)字母的中心位置  1  字母的高度一半   2 字母高度一般+前面字符的高度
            int letterCenterY = i * itemHeight + itemHeight / 2 + getPaddingTop();
            // 基線,基于中心位置, 知道中心位置還不會(huì)基線,看一下之前的視頻
            Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
            int dy = (int) ((fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom);
            int baseLine = letterCenterY + dy;
            // x 繪制在最中間 = 寬度/2 - 文字/2
            int textWidth = (int) mPaint.measureText(mLetters[i]);
            int x = getWidth() / 2 - textWidth / 2;
            if (!isUp){
                // 當(dāng)前字母 高亮  用兩個(gè)畫(huà)筆(最好) 改變顏色
                if (mLetters[i].equals(mCurrentTouchLetter)) {
                    mPaint.setColor(Color.RED);
                    canvas.drawText(mLetters[i], x, baseLine, mPaint);
                } else {
                    mPaint.setColor(Color.BLUE);
                    canvas.drawText(mLetters[i], x, baseLine, mPaint);
                }
            }else {
                mPaint.setColor(Color.BLUE);
                canvas.drawText(mLetters[i], x, baseLine, mPaint);
            }

        }
    }

當(dāng)我們?cè)谶@個(gè)字母列表上面滑動(dòng)的時(shí)候,被點(diǎn)擊到的字母會(huì)變色,這就需要有兩個(gè)顏色的畫(huà)筆去分別畫(huà)不同的字母。
我們可以在onTouchEvent方法里面拿到按下和滑動(dòng)的事件,在MotionEvent.ACTION_DOWN和MotionEvent.ACTION_MOVE的時(shí)候處理字母的變色。我們首先得那個(gè)我們點(diǎn)擊的是哪個(gè)字母,我們可以拿到當(dāng)前點(diǎn)擊位置的y方向的距離去除以每個(gè)字母的高度,然后取整就知道那個(gè)字母被點(diǎn)擊了,這時(shí)候調(diào)用invalidate方法去重新繪制字母列表,這樣就可以實(shí)現(xiàn)當(dāng)那個(gè)字母被點(diǎn)擊或者是滑動(dòng)時(shí)被覆蓋的字母變色的效果。然后在這里我們寫(xiě)一個(gè)回調(diào),去讓頁(yè)面中間的那個(gè)textview知道如何去顯示那個(gè)字母被點(diǎn)擊了。

  @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
          case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                // 計(jì)算出當(dāng)前觸摸字母  獲取當(dāng)前的位置
                float currentMoveY = event.getY();
                // 位置 = currentMoveY / 字母高度 , 通過(guò)位置獲取字母  優(yōu)化?
                int itemHeight = (getHeight() - getPaddingTop() - getPaddingBottom()) / mLetters.length;
                currentPosition = (int) (currentMoveY / itemHeight);

                if (currentPosition < 0)
                    currentPosition = 0;

                if (currentPosition > mLetters.length - 1)
                    currentPosition = mLetters.length - 1;

                // 要判斷 ?

                mCurrentTouchLetter = mLetters[currentPosition];

                if (mListener != null) {
                    mListener.touch(mCurrentTouchLetter, true, currentPosition);
                }
                isUp = false;
                // 重新繪制
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                if (mListener != null) {
                    mListener.touch(mCurrentTouchLetter, false, currentPosition);
                }
                isUp = true;
                // 重新繪制
                invalidate();
                break;
        }
        return true;
    }


    private LetterTouchListener mListener;

    public void setOnLetterTouchListener(LetterTouchListener listener) {
        this.mListener = listener;
    }

    // 接口回掉其他View會(huì)不會(huì)使用?
    public interface LetterTouchListener {
        void touch(CharSequence letter, boolean isTouch,int currentPosition);
    }

我們ManActivity的布局文件是這樣的

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"

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

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_letter"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

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


    <TextView
        android:id="@+id/letter_tv"
        android:layout_width="wrap_content"
        android:layout_centerInParent="true"
        android:text="A"
        android:visibility="gone"
        android:textSize="16sp"
        android:textColor="#FF0000"
        android:layout_height="wrap_content" />

    <com.example.letterlist.LetterSideBar
        android:id="@+id/letter_side_bar"
        android:layout_width="wrap_content"
        android:layout_alignParentRight="true"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:layout_height="match_parent" />
    </RelativeLayout>
</FrameLayout>

在ManActivity里面我們給RecyclerView添加數(shù)據(jù),先給RecyclerView添加字母列表,在RecyclerView的布局文件在添加一個(gè)子RecyclerView。

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

        android:id="@+id/tv_text"
        android:textSize="15sp"
        android:background="#9999"
        android:textColor="#fff"
        android:layout_width="match_parent"
        android:layout_height="50dp" />
    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_child"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

給子RecyclerView添加數(shù)據(jù)之后,在會(huì)掉里面,當(dāng)右邊的列表那個(gè)被惦記了,就將父RecyclerView的那個(gè)對(duì)應(yīng)位置的條目滾動(dòng)到頂部,這樣效果就實(shí)現(xiàn)了

   @Override
    public void touch(CharSequence letter,boolean isTouch,int current) {
        if(isTouch) {
            mLetterTv.setVisibility(View.VISIBLE);
            mLetterTv.setText(letter);
            rvLetter.scrollToPosition(current);
            //讓RecyclerView滾動(dòng)到頂部
            if (current != -1) {
                rvLetter.scrollToPosition(current);
                LinearLayoutManager mLayoutManager =
                        (LinearLayoutManager) rvLetter.getLayoutManager();
                mLayoutManager.scrollToPositionWithOffset(current, 0);
            }

        }else{
            mLetterTv.setVisibility(View.GONE);

        }
    }

項(xiàng)目已經(jīng)放到github上面:https://github.com/chenzhikaizg/LetterListView

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容