Son aktif 1741767137

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

doracoin revised this gist 1741767137. Go to revision

3 files changed, 529 insertions

MainActivity.kt(file created)

@@ -0,0 +1,8 @@
1 + class MainActivity : AppCompatActivity() {
2 + override fun onCreate(savedInstanceState: Bundle?) {
3 + super.onCreate(savedInstanceState)
4 + runOnUiThread {
5 + binding.voiceView.setVolume(volume)
6 + }
7 + }
8 + }

RainbowVoiceLineView.java(file created)

@@ -0,0 +1,209 @@
1 + import android.content.Context;
2 + import android.content.res.TypedArray;
3 + import android.graphics.Canvas;
4 + import android.graphics.Color;
5 + import android.graphics.LinearGradient;
6 + import android.graphics.Paint;
7 + import android.graphics.Path;
8 + import android.graphics.Shader;
9 + import android.util.AttributeSet;
10 + import android.view.View;
11 +
12 + import com.whhh.team.R;
13 +
14 + import java.util.ArrayList;
15 + import java.util.List;
16 +
17 + /**
18 + * 彩虹自定义声音振动曲线view
19 + */
20 + public 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(file created)

@@ -0,0 +1,312 @@
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>
Newer Older