系列文章
造轮子:滚轮选择器实现及原理解析(一)
造轮子:滚轮选择器实现及原理解析(二)
造轮子:滚轮选择器实现及原理解析(三)
造轮子:滚轮选择器实现及原理解析(源码)
上方非循环滚动,下方循环滚动
滚动下面的选择器使上方选择器联动
滚轮选择器的使用场景最常见于时间选择,手机上操作出生年月时经常能看到年月日选择器。
其最典型特征:
抛开动画和展示效果不谈,首要任务在于如何把内容排列在屏幕上。
视觉上典型的LinearLayout
布局,从上到下按顺序排列,甚至滚动都是类似的,不过我们这里不使用LinearLayout
,当需要循环时使用LinearLayout
并不方便
// onDraw()
for (int i = 0; i < size; i++) {
drawItem(canvas, i);
}
// drawItem()
// 测量文字,绘制时居中显示
float textWidth = paint.measureText(text);
// 计算偏移量,在每行固定高度时,偏移量很好计算
float totalOffset = i* itemHeight;
canvas.save();
canvas.translate(0, -totalOffset);
// 此处用于适配文字baseline,否则会导致文字无法绘制在绝对居中位置
Paint.FontMetrics metrics = paint.getFontMetrics();
canvas.drawText(text, width / 2f - textWidth / 2f, - (metrics.top + metrics.bottom) / 2f, paint);
canvas.restore();
i*itemHeight
计算偏移curY
模拟当前滚动距离,使用该变量计算protected int getCenterShowPosition(float y) {
//这里进行y矫正,防止小于0或超出float上限,便于后续计算
float newY = adjustingY(y);
return (int) (newY / itemHeight);
}
现在我们将模型图转换:
因为我们绘制文本时,总是居中绘制,所以理论上我们只关心绘制点的中心线段
在哪,后续绘制时根据itemHeight
进行平移矫正一下,后续我们只关心线条的位置即可
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float y = curY;
// 获取中心位置item的下标
int centerPosition = getCenterShowPosition(y);
// item不可能刚好在中线,计算出它的偏移距离
float offsetY = adjustingY(y) - itemHeight * centerPosition;
// 限制绘制个数,为了保证上下对称,当向上滚动一段距离时,应当在下方多补充一个item绘制
int max = centerPosition + showCount;
// 处于正中心时使两侧显示相同个数item,非中心时下方增加1个
if (offsetY > 0f) {
max += 1;
}
// 只遍历可显示出来的部分
for (int i = centerPosition - showCount + 1; i < max; i++) {
drawItem(canvas, i, centerPosition, offsetY);
}
}
// 计算和中心item的差距
int count = centerPosition - position;
float totalOffset = offsetY + count * itemHeight;
canvas.save();
canvas.translate(0, -totalOffset);
Paint.FontMetrics metrics = paint.getFontMetrics();
// 绘制在中心点的位置
canvas.drawText(text, width / 2f - textWidth / 2f, height / 2f - (metrics.top + metrics.bottom) / 2f, paint);
canvas.restore();
至此,简单的滚轮选择器的基础绘制已完成,调整curY
可使其位置发生改变