一个简单的Android自定义View
来源:互联网 发布:淘宝店芥末和小镇姗姗 编辑:程序博客网 时间:2024/06/11 22:21
最近有个项目中需要录音,参考了一个APP,录音实时用声波图显示声音大小,并且录音结束后可通过拖拽定位修改其中某一段时间的声音。这两天比较闲了,写了个没任何技术含量的波形图自定义view(就是在画线),欢迎指教。
因为音频录制的方式很多,所以这个view只负责接收表示音量大小的值,具体传过来的值多大多小不限制,取所有的值中最大值按比例缩放。
代码如下:
public class WaveView extends View { public WaveView(Context context) { super(context); } public WaveView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(attrs); } public WaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); } private Integer waveType;//波形展示类型 private int centerLineColor = Color.BLACK; private int centerLineWidth = 1; private int lineColor = Color.GREEN; private int lineWidth = 10;//竖线的宽度 private int lineSpace = 30;//竖线之间的间隔宽度 public static final int WVTYPE_CENTER_LINE = 0;//竖线从中间开始 向上向下长度相同 public static final int WVTYPE_SINGLE = 1;//竖线从底部开始向上计算 private List<Integer> values;//存放数值 private int fullValue = 100;//相对最大值 private float mScale = 0;//传入值转换为有效数值需要使用的比例 private int maxValue = 1;//当前数组中的最大值 该值乘以scale应等于fullValue private int maxLineCount ; private boolean hasOver;//值记录是否已完毕 Paint paintCenterLine,paintLine; private void init(AttributeSet attrs){ final TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.WaveView); waveType = typedArray.getInt(R.styleable.WaveView_wvType, 0); centerLineColor = typedArray.getColor(R.styleable.WaveView_wvCenterLineColor,Color.BLACK); centerLineWidth = typedArray.getDimensionPixelSize(R.styleable.WaveView_wvCenterLineWidth,1); lineColor = typedArray.getColor(R.styleable.WaveView_wvLineColor,Color.GREEN); lineWidth = typedArray.getDimensionPixelSize(R.styleable.WaveView_wvLineWidth,10); lineSpace = typedArray.getDimensionPixelSize(R.styleable.WaveView_wvLineSpace,30); paintCenterLine = new Paint(); paintCenterLine.setStrokeWidth(centerLineWidth); paintCenterLine.setColor(centerLineColor); paintLine = new Paint(); paintLine.setStrokeWidth(lineWidth); paintLine.setAntiAlias(true); paintLine.setColor(lineColor); } public void putValue(int value){ if (value>maxValue){ maxValue = value; mScale = (float) fullValue/maxValue; } if (values==null){ values = new ArrayList<>(); }else {// values.add(value);// invalidate(); } values.add(value); invalidate(); } public void setHasOver(boolean over){ hasOver = over; } public boolean hasOver(){ return hasOver; } private int lastX,moveX; private boolean hasBeenEnd=false; @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = (int) (event.getRawX()); break; case MotionEvent.ACTION_MOVE: int x = (int) event.getRawX(); //到达边缘时不能向该方向继续移动 if (!hasBeenEnd || (moveX>0&&(lastX-x)<0 ||(moveX<0&&(lastX-x)>0))) { moveX += (lastX-x)*0.7; lastX = x; invalidate(); } break; } return true; } @Override protected void onDraw(Canvas canvas) { int yCenter = getHeight() / 2; if (maxLineCount==0){ maxLineCount = getWidth()/(lineSpace+lineWidth); } if (waveType==WVTYPE_CENTER_LINE){ /***************画中线*****************/ canvas.drawLine(0,yCenter,getWidth(),yCenter,paintCenterLine); } /***************画竖线*****************/ //判断当前数组中的数据是否超出了可画竖线最大条数 if(values!=null){ /**找出当前第一条竖线以及偏移量*/ int startIndex = 0;//第一条线 int startOffset = 0;//第一条线的偏移 if (!hasOver || moveX==0){//仍在记录中或未手动滑动过 //线条数量超出最大数 只画后面的线 if(values.size()>maxLineCount){ startIndex = values.size()-maxLineCount; } }else {//已结束录值 且x轴有过移动 //先得到第一条线原本应该的位置 if(values.size()>maxLineCount){ startIndex = values.size()-maxLineCount; } //计算移动线条数 int moveLineSize = moveX/(lineWidth+lineSpace); startOffset = moveX%(lineWidth+lineSpace); int currentIndex = startIndex+moveLineSize; if (currentIndex<0){//到达最左边 startIndex = 0; startOffset = 0; hasBeenEnd = true; }else if (currentIndex>=values.size()){ startIndex = values.size()-1; startOffset=0; hasBeenEnd = true; }else { startIndex = currentIndex; hasBeenEnd = false; } Log.d("XXXXXXX","move-x:"+moveX+" moveLineSize:"+moveLineSize +" startIndex:"+startIndex+" startOffset:"+startOffset); } //画竖线 for (int i=startIndex;i<values.size();i++){ int startX =0; int endX =0; int startY =0; int endY =0; int lineHeight = (int) ((((float)values.get(i)*mScale)/fullValue)*getHeight()); switch (waveType){ case WVTYPE_CENTER_LINE: startX = (i-startIndex)*(lineSpace+lineWidth)+lineWidth/2 - startOffset ; endX = startX; startY = (getHeight()-lineHeight)/2; endY = (getHeight()-lineHeight)/2+lineHeight; break; case WVTYPE_SINGLE: startX = (i-startIndex)*(lineSpace+lineWidth)+lineWidth/2 - startOffset ; endX = startX; startY = getHeight()-lineHeight; endY = getHeight(); break; } canvas.drawLine(startX,startY,endX,endY,paintLine); // Paint pNum = new Paint(); // pNum.setColor(Color.RED); // canvas.drawText(""+i,startX,yCenter,pNum); 画出竖线index便于测试 } } }}样式相关:
<resources> <declare-styleable name="WaveView"> <attr name="wvType" format="enum"> <enum name="centerLine" value="0"/> <enum name="single" value="1"/> </attr> <attr name="wvCenterLineColor" format="color" /> <attr name="wvCenterLineWidth" format="dimension" /> <attr name="wvLineColor" format="color" /> <attr name="wvLineWidth" format="dimension" /> <attr name="wvLineSpace" format="dimension" /> </declare-styleable></resources>
源码下载:github源码
阅读全文
1 0
- 一个简单的Android自定义view详解
- 一个简单的Android自定义View
- Android 实现一个简单的自定义View
- Android下 一个自定义VIEW实现简单的弹幕效果
- Android自定义简单的View
- Android自定义简单的View
- Android自定义简单的View
- android 自定义一个简单View总结
- 一个简单的自定义VIEW的DEMO
- 简单实现一个自定义view的ProgressBar
- Android自定义View 一<最简单的自定义View>
- android简单自定义view
- Android 简单自定义View
- 简单举例说明android自定义view的方法
- Android 自定义View -- 简单的倒计时器
- Android简单自定义view的实现
- android 自定义控件---简单的加载View
- android 自定义view的简单实例
- Ubuntu: 修改文件(夹) 名称
- 内容解析器 ContentResolver
- 移植Python2.7到ARM-LINUX嵌入式平台
- python学习之小工具汇总
- MemcacheDB, Tokyo Tyrant, Redis性能测试比较
- 一个简单的Android自定义View
- 每日小记 2017.6.29
- Thrift在Android上的客户端实现(二):文件传输
- Excel 2016用下拉列表进行数据输入
- axis2 调用webservice 2
- IGBT的驱动和过流保护电路的研究
- Java内存区域与内存溢出异常
- android从应用到驱动之—camera(2)---cameraHAL的实现
- SQLite学习第一天