栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 移动开发 > Android

Android自定义控件实现温度旋转按钮效果

Android 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android自定义控件实现温度旋转按钮效果

首先看下效果图


温度旋转按钮

实现思路

  1. 初始化一些参数
  2. 绘制刻度盘
  3. 绘制刻度盘下的圆弧
  4. 绘制标题与温度标识
  5. 绘制旋转按钮
  6. 绘制温度
  7. 处理滑动事件
  8. 提供一些接口方法

实现方法

初始化一些参数

public class TempControlView extends View {

 // 控件宽
 private int width;
 // 控件高
 private int height;
 // 刻度盘半径
 private int dialRadius;
 // 圆弧半径
 private int arcRadius;
 // 刻度高
 private int scaleHeight = dp2px(10);
 // 刻度盘画笔
 private Paint dialPaint;
 // 圆弧画笔
 private Paint arcPaint;
 // 标题画笔
 private Paint titlePaint;
 // 温度标识画笔
 private Paint tempFlagPaint;
 // 旋转按钮画笔
 private Paint buttonPaint;
 // 温度显示画笔
 private Paint tempPaint;
 // 文本提示
 private String title = "最高温度设置";
 // 温度
 private int temperature;
 // 最低温度
 private int minTemp = 15;
 // 最高温度
 private int maxTemp = 30;
 // 四格(每格4.5度,共18度)代表温度1度
 private int angleRate = 4;
 // 按钮图片
 private Bitmap buttonImage = BitmapFactory.decodeResource(getResources(),
   R.mipmap.btn_rotate);
 // 按钮图片阴影
 private Bitmap buttonImageShadow = BitmapFactory.decodeResource(getResources(),
   R.mipmap.btn_rotate_shadow);
 // 抗锯齿
 private PaintFlagsDrawFilter paintFlagsDrawFilter;
 // 温度改变监听
 private onTempChangeListener onTempChangeListener;

 // 以下为旋转按钮相关

 // 当前按钮旋转的角度
 private float rotateAngle;
 // 当前的角度
 private float currentAngle;

 ...

 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
  // 控件宽、高
  width = height = Math.min(h, w);
  // 刻度盘半径
  dialRadius = width / 2 - dp2px(20);
  // 圆弧半径
  arcRadius = dialRadius - dp2px(20);
 }

 ...
}

绘制刻度盘

以屏幕中心为画布原点,圆弧角度为270°,绘制未选中与选中状态的刻度盘。

旋转方法中多减的2°是后期调整所得,不用在意。


private void drawScale(Canvas canvas) {
 canvas.save();
 canvas.translate(getWidth() / 2, getHeight() / 2);
 // 逆时针旋转135-2度
 canvas.rotate(-133);
 dialPaint.setColor(Color.parseColor("#3CB7EA"));
 for (int i = 0; i < 60; i++) {
  canvas.drawLine(0, -dialRadius, 0, -dialRadius + scaleHeight, dialPaint);
  canvas.rotate(4.5f);
 }

 canvas.rotate(90);
 dialPaint.setColor(Color.parseColor("#E37364"));
 for (int i = 0; i < (temperature - minTemp) * angleRate; i++) {
  canvas.drawLine(0, -dialRadius, 0, -dialRadius + scaleHeight, dialPaint);
  canvas.rotate(4.5f);
 }
 canvas.restore();
}


绘制刻度盘下的圆弧


private void drawArc(Canvas canvas) {
 canvas.save();
 canvas.translate(getWidth() / 2, getHeight() / 2);
 canvas.rotate(135 + 2);
 RectF rectF = new RectF(-arcRadius, -arcRadius, arcRadius, arcRadius);
 canvas.drawArc(rectF, 0, 265, false, arcPaint);
 canvas.restore();
}


绘制标题与温度标识

 
 private void drawText(Canvas canvas) {
  canvas.save();

  // 绘制标题
  float titleWidth = titlePaint.measureText(title);
  canvas.drawText(title, (width - titleWidth) / 2, dialRadius * 2 + dp2px(15), titlePaint);

  // 绘制最小温度标识
  // 最小温度如果小于10,显示为0x
  String minTempFlag = minTemp < 10 ? "0" + minTemp : minTemp + "";
  float tempFlagWidth = titlePaint.measureText(maxTemp + "");
  canvas.rotate(55, width / 2, height / 2);
  canvas.drawText(minTempFlag, (width - tempFlagWidth) / 2, height + dp2px(5), tempFlagPaint);

  // 绘制最大温度标识
  canvas.rotate(-105, width / 2, height / 2);
  canvas.drawText(maxTemp + "", (width - tempFlagWidth) / 2, height + dp2px(5), tempFlagPaint);
  canvas.restore();
 }

绘制旋转按钮


private void drawButton(Canvas canvas) {
 // 按钮宽高
 int buttonWidth = buttonImage.getWidth();
 int buttonHeight = buttonImage.getHeight();
 // 按钮阴影宽高
 int buttonShadowWidth = buttonImageShadow.getWidth();
 int buttonShadowHeight = buttonImageShadow.getHeight();

 // 绘制按钮阴影
 canvas.drawBitmap(buttonImageShadow, (width - buttonShadowWidth) / 2,
   (height - buttonShadowHeight) / 2, buttonPaint);

 Matrix matrix = new Matrix();
 // 设置按钮位置
 matrix.setTranslate(buttonWidth / 2, buttonHeight / 2);
 // 设置旋转角度
 matrix.preRotate(45 + rotateAngle);
 // 按钮位置还原,此时按钮位置在左上角
 matrix.preTranslate(-buttonWidth / 2, -buttonHeight / 2);
 // 将按钮移到中心位置
 matrix.postTranslate((width - buttonWidth) / 2, (height - buttonHeight) / 2);

 //设置抗锯齿
 canvas.setDrawFilter(paintFlagsDrawFilter);
 canvas.drawBitmap(buttonImage, matrix, buttonPaint);
}


绘制温度


private void drawTemp(Canvas canvas) {
 canvas.save();
 canvas.translate(getWidth() / 2, getHeight() / 2);

 float tempWidth = tempPaint.measureText(temperature + "");
 float tempHeight = (tempPaint.ascent() + tempPaint.descent()) / 2;
 canvas.drawText(temperature + "°", -tempWidth / 2 - dp2px(5), -tempHeight, tempPaint);
 canvas.restore();
}


处理滑动事件

private boolean isDown;
private boolean isMove;

@Override
public boolean onTouchEvent(MotionEvent event) {
 switch (event.getAction()) {
  case MotionEvent.ACTION_DOWN:
   isDown = true;
   float downX = event.getX();
   float downY = event.getY();
   currentAngle = calcAngle(downX, downY);
   break;

  case MotionEvent.ACTION_MOVE:
   isMove = true;
   float targetX;
   float targetY;
   downX = targetX = event.getX();
   downY = targetY = event.getY();
   float angle = calcAngle(targetX, targetY);

   // 滑过的角度增量
   float angleIncreased = angle - currentAngle;

   // 防止越界
   if (angleIncreased < -270) {
    angleIncreased = angleIncreased + 360;
   } else if (angleIncreased > 270) {
    angleIncreased = angleIncreased - 360;
   }

   IncreaseAngle(angleIncreased);
   currentAngle = angle;
   invalidate();
   break;

  case MotionEvent.ACTION_CANCEL:
  case MotionEvent.ACTION_UP: {
   if (isDown && isMove) {
    // 纠正指针位置
    rotateAngle = (float) ((temperature - minTemp) * angleRate * 4.5);
    invalidate();
    // 回调温度改变监听
    onTempChangeListener.change(temperature);
    isDown = false;
    isMove = false;
   }
   break;
  }
 }
 return true;
}


private float calcAngle(float targetX, float targetY) {
 float x = targetX - width / 2;
 float y = targetY - height / 2;
 double radian;

 if (x != 0) {
  float tan = Math.abs(y / x);
  if (x > 0) {
   if (y >= 0) {
    radian = Math.atan(tan);
   } else {
    radian = 2 * Math.PI - Math.atan(tan);
   }
  } else {
   if (y >= 0) {
    radian = Math.PI - Math.atan(tan);
   } else {
    radian = Math.PI + Math.atan(tan);
   }
  }
 } else {
  if (y > 0) {
   radian = Math.PI / 2;
  } else {
   radian = -Math.PI / 2;
  }
 }
 return (float) ((radian * 180) / Math.PI);
}


private void IncreaseAngle(float angle) {
 rotateAngle += angle;
 if (rotateAngle < 0) {
  rotateAngle = 0;
 } else if (rotateAngle > 270) {
  rotateAngle = 270;
 }
 temperature = (int) (rotateAngle / 4.5) / angleRate + minTemp;
}

提供一些接口方法


public void setTemp(int minTemp, int maxTemp, int temp) {
 this.minTemp = minTemp;
 this.maxTemp = maxTemp;
 this.temperature = temp;
 this.angleRate = 60 / (maxTemp - minTemp);
 rotateAngle = (float) ((temp - minTemp) * angleRate * 4.5);
 invalidate();
}


public void setonTempChangeListener(onTempChangeListener onTempChangeListener) {
 this.onTempChangeListener = onTempChangeListener;
}


public interface onTempChangeListener {
 
 void change(int temp);
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对各位Android开发者们能有所帮助,如果有疑问大家可以留言交流。

转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/160347.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号