欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-02-25 22:26:45
首先看下效果图 温度旋转按钮 实现思路 初始化一些参数 绘制刻度盘 绘制刻度盘下的圆弧 绘制标题与温度标识 绘制旋转按钮...

首先看下效果图

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°是后期调整所得,不用在意。

/**
 * 绘制刻度盘
 *
 * @param canvas 画布
 */
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();
}

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

绘制刻度盘下的圆弧

/**
 * 绘制刻度盘下的圆弧
 *
 * @param canvas 画布
 */
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();
}

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

绘制标题与温度标识

 /**
  * 绘制标题与温度标识
  *
  * @param canvas 画布
  */
 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();
 }

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

绘制旋转按钮

/**
 * 绘制旋转按钮
 *
 * @param canvas 画布
 */
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);
}

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

绘制温度

/**
 * 绘制温度
 *
 * @param canvas 画布
 */
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();
}

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

处理滑动事件

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;
}

/**
 * 以按钮圆心为坐标圆点,建立坐标系,求出(targetx, targety)坐标与x轴的夹角
 *
 * @param targetx x坐标
 * @param targety y坐标
 * @return (targetx, targety)坐标与x轴的夹角
 */
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);
}

/**
 * 增加旋转角度
 *
 * @param angle 增加的角度
 */
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;
}

提供一些接口方法

/**
 * 设置温度
 *
 * @param mintemp 最小温度
 * @param maxtemp 最大温度
 * @param temp 设置的温度
 */
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();
}

/**
 * 设置温度改变监听
 *
 * @param ontempchangelistener 监听接口
 */
public void setontempchangelistener(ontempchangelistener ontempchangelistener) {
 this.ontempchangelistener = ontempchangelistener;
}

/**
 * 温度改变监听接口
 */
public interface ontempchangelistener {
 /**
  * 回调方法
  *
  * @param temp 温度
  */
 void change(int temp);
}

总结

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