Son aktif 1741767137

彩虹自定义声音振动曲线view,来自宋总

MainActivity.kt Ham
1class MainActivity : AppCompatActivity() {
2 override fun onCreate(savedInstanceState: Bundle?) {
3 super.onCreate(savedInstanceState)
4 runOnUiThread {
5 binding.voiceView.setVolume(volume)
6 }
7 }
8}
RainbowVoiceLineView.java Ham
1import android.content.Context;
2import android.content.res.TypedArray;
3import android.graphics.Canvas;
4import android.graphics.Color;
5import android.graphics.LinearGradient;
6import android.graphics.Paint;
7import android.graphics.Path;
8import android.graphics.Shader;
9import android.util.AttributeSet;
10import android.view.View;
11
12import com.whhh.team.R;
13
14import java.util.ArrayList;
15import java.util.List;
16
17/**
18 * 彩虹自定义声音振动曲线view
19 */
20public class RainbowVoiceLineView extends View {
21 private Paint paintVoiceLine;
22 private float translateX = 0;
23 private boolean isSet = false; //是否有语音流输入
24 private boolean isShow = true; //是否开始绘制
25 private float amplitude = 1; //振幅
26 private float volume = 10; //音量
27 private float fineness = 0.2f; //精细度 值越小,曲线越顺滑,但在一些旧手机上,会出现帧率过低的情况,可以把这个值调大一点,在图片的顺滑度与帧率之间做一个取舍
28 private float targetVolume = 1;
29 private int lineSpeed = 90; //波动线的横向移动速度,线的速度的反比,即这个值越小,线横向移动越快,越大线移动越慢
30 private long lastTime = 0;
31
32 List<Path> paths = null;
33
34 private int indexColor = -1; //颜色渲染的数组index
35 private int inputCount = 0; //用于统计语音输入次数
36 private int color[] = {
37 Color.parseColor("#FFFF4744"), Color.parseColor("#FFFF8C44"), Color.parseColor("#FFFFF344"),
38 Color.parseColor("#FF57FF44"), Color.parseColor("#FF44FFDD"), Color.parseColor("#FF9E44FF"),
39 Color.parseColor("#FFFF44BA"), Color.parseColor("#FFFF444D")};
40
41 private int colors[][] = {
42 color,
43 {color[6], color[0], color[1], color[2], color[3], color[4], color[5]},
44 {color[5], color[6], color[0], color[1], color[2], color[3], color[4]},
45 {color[4], color[5], color[6], color[0], color[1], color[2], color[3]},
46 {color[3], color[4], color[5], color[6], color[0], color[1], color[2]},
47 {color[2], color[3], color[4], color[5], color[6], color[0], color[1]},
48 {color[1], color[2], color[3], color[4], color[5], color[6], color[0]}};
49
50 private static LinearGradient linearGradient;
51
52 public RainbowVoiceLineView(Context context) {
53 this(context, null);
54 }
55
56 public RainbowVoiceLineView(Context context, AttributeSet attrs) {
57 this(context, attrs, 0);
58 }
59
60 public RainbowVoiceLineView(Context context, AttributeSet attrs, int defStyleAttr) {
61 super(context, attrs, defStyleAttr);
62 initAtts(context, attrs);
63 }
64
65 //初始化 设置自定义属性
66 private void initAtts(Context context, AttributeSet attrs) {
67 TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VoiceLineView);
68 lineSpeed = typedArray.getInt(R.styleable.VoiceLineView_lineSpeed, 150);
69// fineness = typedArray.getInt(R.styleable.VoiceLineView_fineness, 3);
70
71
72 paths = new ArrayList<>(15);
73 for (int i = 0; i < 15; i++) {
74 paths.add(new Path());
75 }
76 typedArray.recycle();
77 }
78
79 @Override
80 protected void onDraw(Canvas canvas) {
81 super.onDraw(canvas);
82 drawVoiceLine(canvas);
83 if (isShow) {//如果是true则刷新 产生动画 否则不刷新 即没有动画效果
84 invalidate();
85 }
86 }
87
88 //绘制图形
89 private void drawVoiceLine(Canvas canvas) {
90 lineChange();
91
92 if (paintVoiceLine == null) {
93 paintVoiceLine = new Paint();
94 paintVoiceLine.setAntiAlias(true);
95 paintVoiceLine.setStyle(Paint.Style.STROKE);
96 paintVoiceLine.setStrokeWidth(5f);
97 }
98
99 canvas.save();
100 int moveX = getWidth();
101 int moveY = getHeight() / 2;
102
103 //将所有path起点移到左边中点
104 for (int i = 0; i < paths.size(); i++) {
105 paths.get(i).reset();
106 paths.get(i).moveTo(0, moveY);
107 }
108
109
110 //依次从左至右绘制图形
111 for (float i = 0; i < moveX; i += fineness) {
112 amplitude = 4 * volume * i / moveX - 4 * volume * i * i / moveX / moveX;
113 for (int n = 1; n <= paths.size(); n++) {
114 float sin = amplitude * (float) Math.sin((i - Math.pow(1.22, n)) * Math.PI / 180 - translateX);
115 paths.get(n - 1).lineTo(i, (2 * n * sin / paths.size() - 15 * sin / paths.size() + moveY));
116 }
117 }
118
119 //通过设置透明度产生层次效果 180 越大线越不透明
120 for (int n = 0; n < paths.size(); n++) {
121 if (n == paths.size() - 1) {
122 paintVoiceLine.setAlpha(255);
123 } else {
124 paintVoiceLine.setAlpha(n * 180 / paths.size());
125 }
126 if (paintVoiceLine.getAlpha() > 0) {
127 canvas.drawPath(paths.get(n), paintVoiceLine);
128 }
129 }
130 canvas.restore();
131 }
132
133 //对线条颜色进行渲染 inputCount可以控制渲染的速度
134 private void setLinearGradientColor() {
135 inputCount++;
136 if (inputCount % 3 == 0) {
137 indexColor++;
138 if (indexColor > 6) {
139 indexColor = 0;
140 }
141 linearGradient = new LinearGradient(0, getHeight() / 2, getWidth(), getHeight() / 2, colors[indexColor], null, Shader.TileMode.MIRROR);
142 paintVoiceLine.setShader(linearGradient);
143 }
144 }
145
146 //通过声音改变振幅
147 public void setVolume(int vol) {
148 isSet = true;
149 if (vol < 30) {
150 targetVolume = 0;
151 } else if (vol >= 30 && vol < 40) {
152 targetVolume = (float) (0.25 * getHeight() / 2);
153 } else if (vol >= 40 && vol < 45) {
154 targetVolume = (float) (0.50 * getHeight() / 2);
155 } else if (vol >= 45 && vol < 60) {
156 targetVolume = (float) (0.75 * getHeight() / 2);
157 } else {
158 targetVolume = (float) (getHeight() / 2);
159 }
160 }
161
162 public boolean isShow() {
163 return isShow;
164 }
165
166 //启动动画效果 即开始绘制
167 public void startWave() {
168 isShow = true;
169 invalidate();
170 }
171
172 //停止动画效果 即停止绘制
173 public void stopWave() {
174 isShow = false;
175 invalidate();
176 }
177
178 //通过每次改变产生位移量 形成动画
179 private void lineChange() {
180 setLinearGradientColor();
181 //根据时间改变偏移量
182 if (lastTime == 0) {
183 lastTime = System.currentTimeMillis();
184 translateX += 1.5;
185 } else {
186 if (System.currentTimeMillis() - lastTime > lineSpeed) {
187 lastTime = System.currentTimeMillis();
188 translateX += 1.5;
189 } else {
190 return;
191 }
192 }
193 if (volume < targetVolume && isSet) { //声贝大于volume 而且是处于声音输入状态
194 volume = targetVolume;
195 } else {
196 isSet = false;
197
198 if (volume <= 10) {
199 volume = 0;
200 } else {//当结束说话的时候,将振幅缓缓降下来
201 if (volume < getHeight() / 10) {
202 volume -= getHeight() / 20;
203 } else {
204 volume -= getHeight() / 10;
205 }
206 }
207 }
208 }
209}
attrs.xml Ham
1<?xml version="1.0" encoding="utf-8"?>
2<resources>
3
4 <declare-styleable name="TitleView">
5 <attr name="title_title" format="string" />
6 </declare-styleable>
7
8 <declare-styleable name="FileView">
9 <attr name="show_title" format="boolean" />
10 </declare-styleable>
11
12 <declare-styleable name="ParticlesView">
13 <attr name="density" format="integer" />
14 <attr name="frameDelayMillis" format="integer" />
15 <attr name="lineColor" format="color" />
16 <attr name="lineLength" format="dimension" />
17 <attr name="lineThickness" format="dimension" />
18 <attr name="particleColor" format="color" />
19 <attr name="particleRadiusMax" format="dimension" />
20 <attr name="particleRadiusMin" format="dimension" />
21 <attr name="speedFactor" format="float" />
22 </declare-styleable>
23 <declare-styleable name="ItemView">
24 <attr name="leftText" format="string" />
25 <attr name="rightText" format="string" />
26 <attr name="unit" format="string" />
27 <attr name="android:background" format="reference|color" />
28 <attr name="mode" format="integer">
29 <enum name="text" value="0" />
30 <enum name="edit" value="1" />
31 <enum name="check" value="2" />
32 <enum name="img" value="3" />
33 <enum name="desc" value="5" />
34 <enum name="menu" value="6" />
35 </attr>
36 <attr name="android:inputType" />
37 <attr name="android:hint" />
38 <attr name="rightTextColor" format="reference|color" />
39 <attr name="leftTextGravity">
40 <flag name="top" value="0x30" />
41 <flag name="bottom" value="0x50" />
42 <flag name="left" value="0x03" />
43 <flag name="right" value="0x05" />
44 <flag name="center_vertical" value="0x10" />
45 <flag name="fill_vertical" value="0x70" />
46 <flag name="center_horizontal" value="0x01" />
47 <flag name="fill_horizontal" value="0x07" />
48 <flag name="center" value="0x11" />
49 <flag name="fill" value="0x77" />
50 <flag name="clip_vertical" value="0x80" />
51 <flag name="clip_horizontal" value="0x08" />
52 <flag name="start" value="0x00800003" />
53 <flag name="end" value="0x00800005" />
54 </attr>
55 <attr name="rightTextGravity">
56 <flag name="top" value="0x30" />
57 <flag name="bottom" value="0x50" />
58 <flag name="left" value="0x03" />
59 <flag name="right" value="0x05" />
60 <flag name="center_vertical" value="0x10" />
61 <flag name="fill_vertical" value="0x70" />
62 <flag name="center_horizontal" value="0x01" />
63 <flag name="fill_horizontal" value="0x07" />
64 <flag name="center" value="0x11" />
65 <flag name="fill" value="0x77" />
66 <flag name="clip_vertical" value="0x80" />
67 <flag name="clip_horizontal" value="0x08" />
68 <flag name="start" value="0x00800003" />
69 <flag name="end" value="0x00800005" />
70 </attr>
71 <attr name="leftTextColor" format="reference|color" />
72 <attr name="rightTextSize" format="dimension" />
73 <attr name="leftTextSize" format="dimension" />
74 <attr name="item_leftTextStyle">
75 <flag name="normal" value="0" />
76 <flag name="bold" value="1" />
77 <flag name="italic" value="2" />
78 </attr>
79 <attr name="item_rightTextStyle">
80 <flag name="normal" value="0" />
81 <flag name="bold" value="1" />
82 <flag name="italic" value="2" />
83 </attr>
84 <attr name="line_color" format="color" />
85 <attr name="android:maxLength" />
86 <attr name="show_arrow" format="boolean" />
87 <attr name="show_line" format="boolean" />
88 <attr name="show_icon" format="boolean" />
89 <attr name="left_icon" format="reference|color" />
90 <attr name="right_icon" format="reference|color" />
91 </declare-styleable>
92
93 <declare-styleable name="CameraView">
94
95 <attr name="cameraPictureSizeMinWidth" format="integer|reference" />
96 <attr name="cameraPictureSizeMaxWidth" format="integer|reference" />
97 <attr name="cameraPictureSizeMinHeight" format="integer|reference" />
98 <attr name="cameraPictureSizeMaxHeight" format="integer|reference" />
99 <attr name="cameraPictureSizeMinArea" format="integer|reference" />
100 <attr name="cameraPictureSizeMaxArea" format="integer|reference" />
101 <attr name="cameraPictureSizeSmallest" format="boolean" />
102 <attr name="cameraPictureSizeBiggest" format="boolean" />
103 <attr name="cameraPictureSizeAspectRatio" format="string|reference" />
104
105 <attr name="cameraVideoSizeMinWidth" format="integer|reference" />
106 <attr name="cameraVideoSizeMaxWidth" format="integer|reference" />
107 <attr name="cameraVideoSizeMinHeight" format="integer|reference" />
108 <attr name="cameraVideoSizeMaxHeight" format="integer|reference" />
109 <attr name="cameraVideoSizeMinArea" format="integer|reference" />
110 <attr name="cameraVideoSizeMaxArea" format="integer|reference" />
111 <attr name="cameraVideoSizeSmallest" format="boolean" />
112 <attr name="cameraVideoSizeBiggest" format="boolean" />
113 <attr name="cameraVideoSizeAspectRatio" format="string|reference" />
114
115 <attr name="cameraSnapshotMaxWidth" format="integer|reference" />
116 <attr name="cameraSnapshotMaxHeight" format="integer|reference" />
117
118 <attr name="cameraFrameProcessingMaxWidth" format="integer|reference" />
119 <attr name="cameraFrameProcessingMaxHeight" format="integer|reference" />
120 <attr name="cameraFrameProcessingFormat" format="integer|reference" />
121 <attr name="cameraFrameProcessingPoolSize" format="integer|reference" />
122 <attr name="cameraFrameProcessingExecutors" format="integer|reference" />
123
124 <attr name="cameraVideoBitRate" format="integer|reference" />
125 <attr name="cameraAudioBitRate" format="integer|reference" />
126 <attr name="cameraPreviewFrameRate" format="integer|reference" />
127 <attr name="cameraPreviewFrameRateExact" format="boolean" />
128
129 <attr name="cameraGestureTap" format="enum">
130 <enum name="none" value="0" />
131 <enum name="autoFocus" value="1" />
132 <enum name="takePicture" value="2" />
133 <enum name="takePictureSnapshot" value="3" />
134 </attr>
135
136 <attr name="cameraGestureLongTap" format="enum">
137 <enum name="none" value="0" />
138 <enum name="autoFocus" value="1" />
139 <enum name="takePicture" value="2" />
140 <enum name="takePictureSnapshot" value="3" />
141 </attr>
142
143 <attr name="cameraGesturePinch" format="enum">
144 <enum name="none" value="0" />
145 <enum name="zoom" value="4" />
146 <enum name="exposureCorrection" value="5" />
147 <enum name="filterControl1" value="6" />
148 <enum name="filterControl2" value="7" />
149 </attr>
150
151 <attr name="cameraGestureScrollHorizontal" format="enum">
152 <enum name="none" value="0" />
153 <enum name="zoom" value="4" />
154 <enum name="exposureCorrection" value="5" />
155 <enum name="filterControl1" value="6" />
156 <enum name="filterControl2" value="7" />
157 </attr>
158
159 <attr name="cameraGestureScrollVertical" format="enum">
160 <enum name="none" value="0" />
161 <enum name="zoom" value="4" />
162 <enum name="exposureCorrection" value="5" />
163 <enum name="filterControl1" value="6" />
164 <enum name="filterControl2" value="7" />
165 </attr>
166
167 <attr name="cameraEngine" format="enum">
168 <enum name="camera1" value="0" />
169 <enum name="camera2" value="1" />
170 </attr>
171
172 <attr name="cameraPreview" format="enum">
173 <enum name="surface" value="0" />
174 <enum name="texture" value="1" />
175 <enum name="glSurface" value="2" />
176 </attr>
177
178 <attr name="cameraFacing" format="enum">
179 <enum name="back" value="0" />
180 <enum name="front" value="1" />
181 </attr>
182
183 <attr name="cameraHdr" format="enum">
184 <enum name="off" value="0" />
185 <enum name="on" value="1" />
186 </attr>
187
188 <attr name="cameraFlash" format="enum">
189 <enum name="off" value="0" />
190 <enum name="on" value="1" />
191 <enum name="auto" value="2" />
192 <enum name="torch" value="3" />
193 </attr>
194
195 <attr name="cameraWhiteBalance" format="enum">
196 <enum name="auto" value="0" />
197 <enum name="incandescent" value="1" />
198 <enum name="fluorescent" value="2" />
199 <enum name="daylight" value="3" />
200 <enum name="cloudy" value="4" />
201 </attr>
202
203 <attr name="cameraMode" format="enum">
204 <enum name="picture" value="0" />
205 <enum name="video" value="1" />
206 </attr>
207
208 <attr name="cameraAudio" format="enum">
209 <enum name="off" value="0" />
210 <enum name="on" value="1" />
211 <enum name="mono" value="2" />
212 <enum name="stereo" value="3" />
213 </attr>
214
215 <attr name="cameraGrid" format="enum">
216 <enum name="off" value="0" />
217 <enum name="draw3x3" value="1" />
218 <enum name="draw4x4" value="2" />
219 <enum name="drawPhi" value="3" />
220 </attr>
221
222 <attr name="cameraGridColor" format="color|reference" />
223
224 <attr name="cameraPlaySounds" format="boolean" />
225
226 <attr name="cameraVideoMaxSize" format="float" />
227
228 <attr name="cameraVideoMaxDuration" format="integer" />
229
230 <attr name="cameraVideoCodec" format="enum">
231 <enum name="deviceDefault" value="0" />
232 <enum name="h263" value="1" />
233 <enum name="h264" value="2" />
234 </attr>
235
236 <attr name="cameraAudioCodec" format="enum">
237 <enum name="deviceDefault" value="0" />
238 <enum name="aac" value="1" />
239 <enum name="heAac" value="2" />
240 <enum name="aacEld" value="3" />
241 </attr>
242
243 <attr name="cameraAutoFocusResetDelay" format="integer|reference" />
244
245 <attr name="cameraAutoFocusMarker" format="string|reference" />
246
247 <attr name="cameraFilter" format="string|reference" />
248
249 <attr name="cameraUseDeviceOrientation" format="boolean" />
250
251 <attr name="cameraPictureMetering" format="boolean|reference" />
252 <attr name="cameraPictureSnapshotMetering" format="boolean|reference" />
253
254 <attr name="cameraPictureFormat" format="enum">
255 <enum name="jpeg" value="0" />
256 <enum name="dng" value="1" />
257 </attr>
258
259 <attr name="cameraRequestPermissions" format="boolean|reference" />
260 <attr name="cameraExperimental" format="boolean|reference" />
261
262 <attr name="cameraDrawHardwareOverlays" format="boolean" />
263
264 </declare-styleable>
265
266 <declare-styleable name="CameraView_Layout">
267 <attr name="layout_drawOnPreview" format="boolean" />
268 <attr name="layout_drawOnPictureSnapshot" format="boolean" />
269 <attr name="layout_drawOnVideoSnapshot" format="boolean" />
270
271 </declare-styleable>
272
273 <declare-styleable name="VoiceLineView">
274 <!--中间线的颜色,就是波形的时候,大家可以看到,中间有一条直线,就是那个-->
275 <attr name="middleLine" format="color" />
276 <!--中间线的高度,因为宽度是充满的-->
277 <attr name="middleLineHeight" format="dimension" />
278 <!--波动的线的颜色,如果是距形样式的话,刚是距形的颜色-->
279 <attr name="voiceLine" format="color" />
280 <!--波动线的横向移动速度,线的速度的反比,即这个值越小,线横向移动越快,越大线移动越慢,默认90-->
281 <attr name="lineSpeed" format="integer" />
282 <!--矩形的宽度-->
283 <attr name="rectWidth" format="dimension" />
284 <!--矩形之间的间隔-->
285 <attr name="rectSpace" format="dimension" />
286 <!--矩形的初始高度,就是没有声音的时候,矩形的高度-->
287 <attr name="rectInitHeight" format="dimension" />
288 <!--所输入音量的最大值-->
289 <attr name="maxVolume" format="float" />
290 <!--控件的样式,一共有两种,波形或者矩形-->
291 <attr name="viewMode">
292 <enum name="line" value="0" />
293 <enum name="rect" value="1" />
294 </attr>
295 <!--灵敏度,默认值是4-->
296 <attr name="sensibility">
297 <enum name="one" value="1" />
298 <enum name="two" value="2" />
299 <enum name="three" value="3" />
300 <enum name="four" value="4" />
301 <enum name="five" value="5" />
302 </attr>
303 <!--精细度,绘制曲线的时候,每几个像素绘制一次,默认是1,一般,这个值越小,曲线越顺滑,
304 但在一些旧手机上,会出现帧率过低的情况,可以把这个值调大一点,在图片的顺滑度与帧率之间做一个取舍-->
305 <attr name="fineness">
306 <enum name="one" value="1" />
307 <enum name="two" value="2" />
308 <enum name="three" value="3" />
309 </attr>
310 </declare-styleable>
311
312</resources>