Android开发常见的需求: 按拼音排序
Android常见需求,按照汉字首字母排序,从A~Z,右侧自定义一个字母列表,手指可以滑动选择,并和RecyclerView联动的效果。
如图:
左侧RecyclerView建议使用多布局类型,以后好做头部悬停效果。右侧要自定义View来实现,触摸滑动刷新界面了。
首先,计算View的宽高和字母所占的空间高度;
1、计算View的宽度
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//取出宽高的MeasureSpec Mode 和Size
int wMode = MeasureSpec.getMode(widthMeasureSpec);
int wSize = MeasureSpec.getSize(widthMeasureSpec);
int hMode = MeasureSpec.getMode(heightMeasureSpec);
int hSize = MeasureSpec.getSize(heightMeasureSpec);
int measureWidth = 0, measureHeight = 0;//最终测量出来的宽高
//得到合适宽度:
Rect indexBounds = new Rect();//存放每个绘制的index的Rect区域
String index;//每个要绘制的index内容
for (int i = 0; i < firstLetters.size(); i++) {
index = firstLetters.get(i);
mPaint.getTextBounds(index, 0, index.length(), indexBounds);//测量计算文字所在矩形,可以得到宽高
measureWidth = Math.max(indexBounds.width(), measureWidth);//循环结束后,得到index的最大宽度
}
//得到合适的宽度:
switch (wMode) {
case MeasureSpec.EXACTLY:
measureWidth = wSize;
break;
case MeasureSpec.AT_MOST:
//wrap_content
measureWidth = Math.min(measureWidth, wSize);//wSize此时是父控件能给子View分配的最大空间
break;
case MeasureSpec.UNSPECIFIED:
break;
}
}
2、先算出整个View的高度,再除以字母个数,就是每个字母所用的平均空间高度,
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//取出宽高的MeasureSpec Mode 和Size
int wMode = MeasureSpec.getMode(widthMeasureSpec);
int wSize = MeasureSpec.getSize(widthMeasureSpec);
int hMode = MeasureSpec.getMode(heightMeasureSpec);
int hSize = MeasureSpec.getSize(heightMeasureSpec);
int measureWidth = 0, measureHeight = 0;//最终测量出来的宽高
//得到合适宽度:
Rect indexBounds = new Rect();//存放每个绘制的index的Rect区域
String index;//每个要绘制的index内容
for (int i = 0; i < firstLetters.size(); i++) {
index = firstLetters.get(i);
mPaint.getTextBounds(index, 0, index.length(), indexBounds);//测量计算文字所在矩形,可以得到宽高
measureWidth = Math.max(indexBounds.width(), measureWidth);//循环结束后,得到index的最大宽度
measureHeight = Math.max(indexBounds.height(), measureHeight);//循环结束后,得到index的最大高度,然后*size
}
measureHeight *= firstLetters.size();
measureHeight += (getPaddingBottom() + getPaddingTop());
//得到合适的高度:
switch (hMode) {
case MeasureSpec.EXACTLY:
measureHeight = hSize;
break;
case MeasureSpec.AT_MOST:
//wrap_content
measureHeight = Math.min(measureHeight, hSize);//wSize此时是父控件能给子View分配的最大空间
break;
case MeasureSpec.UNSPECIFIED:
break;
}
}
高度算出来后,可以在 onSizeChanged() 方法里面获取;
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
if (mIsHalfWidth){
mCircleRadius = mWidth / 2F;
}
if (null == firstLetters || firstLetters.isEmpty()) {
return;
}
//计算每个字母平均占据空间高度
computeGapHeight();
}
获取高度后,除去字母个数可得每个字母所占平均高度:
private void computeGapHeight() {
//高度减去padding,除以字母个数
mCellHeight = (mHeight - getPaddingTop() - getPaddingBottom()) / firstLetters.size();
}
绘制字母和小圆圈
在onDraw() 方法里吗进行绘制。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int paddingTop = getPaddingTop();
String letter;
for (int i = 0; i < firstLetters.size(); i++) {
//选中的字母
if (choosePos == i) {
//如果有字体大小变化需求的话
// mPaint.setTextSize();
mPaint.setColor(mSelectTextColor);
//计算圆圈圆心坐标,x,y,和半径
//x坐标位于View中间,宽度的一半
//y坐标是每个字母的中心位置,字母所占高度的一半,再加上边几个字母的距离,paddingTop+mCellHeight * i
canvas.drawCircle(mWidth / 2F, paddingTop + mCellHeight