溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android怎么實(shí)現(xiàn)字母導(dǎo)航控件

發(fā)布時間:2022-01-19 16:47:03 來源:億速云 閱讀:162 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“Android怎么實(shí)現(xiàn)字母導(dǎo)航控件”,在日常操作中,相信很多人在Android怎么實(shí)現(xiàn)字母導(dǎo)航控件問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Android怎么實(shí)現(xiàn)字母導(dǎo)航控件”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

自定義完成之后能夠達(dá)到的功能如下:

  • 完成列表數(shù)據(jù)與字母之間的相互聯(lián)動;

  • 支持布局文件屬性配置;

  • 在布局文件中能夠配置相關(guān)屬性,如字母顏色、字母字體大小、字母指示器顏色等屬性。

自定義屬性

在 value 下面創(chuàng)建 attr.xml ,在里面配置需要自定義的屬性,具體如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="LetterView">
        <!--字母顏色-->
        <attr name="letterTextColor" format="color" />
        <!--字母字體大小-->
        <attr name="letterTextSize" format="dimension" />
        <!--整體背景-->
        <attr name="letterTextBackgroundColor" format="color" />
        <!--是否啟用指示器-->
        <attr name="letterEnableIndicator" format="boolean" />
        <!--指示器顏色-->
        <attr name="letterIndicatorColor" format="color" />
    </declare-styleable>
</resources>

然后在相應(yīng)的構(gòu)造方法中獲取這些屬性并進(jìn)行相關(guān)屬性的設(shè)置,具體如下:

public LetterView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    //獲取屬性
    TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.LetterView);
    int letterTextColor = array.getColor(R.styleable.LetterView_letterTextColor, Color.RED);
    int letterTextBackgroundColor = array.getColor(R.styleable.LetterView_letterTextBackgroundColor, Color.WHITE);
    int letterIndicatorColor = array.getColor(R.styleable.LetterView_letterIndicatorColor, Color.parseColor("#333333"));
    float letterTextSize = array.getDimension(R.styleable.LetterView_letterTextSize, 12);
    enableIndicator = array.getBoolean(R.styleable.LetterView_letterEnableIndicator, true);

    //默認(rèn)設(shè)置
    mContext = context;
    mLetterPaint = new Paint();
    mLetterPaint.setTextSize(letterTextSize);
    mLetterPaint.setColor(letterTextColor);
    mLetterPaint.setAntiAlias(true);

    mLetterIndicatorPaint = new Paint();
    mLetterIndicatorPaint.setStyle(Paint.Style.FILL);
    mLetterIndicatorPaint.setColor(letterIndicatorColor);
    mLetterIndicatorPaint.setAntiAlias(true);

    setBackgroundColor(letterTextBackgroundColor);

    array.recycle();
}

Measure測量

要想精確的控制自定義的尺寸以及坐標(biāo),必須要測量出當(dāng)前自定義 View 的寬高,然后才可以通過測量到的尺寸計(jì)算相關(guān)坐標(biāo),具體測量過程就是繼承 View 重寫 omMeasure() 方法完成測量,關(guān)鍵代碼如下:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    //獲取寬高的尺寸大小
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    //wrap_content默認(rèn)寬高
    @SuppressLint("DrawAllocation") Rect mRect = new Rect();
    mLetterPaint.getTextBounds("A", 0, 1, mRect);
    mWidth = mRect.width() + dpToPx(mContext, 12);
    int mHeight = (mRect.height() + dpToPx(mContext, 5)) * letters.length;

    if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT &&
            getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
        setMeasuredDimension(mWidth, mHeight);
    } else if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) {
        setMeasuredDimension(mWidth, heightSize);
    } else if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
        setMeasuredDimension(widthSize, mHeight);
    }

    mWidth = getMeasuredWidth();
    int averageItemHeight = getMeasuredHeight() / 28;
    int mOffset = averageItemHeight / 30; //界面調(diào)整
    mItemHeight = averageItemHeight + mOffset;
}

坐標(biāo)計(jì)算

自定義 View 實(shí)際上就是在 View 上找到合適的位置,將自定義的元素有序的繪制出來即可,繪制過程最困難的就是如何根據(jù)具體需求計(jì)算合適的左邊,至于繪制都是 API 的調(diào)用,只要坐標(biāo)位置計(jì)算好了,自定義 View 繪制這一塊應(yīng)該就沒有問題了,下面的圖示主要是標(biāo)注了字母指示器繪制的中心位置坐標(biāo)的計(jì)算以及文字繪制的起點(diǎn)位置計(jì)算,繪制過程中要保證文字在指示器中心位置,參考如下:

Android怎么實(shí)現(xiàn)字母導(dǎo)航控件

繪制

自定義 View 的繪制操作都是在 onDraw() 方法中進(jìn)行的,這里主要使用到圓的繪制以及文字的繪制,具體就是 drawCircle() 和 drawText() 方法的使用,為避免文字被遮擋,需繪制字母指示器,然后再繪制字母,代碼參考如下:

@Override
protected void onDraw(Canvas canvas) {
    //獲取字母寬高
    @SuppressLint("DrawAllocation") Rect rect = new Rect();
    mLetterPaint.getTextBounds("A", 0, 1, rect);
    int letterWidth = rect.width();
    int letterHeight = rect.height();

    //繪制指示器
    if (enableIndicator){
        for (int i = 1; i < letters.length + 1; i++) {
            if (mTouchIndex == i) {
                canvas.drawCircle(0.5f * mWidth, i * mItemHeight - 0.5f * mItemHeight, 0.5f * mItemHeight, mLetterIndicatorPaint);
            }
        }
    }
    //繪制字母
    for (int i = 1; i < letters.length + 1; i++) {
        canvas.drawText(letters[i - 1], (mWidth - letterWidth) / 2, mItemHeight * i - 0.5f * mItemHeight + letterHeight / 2, mLetterPaint);
    }
}

到此為止,可以說 View 的基本繪制結(jié)束了,現(xiàn)在使用自定義的 View 界面能夠顯示出來了,只是還沒有添加相關(guān)的事件操作,下面將在 View 的觸摸事件里實(shí)現(xiàn)相關(guān)邏輯。

Touch事件處理

為了判斷手指當(dāng)前所在位置對應(yīng)的是哪一個字母,需要獲取當(dāng)前觸摸的坐標(biāo)位置來計(jì)算字母索引,重新 onTouchEvent() 方法,監(jiān)聽 MotionEvent.ACTION_DOWN、MotionEvent.ACTION_MOVE 來計(jì)算索引位置,監(jiān)聽 MotionEvent.ACTION_UP 將獲得結(jié)果回調(diào)出去,具體參考如下:

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:
            isTouch = true;
            int y = (int) event.getY();
            Log.i("onTouchEvent","--y->" + y + "-y-dp-->" + DensityUtil.px2dp(getContext(), y));
            int index = y / mItemHeight;

            if (index != mTouchIndex && index < 28 && index > 0) {
                mTouchIndex = index;
                Log.i("onTouchEvent","--mTouchIndex->" + mTouchIndex + "--position->" + mTouchIndex);
            }

            if (mOnLetterChangeListener != null && mTouchIndex > 0) {
                mOnLetterChangeListener.onLetterListener(letters[mTouchIndex - 1]);
            }

            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            isTouch = false;
            if (mOnLetterChangeListener != null && mTouchIndex > 0) {
                mOnLetterChangeListener.onLetterDismissListener();
            }
            break;
    }
    return true;
}

到此為止,View 的自定義關(guān)鍵部分基本完成。

數(shù)據(jù)組裝

字母導(dǎo)航的基本思路是將某個需要與字母匹配的字段轉(zhuǎn)換為對應(yīng)的字母,然后按照該字段對數(shù)據(jù)進(jìn)行排序,最終使得通過某個數(shù)據(jù)字段的首字母就可以批匹配到相同首字母的數(shù)據(jù)了,這里將漢字轉(zhuǎn)化為拼音使用的是 pinyin4j-2.5.0.jar ,然后對數(shù)據(jù)項(xiàng)按照首字母進(jìn)行排序?qū)?shù)據(jù)展示到出來即可,漢字裝換為拼音如下:

//漢字轉(zhuǎn)換為拼音
public static String getChineseToPinyin(String chinese) {
    StringBuilder builder = new StringBuilder();
    HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
    format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
    format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);

    char[] charArray = chinese.toCharArray();
    for (char aCharArray : charArray) {
        if (Character.isSpaceChar(aCharArray)) {
            continue;
        }
        try {
            String[] pinyinArr = PinyinHelper.toHanyuPinyinStringArray(aCharArray, format);
            if (pinyinArr != null) {
                builder.append(pinyinArr[0]);
            } else {
                builder.append(aCharArray);
            }
        } catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {
            badHanyuPinyinOutputFormatCombination.printStackTrace();
            builder.append(aCharArray);
        }
    }
    return builder.toString();
}

至于數(shù)據(jù)排序使用 Comparator 接口即可

顯示效果

顯示效果如下:

Android怎么實(shí)現(xiàn)字母導(dǎo)航控件

到此,關(guān)于“Android怎么實(shí)現(xiàn)字母導(dǎo)航控件”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI