Android 自定义控件 (神级)+MediaRecoder 录音,android 开发基础应用
private double rad(double deg) {return deg / 180 * Math.PI;}}
3.正弦函数的动起来
什么影响正弦函数的横向位移--相位:φ
那还等什么,ValueAnimator 走起,从 0~2 * Math.PI
//数字时间流 mAnimator = ValueAnimator.ofFloat(0, (float) (2 * Math.PI));mAnimator.setDuration(1000);mAnimator.setRepeatMode(ValueAnimator.RESTART);mAnimator.setInterpolator(new LinearInterpolator());mAnimator.addUpdateListener(a -> {φ = (float) a.getAnimatedValue();invalidate();});
就这么简单?---是的
4.让凸起的部分渐渐平息
不就是对 A 值进行渐变嘛...非常简单
mAnimator.addUpdateListener(a -> {φ = (float) a.getAnimatedValue();A = (float) (mMaxHeight* (1 - (float) a.getAnimatedValue() / (2 * Math.PI)));invalidate();});
二、加入衰减函数与渐变色
1.加入衰减函数
虽然有那么点感觉,但是还是差很多,关键在对应法则,说起来也简单
但是操作起来挺费劲,衰减函数凑了好一会...
/**
对应法则
@param x 原像(自变量)
@return 像(因变量)*/private double f(double x) {double len = max - min;double a = 4 / (4 + Math.pow(rad(x / Math.PI * 800 / len), 4));double aa = Math.pow(a, 2.5);ω = 2 * Math.PI / (rad(len) / 2);double y = aa * A * Math.sin(ω * rad(x) - φ);return y;}
2.加渐变色
什么颜色好呢,好吧,我计较懒,搭条彩虹吧(以前实现过)
int[] colors = new int[]{Color.parseColor("#F60C0C"),//红 Color.parseColor("#F3B913"),//橙 Color.parseColor("#E7F716"),//黄 Color.parseColor("#3DF30B"),//绿 Color.parseColor("#0DF6EF"),//青 Color.parseColor("#0829FB"),//蓝 Color.parseColor("#B709F4"),//紫};float[] pos = new float[]{1.f / 7, 2.f / 7, 3.f / 7, 4.f / 7, 5.f / 7, 6.f / 7, 1};mPaint.setShader(new LinearGradient((int) min, 0, (int) max, 0,colors, pos,Shader.TileMode.CLAMP));
三、第二条曲线的绘制
1.路径的形成
会了一个,另一个 Y 镜像一下就行了(y 坐标边-y)
private void formPath() {mPath.moveTo((float) min, (float) f(min));mReflexPath.moveTo((float) min, (float) f(min));for (double x = min; x <= max; x++) {double y = f(x);mPath.lineTo((float) x, (float) y);mReflexPath.lineTo((float) x, -(float) y);}}
2.绘制第二条曲线:onDraw
第二条淡一点
mPaint.setAlpha(255);canvas.drawPath(mPath, mPaint);mPaint.setAlpha(66);canvas.drawPath(mReflexPath, mPaint);
3.高度设置
我的用意是在录音是监听音量大小,然后让图象波动
暴漏设置高度的方法,在设置时执行动画,下面是点击设置随机高度效果
/**
设置高度
@param maxHeight*/public void setMaxHeight(double maxHeight) {mMaxHeight = maxHeight;mAnimator.start();invalidate();}
四、扫尾--封装
该 dp 的 dp,该删的删,该封装的封装,该优化的优化,直接贴代码
/**
作者:张风捷特烈<br/>
时间:2018/11/16 0016:9:04<br/>
邮箱:1981462002@qq.com<br/>
说明:贝塞尔三次曲线--旋律视图*/public class RhythmView extends View {private double mMaxHeight = 0;//最到点 private double mPerHeight = 0;//最到点
private double min;//最小 xprivate double max;//最大 x
private double φ = 0;//初相 private double A = mMaxHeight;//振幅 private double ω;//角频率
private Paint mPaint;//主画笔 private Path mPath;//主路径 private Path mReflexPath;//镜像路径 private ValueAnimator mAnimator;private int mHeight;private int mWidth;
public RhythmView(Context context) {this(context, null);}
public RhythmView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);init();//初始化}
private void init() {//初始化主画笔 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint.setColor(Color.BLUE);mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth(dp(2));//初始化主路径 mPath = new Path();mReflexPath = new Path();//数字时间流 mAnimator = ValueAnimator.ofFloat(0, (float) (2 * Math.PI));mAnimator.setDuration(1000);mAnimator.setRepeatMode(ValueAnimator.RESTART);mAnimator.setInterpolator(new LinearInterpolator());mAnimator.addUpdateListener(a -> {φ = (float) a.getAnimatedValue();A = (float) (mMaxHeight * mPerHeight * (1 - (float) a.getAnimatedValue() / (2 * Math.PI)));invalidate();});}
public void setPerHeight(double perHeight) {mPerHeight = perHeight;mAnimator.start();}
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = MeasureSpec.getSize(widthMeasureSpec);mHeight = MeasureSpec.getSize(heightMeasureSpec);mMaxHeight = mHeight / 2 * 0.9;min = -mWidth / 2;max = mWidth / 2;handleColor();setMeasuredDimension(mWidth, mHeight);}
private void handleColor() {int[] colors = new int[]{Color.parseColor("#33F60C0C"),//红 Color.parseColor("#F3B913"),//橙 Color.parseColor("#E7F716"),//黄 Color.parseColor("#3DF30B"),//绿 Color.parseColor("#0DF6EF"),//青 Color.parseColor("#0829FB"),//蓝 Color.parseColor("#33B709F4"),//紫};
float[] pos = new float[]{1.f / 10, 2.f / 7, 3.f / 7, 4.f / 7, 5.f / 7, 9.f / 10, 1};
mPaint.setShader(new LinearGradient((int) min, 0, (int) max, 0,colors, pos,Shader.TileMode.CLAMP));}
@Overrideprotected void onDraw(Canvas canvas) {mPath.reset();mReflexPath.reset();super.onDraw(canvas);canvas.save();canvas.translate(mWidth / 2, mHeight / 2);formPath();mPaint.setAlpha(255);canvas.drawPath(mPath, mPaint);mPaint.setAlpha(66);canvas.drawPath(mReflexPath, mPaint);canvas.restore();}
/**
对应法则
@param x 原像(自变量)
@return 像(因变量)*/private double f(double x) {double len = max - min;double a = 4 / (4 + Math.pow(rad(x / Math.PI * 800 / len), 4));double aa = Math.pow(a, 2.5);ω = 2 * Math.PI / (rad(len) / 2);double y = aa * A * Math.sin(ω * rad(x) - φ);return y;}
private void formPath() {mPath.moveTo((float) min, (float) f(min));mReflexPath.moveTo((float) min, (float) f(min));for (double x = min; x <= max; x++) {double y = f(x);mPath.lineTo((float) x, (float) y);mReflexPath.lineTo((float) x, -(float) y);}
}
private double rad(double deg) {return deg / 180 * Math.PI;}
protected float dp(float dp) {return TypedValue.applyDime
nsion(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());}
}
五、MediaRecode 实现录音
第一天用
AudioTrack
实现了录音,MediaRecode 可以录音也可以录视频两者的区别
AudioTrack
麻烦一点,需要自己去操作字节流,但可以精致操作MediaRecode 相当于给你封装好了,你一步步走,给个文件就行了
1.录音的辅助类
/**
作者:张风捷特烈
时间:2018/4/16:10:33
邮箱:1981462002@qq.com
说明:MediaRecorder 录音帮助类*/public class MediaRecorderTask {private MediaRecorder mRecorder;private long mStartTime;//开始的时间 private int mAllTime;//总共耗时 private boolean isRecording;//是否正在录音 private File mFile;//文件
private Timer mTimer;private final Handler mHandler;
public MediaRecorderTask() {mTimer = new Timer();//创建 TimermHandler = new Handler();//创建 Handler}
/**
开始录音*/public void start(File file) {mAllTime = 0;mFile = file;if (mRecorder == null) {// [1]获取 MediaRecorder 类的实例 mRecorder = new MediaRecorder();}//配置 MediaRecorder// [2]设置音频的来源 mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// [3]设置音频的输出格式 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);// [4]采样频率 mRecorder.setAudioSamplingRate(44100);// [5]设置音频的编码方式 mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);//[6]音质编码频率:96KbpsmRecorder.setAudioEncodingBitRate(96000);//[7]设置录音文件位置 mRecorder.setOutputFile(file.getAbsolutePath());try {mRecorder.prepare();} catch (IOException e) {e.printStackTrace();}mStartTime = System.currentTimeMillis();if (mRecorder != null) {mRecorder.start();isRecording = true;
cbkVolume();}}
/**
每隔 1 秒回调一次音量*/private void cbkVolume() {mTimer.schedule(new TimerTask() {@Overridepublic void run() {if (isRecording) {float per;try {//获取音量大小 per = mRecorder.getMaxAmplitude() / 32767f;//最大 32767} catch (IllegalStateException e) {e.printStackTrace();per = (float) Math.random();}if (mOnVolumeChangeListener != null) {float finalPer = per;mHandler.post(() -> {
评论