Android 音量调节View
来源:互联网 发布:简单数据库软件 编辑:程序博客网 时间:2024/05/21 22:33
导语
手机直播一般都会通过移动屏幕来调节音量的大小,本篇只实现了图例,并不能改变音量。
先看效果:
需要的素材:小喇叭图片,点击这里获取
预热
如果你对Path,PathMeasure,RectF,Canvas等不适很了解的话,强烈建议看这位哥们的教程:
点击这里查看教程
如果你将这哥们的十几篇帖子都看完了的话,这个View实际上是非常简单的
步骤介绍
用动态图来介绍:
这里用文字翻译下:
- 将小喇叭画到中心位置
- 围绕着喇叭画一个圆圈,浅色的
- 画一个圆弧,深色的
- 根据触摸的位置来改变圆弧的大小
分解之后,发现并没有什么难度(可能本身就没有什么难度),下面来看每一步的操作,最后会将整个View的代码贴出来
绘制小喇叭
相关代码片(不要复制,只是看的)
@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); //坐标移动到中心 canvas.translate(mViewWidth / 2, mViewHeight / 2); //拿到小喇叭图片 Bitmap voice = BitmapFactory.decodeResource(getResources(), R.mipmap.voice); //获取图片的宽高 int bWidth = voice.getWidth(); int bHeight = voice.getHeight(); //移动坐标到中心位置 canvas.drawBitmap(voice, -bWidth / 2, -bHeight / 2, outerCirclePaint);}
分析
核心:将图片放到中心位置:
将图片向上移动高度的一半,向左移动宽度的一半,就可以移动到中心如图所示:
绘制浅色的圆环
相关代码片(不要复制,只是看的)
@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); initPaint(); //坐标移动到中心 canvas.translate(mViewWidth / 2, mViewHeight / 2); //底层圆圈 if (cirPath == null) cirPath = new Path(); if (rectF == null) { //半径选取为图片宽度一半的1.3倍,可以调节 r = (int) (bWidth / 2 * 1.3f); rectF = new RectF(-r, -r, r, r); } cirPath .addArc(rectF, 0, 360); //画底层浅色的圆圈 canvas.drawPath(cirPath, outerCirclePaint);}
分析:
这步没有什么难度,只是绘制一个圆圈
画一个深色的圆弧
相关代码片(不要复制,只是看的)
@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); //坐标移动到中心 canvas.translate(mViewWidth / 2, mViewHeight / 2); //音量大小 if (innerCirclePath == null) innerCirclePath = new Path(); //绘制外层深色的音量弧形 drawVoicePath(innerCirclePath); //画音量强度 canvas.drawPath(voicePath, voicePaint);}private void drawVoicePath(Path path) { if (voiceRectf == null) { //与底层圆圈保持一致 voiceRectf = new RectF(-r, -r, r, r); voicePath = new Path(); } voicePath.reset(); //道听途说使用359.9可以测量的更准 path.addArc(voiceRectf, -90, 359.9f); //通过PathMeasure来绘制部分的圆圈,表现出来就是绘制了弧形 PathMeasure measure = new PathMeasure(path, false); //获取圆的总长度 float length = measure.getLength(); //根据音量大小来绘制部分的弧形 measure.getSegment(0, voiceNumber * length, voicePath, true);}
分析
这段代码需要了解PathMeasure的用法点击这里了解。
圆弧从上往下绘制,所以:addArc(RectF oval, float startAngle, float sweepAngle)中的第二个参数startAngle为-90;
圆各部分的对应的Angle:
另外,通过可变参数voiceNumber来控制圆弧的大小,用于之后的修改。
触摸改变圆弧的大小
相关代码片(不要复制,只是看的)
@Overridepublic boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //记录起始位置的坐标和音量大小 startY = (int) event.getY(); oldVoiceNumber = voiceNumber; break; case MotionEvent.ACTION_MOVE: //记录当前位置的坐标 moveY = (int) event.getY(); //与起始位置进行比较来确定音量的大小 changedVoiceNumber(); break; case MotionEvent.ACTION_UP: //手指离开屏幕,重置数据 resetData(); break; } //绘制图形 invalidate(); //这里需要改View处理事件,所以放回true; return true;}
最后一步的代码比较多,这里没有贴完,详细代码在最后都会贴出来。
分析:
既然要通过滑动来改变深色圆弧的大小,那么可定是在onTouchEvent()中来进行相关的操作。
1. 通过滑动,图形改变,需要重新绘制,所以调用invalidate()
2. 滑动事件需要改View来处理,所以返回值为true
3. 核心部分是通过ACTION_DOWN,ACTION_MOVE,ACTION_UP的相关操作来实现的
核心部分的大致流程图是这样的,如果与后面的代码有出入,以代码为准:
完整代码
这里可以复制粘贴了
/** * Created by Kevin on 2016/8/31. */public class VoiceView extends View { //控件的宽高 private int mViewWidth; private int mViewHeight; //小喇叭 private Bitmap voice; //小喇叭的宽度 private int bWidth; //小喇叭的高度 private int bHeight; //表示音量大小 private float voiceNumber = 0.5f; //调节之前音量的大小 private float oldVoiceNumber; //开始时的坐标 private int startY; //移动后的坐标 private int moveY; //圆圈的半径 private int r; //音量从0-->1所需要移动的距离 private int voiceChangedY; //音量的画笔 private Paint voicePaint; //顶层圆圈的画笔 private Paint outerCirclePaint; //音量的Path private Path voicePath; //顶层圆圈的的Path private Path cirPath; //音量圆圈的Path private Path innerCirclePath; //顶层的RectF private RectF rectF; //音量的RectF private RectF voiceRectf; public VoiceView(Context context) { super(context); initBitmap(); } public VoiceView(Context context, AttributeSet attrs) { super(context, attrs); initBitmap(); } public VoiceView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initBitmap(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); initPaint(); //坐标移动到中心 canvas.translate(mViewWidth / 2, mViewHeight / 2); //外层圆圈 if (cirPath == null) cirPath = new Path(); //音量大小 if (innerCirclePath == null) innerCirclePath = new Path(); //绘制底层浅色圆圈 drawCirclePath(cirPath); //绘制外层深色的音量弧形 drawVoicePath(innerCirclePath); //移动坐标到中心位置 canvas.drawBitmap(voice, -bWidth / 2, -bHeight / 2, outerCirclePaint); //画顶层浅色的圆圈 canvas.drawPath(cirPath, outerCirclePaint); //画音量强度 canvas.drawPath(voicePath, voicePaint); } /** * 通过触摸来改变音量的大小 * * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //记录起始位置的坐标和音量大小 startY = (int) event.getY(); oldVoiceNumber = voiceNumber; break; case MotionEvent.ACTION_MOVE: //记录当前位置的坐标 moveY = (int) event.getY(); //与起始位置进行比较来确定音量的大小 changedVoiceNumber(); break; case MotionEvent.ACTION_UP: //手指离开屏幕,重置数据 resetData(); break; } //绘制图形 invalidate(); //这里需要改View处理事件,所以放回true; return true; } /** * 根据起始位置和当前位置来确定音量的大小 * <p> * 一般情况下:音量大小的改变量 = (当前位置 - 起始位置) / 一个固定的长度 * 注释:这里选取的“一个固定的长度”为高度的一半 * <p> * 极端情况:如果音量调节到1或者0,仍然以最开始的位置作为起始位置,感觉会很奇怪(可以将resetData()中的的代码屏蔽来感觉一下); * 处理:当为0或者1时,重置数据 */ private void changedVoiceNumber() { int changeY = moveY - startY; float changedVoice = changeY / (voiceChangedY * 1.0f); if (changedVoice > 0) { //音量增加 if (voiceNumber >= 1) { voiceNumber = 1; resetData(); return; } else { float afterChange = oldVoiceNumber + changedVoice; if (afterChange >= 1) { voiceNumber = 1; resetData(); } else { voiceNumber = afterChange; } } } else if (changedVoice < 0) { //音量减少 if (voiceNumber <= 0) { voiceNumber = 0; resetData(); return; } else { float afterChange = oldVoiceNumber + changedVoice; if (afterChange <= 0) { voiceNumber = 0; resetData(); } else { voiceNumber = afterChange; } } } else if (changedVoice == 0) { //音量不变 }// String print = String.format("startY-->%d,moveY-->%d,voiceNumber-->%f,changeVoice-->%f", startY, moveY, voiceNumber, changedVoice);// Log.e("ddd", print); } /** * 当音量达到0或者1时,重置数据 */ private void resetData() { startY = moveY; oldVoiceNumber = voiceNumber; } /** * 绘制底层层圆圈 * * @param path */ private void drawCirclePath(Path path) { if (rectF == null) { //半径选取为图片宽度一半的1.3倍,可以调节 r = (int) (bWidth / 2 * 1.3f); rectF = new RectF(-r, -r, r, r); } path.addArc(rectF, 0, 360); } /** * 绘制音量 * * @param path */ private void drawVoicePath(Path path) { if (voiceRectf == null) { //与底层圆圈保持一致 voiceRectf = new RectF(-r, -r, r, r); voicePath = new Path(); } voicePath.reset(); //道听途说使用359.9可以测量的更准 path.addArc(voiceRectf, -90, 359.9f); //通过PathMeasure来绘制部分的圆圈,表现出来就是绘制了弧形 PathMeasure measure = new PathMeasure(path, false); //获取圆的总长度 float length = measure.getLength(); //根据音量大小来绘制部分的弧形 measure.getSegment(0, voiceNumber * length, voicePath, true); } /** * 小喇叭 */ private void initBitmap() { voice = BitmapFactory.decodeResource(getResources(), R.mipmap.voice); bWidth = voice.getWidth(); bHeight = voice.getHeight(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mViewWidth = w; mViewHeight = h; //音量从0-->1所需要移动的距离 voiceChangedY = h / 2; } /** * 初始化画笔 */ private void initPaint() { int stroke = 20; if (outerCirclePaint == null) { outerCirclePaint = new Paint(); outerCirclePaint.setStrokeWidth(stroke); outerCirclePaint.setStyle(Paint.Style.STROKE); outerCirclePaint.setColor(0x8089cff0); outerCirclePaint.setAntiAlias(true); } if (voicePaint == null) { voicePaint = new Paint(); voicePaint.setStrokeWidth(stroke); voicePaint.setStyle(Paint.Style.STROKE); voicePaint.setColor(0xff1d8ffe); voicePaint.setAntiAlias(true); } }}
结语
该View的绘制难度并不大,涉及了不少基础,当做练习是一个很好的素材。
转载请标明出处:http://blog.csdn.net/qq_26411333/article/details/52383186#t6
- Android 音量调节View
- Android 音量调节View
- 自定义View音量调节
- Android音量调节原理
- Android调节音量
- Android音量控制调节
- Android之音量调节
- Android音量控制调节
- Android 音量调节
- Android(Java):音量调节
- android 调节媒体音量
- android audio 音量调节
- Android 音量调节
- Android音量控制调节
- Android 音量调节方法
- Android音量控制调节
- Android音量控制调节
- Android音量调节
- linux文件目录操作命令 cd
- 转:在华为的工作体验,可以get一些点(仅自娱自乐)
- android之PowerManager 与电源管理,解决灭屏状态下来短信屏幕不会点亮问题
- STA基础分析-setup和hold
- Java笔记整理:一切都是对象
- Android 音量调节View
- python3.5 EMBED in C
- 82.Single Number-落单的数(容易题)
- 二、什么是asp网站
- UVA1610 Party Games
- Android 解析微信基础表情并显示
- java 泛型讲解
- Core Python Programming学习记录(1)
- linux 文件目录命令 pwd