自定义View实现字母导航控件
PS:如果不能严格内化自己,就没有足够的心理能量进行深度工作。
完成列表数据与字母之间的相互联动;
支持布局文件属性配置;
在布局文件中能够配置相关属性,如字母颜色、字母字体大小、字母指示器颜色等属性。
自定义属性
Measure测量
坐标计算
绘制
显示效果
自定义属性
<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();
}
Measure测量
@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;
}
坐标计算
绘制
@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);
}
}
Touch事件处理
@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;
}
数据组装
//汉字转换为拼音
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();
}
显示效果
评论