一个不错效果的调光调色开关

  先上效果图:

  不错吧,最中间那个开关是个CheckBox,中间那个蓝色的是个圆形的拖动条,可以用来显示灯的亮度,而最外面的彩色环形也是可以拖动的,可以用来控制色彩。

  彩色环形是自定义View——CirclView,onTouch事件计算如旋转的角度,然后旋转画布,那个环形是UI素材。代码如下:


  1 import android.content.Context;
2 import android.graphics.Bitmap;
3 import android.graphics.Canvas;
4 import android.graphics.Color;
5 import android.graphics.drawable.BitmapDrawable;
6 import android.graphics.drawable.Drawable;
7 import android.util.AttributeSet;
8 import android.view.MotionEvent;
9 import android.view.View;
10
11 public class CircleView extends View {
12 public static final int INVALID_ANGLE = Integer.MIN_VALUE;
13
14 private float lastX; //起始X坐标
15 private float lastY; //起始Y坐标
16
17 private float centerX; //圆心X坐标
18 private float centerY; //圆心Y坐标
19
20 double oldAngle; //旋转前角度
21 double angle; //旋转后角度
22
23 private Drawable rotatedPicture; //要旋转的背景图片
24 private Bitmap rotatedBitmap;
25 private float ringRatio;
26
27 private int maxAngle = INVALID_ANGLE;
28 private int minAngle = INVALID_ANGLE;
29
30 private OnAngleChangedListener anglelistener;
31 private OnColorChangedListener colorListener;
32
33 public CircleView(Context context) {
34 this(context, null);
35 }
36
37 public CircleView(Context context, AttributeSet attrs) {
38 this(context, attrs, 0);
39 }
40
41 public CircleView(Context context, AttributeSet attrs, int defStyle) {
42 super(context, attrs, defStyle);
43 }
44
45 /**
46 *
47 * @param lastPointX 一次ActionMove的起始X坐标
48 * @param lastPointY 一次ActionMove的起始Y坐标
49 * @param pointX 一次ActionMove的终止X坐标
50 * @param pointY 一次ActionMove的终止Y坐标
51 * @return 返回一次ActionMove转过的角度
52 */
53 private double computeAngle(float lastPointX, float lastPointY, float pointX, float pointY) {
54 //坐标系换算,原坐标系为以屏幕左上角为原点的直角坐标系,新坐标系为以圆心位置(centerX,centerY)为原点的直角坐标系
55 //没有delta前缀的都是原坐标系的值,delta前缀标识的为换算后新坐标系的值
56 float deltaLastPointX = lastPointX - centerX;
57 float deltaLastPointY = centerY - lastPointY;
58
59 float deltaPointX = pointX - centerX;
60 float deltaPointY = centerY - pointY;
61
62 //gradient表示斜率,如果deltaPonitX的值为零,则gradient为无穷大,否则为deltaPointY / deltaPointX
63 float gradient = deltaPointX != 0 ? deltaPointY / deltaPointX : Integer.MAX_VALUE;
64 float lastGradient = deltaLastPointX != 0 ? deltaLastPointY / deltaLastPointX : Integer.MAX_VALUE;
65 //如果斜率相同,则返回0
66 if (gradient == lastGradient)
67 return 0;
68
69 //lastPointSidePow,pointSidePow表示对应点到圆心的距离平方
70 float lastPointSidePow = deltaLastPointX * deltaLastPointX + deltaLastPointY * deltaLastPointY;
71 float pointSidePow = deltaPointX * deltaPointX + deltaPointY * deltaPointY;
72 //两点之间距离的平方
73 float lastPointPointSidePow = (float) (Math.pow(deltaLastPointY - deltaPointY, 2) + Math.pow(deltaLastPointX
74 - deltaPointX, 2));
75 //下面使用余弦定理求出一次ActionMove所经过角度的余弦值
76 //余弦定理:cosC = (a^2 + b^2 - c^2) / (2·a·b)
77 double cosinCentralAngle = (lastPointSidePow + pointSidePow - lastPointPointSidePow)
78 / (2 * Math.sqrt(lastPointSidePow) * Math.sqrt(pointSidePow));
79 if (cosinCentralAngle > 1 || cosinCentralAngle < -1)
80 return 0;
81 //反余弦:把余弦值换算成对应弧度
82 double acos = Math.acos(cosinCentralAngle);
83 //弧度角度换算:把弧度换算成对应角度
84 double increment = (acos / Math.PI) * 180;
85 //isBellow判断一次ActionMove之后斜率值是否降低
86 boolean isBellow = lastGradient > gradient;
87 //如果斜率降低
88 if (isBellow) {
89 //如果ActionMove之前在第一、四象限
90 if (deltaLastPointX >= 0) {
91 //如果ActionMove之后也在第一、四象限,则旋转的方向为逆时针,角度应为正值
92 if (deltaPointX >= 0) {
93 return increment;
94 //如果ActionMove之后在第二、三象限,则旋转的方向为顺时针,角度为负值
95 } else {
96 return -increment;
97 }
98 //如果ActionMove之前在第二、三象限
99 } else {
100 //如果ActionMove之后也在第二、三象限,则旋转的方向为逆时针,角度应为正值
101 if (deltaPointX <= 0) {
102 return increment;
103 //如果ActionMove之后在第一、四象限,则旋转的方向为顺时针,角度为负值
104 } else {
105 return -increment;
106 }
107 }
108 } else {
109 if (deltaLastPointX >= 0) {
110 if (deltaPointX >= 0) {
111 return -increment;
112 } else {
113 return increment;
114 }
115 } else {
116 if (deltaPointX <= 0) {
117 return -increment;
118 } else {
119 return increment;
120 }
121 }
122 }
123 }
124
125 @Override
126 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
127 centerX = w / 2.0f;
128 centerY = h / 2.0f;
129 rotatedPicture.setBounds(0, 0, w, h);
130 rotatedBitmap = ((BitmapDrawable) rotatedPicture).getBitmap();
131 }
132
133 @Override
134 protected void onDraw(Canvas canvas) {
135 canvas.save();
136 canvas.rotate((float) angle, centerX, centerY);
137 rotatedPicture.draw(canvas);
138 canvas.restore();
139 }
140
141 public boolean isHit(int x, int y) {
142 //getPixel(x, y)方法返回(x,y)坐标位置的像素颜色信息
143 //x,y的取值范围分别为(0...width-1)、(0...height-1),如果超出取值范围则会抛出异常
144 //方法返回值为
145 return (rotatedBitmap.getPixel(x, y) & 0xFF000000) != 0;
146 }
147
148 @Override
149 public boolean onTouchEvent(MotionEvent event) {
150 final float nowX = event.getX();
151 final float nowY = event.getY();
152
153 switch (event.getAction()) {
154 case MotionEvent.ACTION_DOWN:
155 if (!isHit((int) nowX, (int) nowY))
156 return false;
157 lastX = nowX;
158 lastY = nowY;
159 oldAngle = angle;
160 break;
161 case MotionEvent.ACTION_MOVE:
162 double increment = computeAngle(lastX, lastY, nowX, nowY);
163 if (increment != 0) {
164 angle += increment;
165 if (maxAngle != INVALID_ANGLE && angle > maxAngle) {
166 angle = maxAngle;
167 } else if (minAngle != INVALID_ANGLE && angle < minAngle) {
168 angle = minAngle;
169 }
170 invalidate();
171 }
172 lastX = nowX;
173 lastY = nowY;
174 break;
175 case MotionEvent.ACTION_UP:
176 if (anglelistener != null) {
177 anglelistener.onAngleChanged(oldAngle, angle);
178 }
179 if (colorListener != null && ringRatio != 0) {
180 int width = getWidth();
181 int r = (int) (width / 2 - ringRatio * width / 4);
182 int x = 0;
183 int y = 0;
184 double radian = (-angle % 360) * Math.PI / 180;
185 x = (int) (width / 2 + r * Math.sin(radian));
186 y = (int) (width / 2 - r * Math.cos(radian));
187 int color = rotatedBitmap.getPixel(x, y);
188 colorListener.onColorChanged(Color.red(color), Color.green(color), Color.blue(color));
189 }
190 invalidate();
191 break;
192 }
193
194 return true;
195 }
196
197 public static interface OnAngleChangedListener {
198 public void onAngleChanged(double oldAngle, double newAngle);
199 }
200
201 public static interface OnColorChangedListener {
202 public void onColorChanged(int red, int green, int blue);
203 }
204
205 public void OnAngleChangedListener(OnAngleChangedListener listener) {
206 this.anglelistener = listener;
207 }
208
209 public void setOnColorChangedListener(OnColorChangedListener listener) {
210 this.colorListener = listener;
211 }
212
213 public void setRotateDrawable(Drawable rotatedPicture, float ringRatio) {
214 this.rotatedPicture = rotatedPicture;
215 this.ringRatio = ringRatio;
216 }
217
218 public void setRotateDrawable(Drawable rotatedPicture) {
219 this.rotatedPicture = rotatedPicture;
220 }
221
222 public void setMaxRotatedAngle(int maxAngle) {
223 this.maxAngle = maxAngle;
224 }
225
226 public void setMinRotatedAngle(int minAngle) {
227 this.minAngle = minAngle;
228 }
229
230 public void setAngle(double angle) {
231 this.angle = angle;
232 postInvalidate();
233 }
234
235 protected double getAngle() {
236 return angle;
237 }
238 }

  那个圆形拖动条则继承自CircleView,然后重写onDraw方法绘制进度。代码如下:


 1 import android.content.Context;
2 import android.graphics.Canvas;
3 import android.graphics.Paint;
4 import android.graphics.RectF;
5 import android.graphics.Paint.Cap;
6 import android.graphics.Paint.Style;
7 import android.util.AttributeSet;
8
9 public class ProgressCircleView extends CircleView {
10 private int progressBackground;
11 private int progress;
12
13 private RectF progressRectF;
14 private int progressBgWidth, progressWidth;
15 private Paint progressBgPaint;
16 private Paint progressPaint;
17
18 public ProgressCircleView(Context context) {
19 this(context, null);
20 }
21
22 public ProgressCircleView(Context context, AttributeSet attrs) {
23 this(context, attrs, 0);
24 }
25
26 public ProgressCircleView(Context context, AttributeSet attrs, int defStyle) {
27 super(context, attrs, defStyle);
28 super.setMaxRotatedAngle(360);
29 super.setMinRotatedAngle(0);
30 }
31
32 @Override
33 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
34 super.onSizeChanged(w, h, oldw, oldh);
35 int offset = progressWidth / 2 + 1;
36 progressRectF = new RectF(offset, offset, w - offset, h - offset);
37 }
38
39 @Override
40 protected void onDraw(Canvas canvas) {
41 super.onDraw(canvas);
42 // draw bg
43 canvas.drawArc(progressRectF, 0, 360, false, progressBgPaint);
44 // draw arc
45 canvas.drawArc(progressRectF, -90, (float) getAngle(), false, progressPaint);
46 }
47
48 public void setProgressBackground(int width, int color) {
49 int widthDp = (int) (width * getResources().getDisplayMetrics().density);
50 Paint paint = new Paint();
51 paint.setAntiAlias(true);
52 paint.setAlpha(0xff);
53 paint.setStrokeWidth(widthDp);
54 paint.setStyle(Style.STROKE);
55 paint.setColor(color);
56 progressBgWidth = widthDp;
57 progressBgPaint = paint;
58 }
59
60 public void setProgress(int width, int color) {
61 int widthDp = (int) (width * getResources().getDisplayMetrics().density);
62 Paint paint = new Paint();
63 paint.setAntiAlias(true);
64 paint.setAlpha(0xff);
65 paint.setStrokeWidth(widthDp);
66 paint.setStyle(Style.STROKE);
67 paint.setColor(color);
68 paint.setStrokeCap(Cap.ROUND);
69 progressWidth = widthDp;
70 progressPaint = paint;
71 }
72
73 }

  简单使用的Activity:


 1 public class MainActivity extends Activity {
2
3 private double oldAngle;
4 boolean isClicked;
5 @Override
6 protected void onCreate(Bundle savedInstanceState) {
7 super.onCreate(savedInstanceState);
8 setContentView(R.layout.color_light_control_panel);
9
10 CircleView cv = (CircleView) findViewById(R.id.colorCircle);
11 cv.setRotateDrawable(getResources().getDrawable(R.drawable.color_light_color_circle), 0.15f);
12 cv.setOnColorChangedListener(new OnColorChangedListener() {
13
14 @Override
15 public void onColorChanged(int red, int green, int blue) {
16 Log.d("onColorChanged", red + " " + green + " " + blue + " ");
17
18 }
19 });
20 // cv.setMaxRotatedAngle(360);
21 // cv.setMinRotatedAngle(0);
22 final ProgressCircleView pcv = (ProgressCircleView) findViewById(R.id.progress);
23 pcv.setRotateDrawable(getResources().getDrawable(R.drawable.color_light_progress));
24 pcv.setProgress(10, 0xFF32CFEB);
25 pcv.setProgressBackground(10, 0xFF3A3A3A);
26
27 pcv.OnAngleChangedListener(new OnAngleChangedListener() {
28
29 @Override
30 public void onAngleChanged(double oldAngle, double newAngle) {
31 Log.d("angle=", "oldAngle=" + oldAngle + " newAngle=" + newAngle);
32 MainActivity.this.oldAngle = oldAngle;
33 }
34 });
35
36 View btn = findViewById(R.id.switch_btn);
37 btn.setOnClickListener(new OnClickListener() {
38
39 @Override
40 public void onClick(View v) {
41 pcv.setAngle(oldAngle);
42 }
43 });
44 }
45 }

  最后是布局文件:


 1 <?xml version="1.0" encoding="utf-8"?>
2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 android:background="#ff000000" >
6
7 <com.example.test2.CircleView
8 android:id="@+id/colorCircle"
9 android:layout_width="242dp"
10 android:layout_height="242dp"
11 android:layout_centerInParent="true" >
12 </com.example.test2.CircleView>
13
14 <com.example.test2.ProgressCircleView
15 android:id="@+id/progress"
16 android:layout_width="164dp"
17 android:layout_height="164dp"
18 android:layout_centerInParent="true" >
19 </com.example.test2.ProgressCircleView>
20
21 <View
22 android:id="@+id/switch_btn"
23 android:layout_width="61dp"
24 android:layout_height="61dp"
25 android:background="@drawable/color_light_switch_on"
26 android:layout_centerInParent="true" >
27 </View>
28
29 </RelativeLayout>

一个不错效果的调光调色开关

时间: 2024-10-17 05:33:08

一个不错效果的调光调色开关的相关文章

RGBW ------ 调光调色

gamma 人眼对光强属于非线性响应,所以软件对亮度变化曲线做gamma修正来给人以亮度均匀变化的视觉体验 光源对物体的显色能力称为显色性,是通过与同色温的参考或基准光源(白炽灯或画光)下物体外观颜色的比较. 根据杨-亥姆霍兹的三原色理论,色的感觉是由于三种原色光刺激的综合结果.在红.绿,蓝三原色系统中,红.绿.蓝的刺激量分别以R.G.B表示之.由于从实际光谱中选定的红.绿.蓝三原色光不可能调(匹)配出存在于自然界的所有色彩,所以,CIE于1931年从理论上假设了并不存在于自然界的三种原色,即理

调光设备术语:调光曲线(转)

源:调光设备术语:调光曲线 核心提示:调光曲线是调光设备重要的参数之一,它直接影响到了灯光输出的效果,是数字化调光设备性能的体现. 上面这句话包含了三点内容,我们逐条解析. 调光曲线是调光设备重要的参数之一 本文指的调光设备不局限于灯控台这一点,凡是与调光有关的东西,都是调光设备.最常见的还有硅箱.调光曲线就是这些设备手册中经常要列举的一项参数. 调光曲线简而言之通俗地讲,就是一个调光设备在接收到输入信号之后根据预定函数进行光的输出,这个函数图像就是调光曲线. 下图X轴代表输入,用百分比表示,Y

一个不错的loading效果

一个不错的loading加载效果,弹性收缩,效果不错,学习android动画的朋友可以下载来研究研究本例子其实由SeekBar实现,由MetaballView,MetaballDebugView实现动画效果.当滑动到有一个位置的时候设置选中和未选中状态.metaballView.setPaintMode();           debugMetaballView.setPaintMode();设置SeekBar 的进度debugMetaballView.setMaxDistance(progr

DALI调光方案

DALI调光方案使用手册 公  司: 深圳市万秀电子有限公司 网  站: http://www.wanxiucx.com 总  机: 0755-23215689 联系人: 张先生 手  机: 13923882807 Q Q  : 813267849 邮  箱: [email protected] 一.概述(联系人:张先生,电话:13923882807,QQ:813267849) 欢迎使用本公司的DALI解码模块,该模块支持"DALI第一套协议","DALI第二套协议"

iwatt(艾瓦特)IW3689/IW3688隔离/非隔离离线可控硅调光

品牌名称:艾瓦特   QQ  2892715427 特点 隔离/非隔离离线120VAC / 230VAC LED驱动高达20W的输出功率宽线的频率范围(从45Hz至66hz)符合IEC61000-3-2谐波电流要求总谐波失真小于20%的PF > 0.92优良的调光器的兼容性宽调光范围1%到100%共振控制,以实现高效率(典型> 85%不调光)LED过流保护和过温关机紧调节LED电流(±5%)快速启动(小于0.5s没有调光) 4 规格; 隔离/非隔离离线120VAC / 230VAC SOP封装

兼容可控硅调光的一款LED驱动电路记录

1.该款电路为兼容可控硅调光的LED驱动电路,采用OB3332为开关控制IC,拓扑方案为Buck: 2.FB1:磁珠的单位是欧姆,而不是亨利,这一点要特别注意.因为磁珠的单位是按照它在某一频率 产生的阻抗来标称的,阻抗的单位也是欧姆.磁珠的 DATASHEET上一般会提供频率和阻抗的特性曲线图,一般以100MHz为标准,比如[email protected],意思就是在100MHz频率的时候磁珠的阻抗相当于600欧姆: 3.UFM14PL-TP普通二极管: Maximum Recurrent P

DALI2调光协议简介

DALI2调光协议简介 一.概述(13923882807-QQ:813267849) 欢迎使用本公司的DALI解码模块,拥有"DALI第一套协议" (DALI 1.0),"DALI第二套协议"(DALI 2.0),"DALI NFC","DALI调色温"模块,具备10年的DALI行业经验,支持客户LED电源过DALI认证. 该模块体积微小,采用了先进的控制技术,完美兼容TRIDONIC(锐高),OSRAM(欧司朗),PHILI

一个不错的标签管理浏览器插件

推荐一个不错的插件,支持chrome和UC浏览器,能够右键添加当前活动的网页.采用云存储的方式进行同步,与电脑无关.并且有更好的标签编辑方式. 可以通过添加自己想保留,想在不同的电脑,不同的平台导入标签,告别繁琐的浏览器自带的标签导入功能. 下载网站:http://m.wsh.0letter.com/tag

[jQuery编程挑战]006 生成一个倒计时效果

<!DOCTYPE html> <html lang="zh"> <head> <meta charset="utf-8"/> <title>生成一个倒计时效果</title> <style type="text/css"> body{ margin:0; padding:0; background: orange; width: 100%; height: 10