ビューをカスタマイズして、レターナビゲーションコントロールを実装します

PS:自分自身を厳密に内面化できない場合、深い仕事をするのに十分な精神的エネルギーがありません。

今日は、以前に実装した名簿のレターナビゲーションコントロールを共有します。名簿に似たレターナビゲーションビューをカスタマイズしましょう。レターインジケータの描画、テキストの描画、タッチモニタリング、座標計算など、カスタマイズが必要ないくつかの要素を知ることができます。カスタマイズが完了した後に実行できる機能は次のとおりです。

  • リストデータと文字の間の相互リンクを完了します。
  • レイアウトファイル属性の構成をサポートします。
  • 文字の色、文字のフォントサイズ、文字のインジケーターの色、その他の属性など、関連する属性をレイアウトファイルで構成できます。

主な内容は以下のとおりです。

  1. カスタム属性
  2. 測定する
  3. 座標計算
  4. ドロー
  5. 表示効果

カスタム属性

次のように、valueの下に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>

次に、対応する工法でこれらの属性を取得し、次のように関連する属性を設定します。

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);

    //默认设置
    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();
}

測定する

カスタムサイズと座標を正確に制御するには、現在のカスタムビューの幅と高さを測定し、測定されたサイズから関連する座標を計算する必要があります。特定の測定プロセスは、ビューを継承してomMeasure()を書き換えることです。測定を完了する方法。、キーコードは次のとおりです。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
    
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    //获取宽高的尺寸大小
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    //wrap_content默认宽高
    @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; //界面调整
    mItemHeight = averageItemHeight + mOffset;
}

座標計算

カスタムビューは、実際にはビュー上の適切な位置を見つけて、カスタム要素を整然と描画することです。描画プロセスの最も難しい部分は、特定のニーズに応じて右側を計算する方法です。描画に関しては、すべてのAPI呼び出し。座標位置が計算されている限り、カスタムビュー図面に問題はありません。次の図は、主に文字インジケータ図面の中心位置座標の計算と、の開始点位置の計算を示しています。テキストの描画。描画プロセス中に描画されていることを確認してください。テキストはインジケーターの中央にあります。以下を参照してください。

ドロー

カスタムビューの描画操作はすべてonDraw()メソッドで実行されます。ここでは、円とテキストの描画、特に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);
    }
}

これまでのところ、ビューの基本的な描画は終了したと言えます。カスタムのビューインターフェイスを使用して表示できるようになりましたが、関連するイベント操作はまだ追加されていません。以下は、のタッチイベントに関連するロジックを実装します。景色。

タッチイベント処理

どの文字が指の現在の位置に対応するかを判断するには、現在のタッチの座標位置を取得して文字インデックスを計算する必要があります。re-onTouchEvent()メソッド、MotionEvent.ACTION_DOWN、MotionEvent.ACTION_MOVEをリッスンして計算します。インデックス位置を取得し、MotionEvent.ACTION_UPをリッスンして取得します。結果がコールバックされます。具体的な参照は次のとおりです。

@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;
}

これまでのところ、ビューのカスタマイズの重要な部分は基本的に完了しています。

データアセンブリ

文字ナビゲーションの基本的な考え方は、文字と一致させる必要のあるフィールドを対応する文字に変換し、フィールドに従ってデータを並べ替えて、最後に同じ最初の文字でデータをバッチ一致させることを可能にすることですデータフィールドの最初の文字を介してここで、pinyin4j-2.5.0.jarを使用して中国語の文字を拼音に変換し、最初の文字に従ってデータ項目を並べ替えてデータを表示します。中国語の文字は次のように拼音に置き換えられます。次のとおりです。


//汉字转换为拼音
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();
}

データの並べ替えについては、Comparatorインターフェースを使用できるため、ここでは詳しく説明しません。詳細については、記事の最後にあるソースコードのリンクを参照してください。

表示効果

表示効果は次のとおりです。

公開ミユキの返信はありません[キーワード] MLetterViewソースを表示します。

ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/jzman/article/details/114006101