安卓自定义弧形刻度选择器
来源:互联网 发布:华硕mg248q设置软件 编辑:程序博客网 时间:2024/05/20 00:36
在android开发过程中实现通过自定义View实现的弧形刻度选择器,效果如下。
使用方法:
1,布局文件添加以下属性
app:arcLineColor="#ff0000" 弧线颜色
app:drawLineSpace="1" 刻度线间距
app:drawTextSpace="5" 刻度值间隔
app:everyScaleValue="1" 滑动像素与刻度值的比例
app:indicatorColor="#1cffaf" 中间指示器颜色
app:scaleLineColor="#0000ff" 刻度线颜色
app:scaleMin="200" 选择器最小值
app:scaleNum="30" 刻度数量
app:scaleSpace="1" 刻度间距
app:scaleTextColor="#0000ff" 刻度值颜色
app:scaleUnit="单位" 刻度单位
app:selectTextColor="#111111" 选中值颜色
2,setSelectScaleListener()监听刻度值变化
一,测量:
首先在onMeasure方法中通过测量获取当前View的宽高,中心点,半径
mWidth = getMeasuredWidth();mHeight = getMeasuredHeight();mCenterX = mWidth / 2;mCenterY = 0;radius = Math.min(mWidth / 2 - padding, mHeight / 2 - padding);
二,画弧形:
绘制弧形可以通过canvas.drawPath或通过canvas.drawArc()方法绘制弧形,本文中选择通过canvas.drawPath方法绘制,下文会讲解为什么使用drawPath方法绘制弧形
int top = -radius;int bottom = radius;int left = mCenterX - radius;int right = mCenterX + radius;mArcPath.reset();mArcPath.addArc(new RectF(left, top, right, bottom), 0, 180);canvas.drawPath(mArcPath, mArcPaint);
三,绘制弧形刻度线以及刻度:
怎么样绘制刻度线呢??通过观察发现刻度线是垂直于弧形切线的,所以绘制刻度线我们首先要知道这些刻度点当前的切线。PathMeasure.getPosTan()可以获取到Path上某个点的xy坐标与tan值,PathMeasure.getLength可以获取Path的长度,getLength与getPosTan方法配合使用获取Path线上点的pos与tan值,获取到坐标值与tan值之后我们就可以绘制刻度线了。PathMeasure办法只能作用在Path上,这也就解释了为什么选择drawPath的方法绘制弧形。
PathMeasure mPathMeasure = new PathMeasure();mPathMeasure.setPath(mArcPath, false);float[] pos = new float[2];float[] tan = new float[2];for (int i = 1; i <= mScaleNumber; i++) { //mScaleNumber为刻度点的数量,for循环遍历刻度点float percentage = i / (float) mScaleNumber;//计算当前刻度所占总刻度的百分比,mPathMeasure.getPosTan(mPathMeasure.getLength() * percentage, pos, tan);//通过上一步计算出来的百分比可以计算出当前刻度在Path上的位置double atan2 = Math.atan2(tan[1], tan[0]);double angle = calcArcAngle(atan2) + 90;//刻度线垂直切线,所以旋转90°int scale = Math.round(currentAngle + mScaleMin + i * mScaleSpace); if (scale >= mScaleMin && scale % mDrawLineSpace == 0) {float startX = pos[0]; float startY = pos[1]; float endX = 0; float endY = pos[1]; if (scale % mDrawTextSpace == 0) {endX = pos[0] + 80;mScaleLinePaint.setStrokeWidth(15);mScaleLinePaint.setColor(mScaleLineColor); if (currentAngle >= (-(mScaleNumber / 2) * mScaleSpace)) {canvas.save();canvas.rotate((float) (angle + 90), pos[0], pos[1]);String mScaleText = scale + mScaleUnit; float scaleTextLength = mScaleTextPaint.measureText(mScaleText, 0, mScaleText.length());canvas.drawText(mScaleText, pos[0] - scaleTextLength / 2, pos[1] - 130, mScaleTextPaint);canvas.restore();}} else if (scale % mDrawLineSpace == 0) {mScaleLinePaint.setColor(mScaleTextColor);mScaleLinePaint.setStrokeWidth(10);endX = pos[0] + 50;}canvas.save();canvas.rotate((float) angle, pos[0], pos[1]);canvas.drawLine(startX, startY, endX, endY, mScaleLinePaint);canvas.restore();}}
四,绘制当前选中的刻度值
String selectedScaleText = selectedScale + mScaleUnit;float selectedScaleTextLength = mSelectedTextPaint.measureText(selectedScaleText, 0, selectedScaleText.length());canvas.drawText(selectedScaleText, mCenterX - selectedScaleTextLength / 2, mCenterY + 100, mSelectedTextPaint);
五,绘制中心指示器:
中心指示器位于弧形中心,所以首先获取要弧形中心点坐标,tan值。弧形中心点也就是弧形长度的一半也就是mPathMeasure.getLength() * (0.5f)。通过坐标以及tan值使用drawLine方法绘制直线drawPath方法绘制剪头
PathMeasure mPathMeasure = new PathMeasure();mPathMeasure.setPath(mArcPath, false);float[] tan = new float[2];float[] pos = new float[2];mPathMeasure.getPosTan(mPathMeasure.getLength() * (0.5f), pos, tan);canvas.save();double angle = calcArcAngle(Math.atan2(tan[1], tan[0])) + 90;canvas.rotate((float) angle, pos[0], pos[1]);//画直线canvas.drawLine(pos[0], pos[1], pos[0] + 80, pos[1], mIndicatorPaint);Path linePath = new Path();//画箭头linePath.moveTo(pos[0] + 80, pos[1] - 20);linePath.lineTo(pos[0] + 80 + 20, pos[1]);linePath.lineTo(pos[0] + 80, pos[1] + 20);canvas.drawPath(linePath, mIndicatorPaint);canvas.restore();
六,为了美观画弧形两侧的遮罩层
弧形的两侧有一个有白色到透明的线性渐变,LinearGradient类可以实现画笔的线性渐变。
//画左侧遮罩LinearGradient mLeftLinearGradient = new LinearGradient(0, 0, mCenterX - 100, 150, Color.WHITE, Color.TRANSPARENT, Shader.TileMode.CLAMP);mMaskPaint.setShader(mLeftLinearGradient);canvas.drawPath(mArcPath, mMaskPaint);//画右侧遮罩LinearGradient rightLinearGradient = new LinearGradient(mWidth, 0, mCenterX + 100, 150, Color.WHITE, Color.TRANSPARENT, Shader.TileMode.CLAMP);mMaskPaint.setShader(rightLinearGradient);canvas.drawPath(mArcPath, mMaskPaint);canvas.drawPath(mArcPath, mArcPaint);
七,计算滑动旋转角度:
当触摸屏幕的时候会有横向的坐标x与纵向的坐标值y,x与y与中点会产生一个三角形,通过三角函数定理以及当前坐标我们可以获取到sin值,通过反三角函数Math.asin方法通过sin值我们可以计算出滑动角度。滑动过程中会角度会不断变化,角度变化的差值就决定了选择器的增加或减少。
触摸屏幕对角度的处理
switch (event.getAction()) {case MotionEvent.ACTION_DOWN:float mDownX = event.getX(); float mDownY = event.getY();initAngle = computeAngle(mDownX, mDownY); if (mDownX > mCenterX) {initAngle = 180 - initAngle;}break; case MotionEvent.ACTION_MOVE:float mTouchX = event.getX(); float mTouchY = event.getY(); if (isTouch(mTouchX, mTouchY)) {double moveAngle = computeAngle(mTouchX, mTouchY); if (mTouchX > mCenterX) {moveAngle = 180 - moveAngle;}double tempAngle = moveAngle - initAngle; long addValue = Math.round(tempAngle * mEvenyScaleValue);currentAngle += addValue; if (currentAngle >= -(mScaleNumber / 2) * mScaleSpace) {invalidate();} else {currentAngle = currentAngle - addValue;}initAngle = moveAngle; return true;}break;}
计算角度
private double computeAngle(float touchX, float touchY) {double atan2 = Math.atan2(touchY, touchX); double taperedEdge = Math.sqrt(Math.pow(touchX - mCenterX, 2) + Math.pow(touchY - mCenterY, 2));//计算斜边double sin = (touchY - mCenterY) / taperedEdge; double asin = Math.asin(sin); double calcArcAngle = calcArcAngle(asin); return calcArcAngle;}
本文讲解了如何实现一个弧形刻度选择器,由于本人能力有限,必然存在很多不足,忘大家见解
大家可以到https://github.com/yhongm/ArcScaleView下载完整的代码,在代码中有详细的注释。欢迎大家fork,star
- 安卓自定义弧形刻度选择器
- 安卓自定义半圆弧形菜单
- 弧形刻度进度条
- 安卓自定义日历选择器
- 安卓自定义日历选择器
- 安卓自定义相册的选择器
- 安卓自定义View基础05-Canvas之基础图形绘制,点,线,矩形,圆,椭圆,弧形等
- android 弧形自定义view
- 自定义进度弧形条
- 自定义弧形进度条
- 安卓选择器类库,包括日期选择器、时间选择器、单项选择器、数字选择器、二三级联动选择器、省市区地址选择器、颜色选择器、文件目录选择器等,可自定义顶部及底部界面,可自定义窗口动画
- 安卓选择器类库,包括日期时间选择器、单项选择器、二三级联动选择器、地址选择器、颜色选择器、文件目录选择器、数字选择器等,可自定义顶部及底部界面,可自定义窗口动画。
- HighCharts自定义坐标轴刻度
- 安卓选择器
- 安卓状态选择器
- 安卓时间选择器
- swing自定义弧形边框 CurvedBorder
- 自定义弧形渐变进度条功能
- 充分使用树莓派SD卡容量
- Codeforces gym 101350G 数学
- python学习笔记先导
- 信号量(生产者和消费者模型)
- Linux下如何使用awk解析json数据
- 安卓自定义弧形刻度选择器
- c语言基础(三)
- 关于Java序列化与反序列化
- nginx的反向代理与负载均衡
- Hibernate 出现Unsupported major.minor version 52.0 [duplicate]
- c/c++ static extern const
- BZOJ 1434: [ZJOI2009]染色游戏 博弈
- Memory Network简单理解
- 无需启动项目测试spring RunWith ContextConfiguration