在做一个音频的项目,想在网上找一个圆形aseekbar,但是一直没找到合适的,只好自己动手写了,上网找了一个demo进行了大修改效果如下
源码
package com.jian.View; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; import com.example.jian.bluetooth.R; public class DutyViewThumb extends View { int width; int height; private boolean selectState = false; public void setSelected(boolean state) { if(selectState != state) { selectState = state; postInvalidate(); } } public boolean isSelected() { return selectState; } public DutyViewThumb(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub try { thumbUp = BitmapFactory.decodeResource(getResources(), R.drawable.thumb_up); upSrc.set(0, 0, thumbUp.getWidth(), thumbUp.getHeight()); thumbDn = BitmapFactory.decodeResource(getResources(), R.drawable.thumb_dn); dnSrc.set(0,0,thumbDn.getWidth(),thumbDn.getHeight()); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } /* setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if(selectState == false) { selectState = true; invalidate(); Log.i("userLog", "onSelected"); } return true; default: break; } return false; } }); */ } private Bitmap thumbUp; private Bitmap thumbDn; private Rect upSrc = new Rect(); private Rect dnSrc = new Rect(); private Rect dstRect = new Rect(); @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub try { if(isSelected()) { canvas.drawBitmap(thumbDn, dnSrc, dstRect, null); } else { canvas.drawBitmap(thumbUp, upSrc, dstRect, null); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub if(MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) { width = MeasureSpec.getSize(widthMeasureSpec); } else { width = DensityUtils.dp2px(getContext(), 40); } height = width; setMeasuredDimension(width, height); dstRect.set(width/4, height/4, width*3/4, height*3/4); } }
package com.jian.View; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.PaintFlagsDrawFilter; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewGroup; import com.example.jian.bluetooth.R; public class DutyView extends ViewGroup implements OnTouchListener{ int width; int height; /** * duty最大值 */ public static final int MAX_DUTY = 100; public int getMaxDuty() { return MAX_DUTY; } /** * duty当前值 */ private int duty; public int getDuty() { return duty; } public void setDuty(int value) { if(value >= 0 && value <= MAX_DUTY) { duty = value; postInvalidate(); } } /** * 文本大小 */ private float textSize; public float getTextSize() { return textSize; } public void setTextSize(float textSize) { this.textSize = textSize; } /** * 文本颜色 */ public static final int DEFAULT_TEXT_COLOR = 0xff326ee9; private int textColor = DEFAULT_TEXT_COLOR; public void setTextColor(int color) { this.textColor = color; postInvalidate(); } public int getTextColor() { return this.textColor; } /** * 圆弧颜色 */ public static final int DEFAULT_PROGRESS_BG_COLOR = 0xffffffff; private int progressBgColor = DEFAULT_PROGRESS_BG_COLOR; public int getProgressBgColor() { return progressBgColor; } public void setProgressBgColo(int arcColor) { this.progressBgColor = arcColor; postInvalidate(); } public static final int DEFAULT_PROGRESS_COLOR = 0xffff4e00; private int ProgressColor = DEFAULT_PROGRESS_COLOR; public int getProgressColor() { return ProgressColor; } public void setProgressColor(int value) { this.ProgressColor = value; postInvalidate(); } /** * 圆弧尺寸 */ private float arcWidth; /** * 抗锯齿 */ private PaintFlagsDrawFilter pfd; public float getArcWidth() { return arcWidth; } public void setArcWidth(float arcWidth) { this.arcWidth = arcWidth; } public void setRotatDrawableResource(int id) { BitmapDrawable drawable = (BitmapDrawable)getContext().getResources().getDrawable(id); setRotatDrawable(drawable); } public void setRotatDrawable(BitmapDrawable drawable) { thumbUp = drawable.getBitmap(); upSrc.set(0, 0, thumbUp.getWidth(), thumbUp.getHeight()); postInvalidate(); } public DutyView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DutyView); pfd = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG); duty = array.getInteger(R.styleable.DutyView_initDuty, 0); textColor = array.getColor(R.styleable.DutyView_textColor, DEFAULT_TEXT_COLOR); textSize = array.getDimension(R.styleable.DutyView_textSize, DensityUtils.sp2px(context, 18)); progressBgColor = array.getColor(R.styleable.DutyView_progressBgColor, DEFAULT_PROGRESS_BG_COLOR); ProgressColor = array.getColor(R.styleable.DutyView_progressColor, DEFAULT_PROGRESS_COLOR); arcWidth = array.getDimension(R.styleable.DutyView_arcWidth, DensityUtils.dp2px(context, 5)); array.recycle(); arcPaint = new Paint(); arcPaint.setColor(progressBgColor); arcPaint.setAntiAlias(true); arcPaint.setStyle(Style.STROKE); arcPaint.setStrokeWidth(arcWidth); textPaint = new Paint(); textPaint.setColor(textColor); textPaint.setTextSize(textSize); textPaint.setAntiAlias(true); setOnTouchListener(this); this.setBackgroundColor(0x00ffffff); try { bgPaint = new Paint(); bgPaint.setColor(Color.GRAY); bgPaint.setStrokeWidth(6); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } Paint arcPaint = null; RectF arcRectF = new RectF(); Paint bgPaint = null; Canvas bgcanvas; Paint textPaint = null; private void drawText(Canvas canvas) { String text = String.valueOf((int)duty); float length = textPaint.measureText(text); float x = width/2-length/2; float y = height/2+length/4; canvas.drawText(text, x, y, textPaint); } private Bitmap thumbUp; private Bitmap thumbDn; private Rect upSrc = new Rect(); private Rect dnSrc = new Rect(); private Rect dstRect = new Rect(); //DutyViewProgress progressView; DutyViewThumb thumbView; int thumbWidth; int thumbHeight; @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub //抗锯齿 canvas.setDrawFilter(pfd); canvas.drawBitmap(thumbUp, upSrc, dstRect, null); drawProgressBar(canvas); drawText(canvas); drawgraduation(canvas); super.onDraw(canvas); } private int lineHeight = 20; private void drawProgressBar(Canvas canvas) { // TODO Auto-generated method stub // arcPaint.setColor(progressBgColor); // canvas.drawArc(arcRectF, 135, 270, false, arcPaint); // arcPaint.setColor(ProgressColor); // canvas.drawArc(arcRectF, 135, 270*duty/MAX_DUTY, false, arcPaint); } private int countGraduation = 20;//刻度数 private void drawgraduation(Canvas canvas) {canvas.save(); float degrees = (float) (270.0/countGraduation); float Graduation = ((float)duty*21/MAX_DUTY); Log.i("jian","duty"+duty+"max"+MAX_DUTY); int pointX = width/2; int pointY = height/2; canvas.save(); canvas.translate(0,pointY); canvas.rotate(-45, pointX, 0); for(int i = 0;i<countGraduation+1;i++){ if(i<Graduation||duty == MAX_DUTY){ bgPaint.setColor(Color.BLUE); }else{ bgPaint.setColor(Color.GRAY); } if(i==0||i==countGraduation) { canvas.drawLine(0, 0, lineHeight, 0, bgPaint); }else{ canvas.drawCircle(8,8,10,bgPaint); } canvas.rotate(degrees, pointX, 0); } canvas.restore(); // for(int i= 0;i<) // canvas.drawLine(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub measureChildren(widthMeasureSpec, heightMeasureSpec); width = MeasureSpec.getSize(widthMeasureSpec); height = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(width, height); if(thumbView == null) { thumbView = (DutyViewThumb) getChildAt(0); thumbWidth = thumbView.getMeasuredWidth()/2; thumbHeight = thumbView.getMeasuredHeight()/2; } arcRectF.set(thumbWidth, thumbWidth, width-thumbWidth,height-thumbWidth); dstRect.set(40, 40, width-40, height-40); invaliArea.set(width/3, height/2, width*2/3, height); } RectF thumbRect = new RectF(); @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // TODO Auto-generated method stub try { if(thumbView == null) { thumbView = (DutyViewThumb) getChildAt(0); thumbWidth = thumbView.getMeasuredWidth()/2; thumbHeight = thumbView.getMeasuredHeight()/2; } calculateThumbPosition(); thumbView.layout((int)thumbRect.left, (int)thumbRect.top, (int)thumbRect.right, (int)thumbRect.bottom); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } /** * 输入坐标,求出对应象限 * @param x * @param y * @return */ private static int getQuadrant(double x, double y) { if (x >= 0) { return y >= 0 ? 1 : 4; } else { return y >= 0 ? 2 : 3; } } /** * 获取指定坐标对应的角度 * @param xTouch * @param yTouch * @return */ double angle; double changeAngle; private double getAngle(double xTouch, double yTouch) { double x = xTouch - (width / 2d); double y = height - yTouch - (height / 2d); double a; switch (getQuadrant(x, y)) { case 1: return Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI; case 2: case 3: return 180 - (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI); case 4: return 360 + Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI; default: // ignore, does not happen return 0; } // switch (getQuadrant(x, y)) { // case 1: // a = 180 - (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI); // break; // case 2: // case 4: // a = 360 + Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI; // break; // default: // // ignore, does not happen // a = 0; // break; // } // // changeAngle = a-angle; // angle = a; // // return angle; } private final float angleRate = MAX_DUTY/270f; /** * 角度对应的百分比 * @param angle * @return */ private int angle2pesent(double angle) { //无效角度 if(angle < 300 && angle > 240) return -1; if(angle > 225) angle-=360; return (int) (Math.abs(angle-225)*angleRate); } /** * 根据当前的duty值计算thumb的位置 */ private void calculateThumbPosition() { double angle = duty/angleRate; angle += 135; if(angle > 360) angle-=360; float xPoint = (float) (width/2+(width/2-thumbWidth*2)*Math.cos(Math.toRadians(angle)));//修改这里可修改thumb的位置 float yPoint = (float) (height/2+(height/2-thumbHeight*2)*Math.sin(Math.toRadians(angle))); thumbRect.left = xPoint-thumbWidth; thumbRect.top = yPoint-thumbHeight; thumbRect.right = xPoint+thumbWidth; thumbRect.bottom = yPoint+thumbHeight; } //触摸的无效区域 RectF invaliArea = new RectF(); float last_x; float last_y; @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub float x = event.getX(); float y = event.getY(); //触摸无效区域禁止横向滑动 if(invaliArea.contains(x, y)) { if(thumbView.isSelected()) { thumbView.setSelected(false); if(listener != null) listener.onDutyChanged(duty); } Log.i("userLog", "无效区域"); return true; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: Log.i("userLog", "action down"); if(thumbView.isSelected()) { /*thumbView.setSelected(false); if(listener != null) { listener.onDutyChanged(duty); } */ } else { //是否点击滑动块 if(thumbRect.contains((int)x, (int)y)) { thumbView.setSelected(true); last_x = x; last_y = y; Log.i("userLog", "点击滑块"); } } break; case MotionEvent.ACTION_MOVE: if(thumbView.isSelected()) { Log.i("userLog", "滑动"); //触摸不连续,防止多点触控 if(Math.abs(x-last_x) > 150 || Math.abs(y-last_y) > 150) { Log.i("userLog", "滑动不连续"); thumbView.setSelected(false); if(listener != null) { listener.onDutyChanged(duty); } return true; } //计算角度和百分比 double angle = getAngle(x, y); int _duty = angle2pesent(angle); if(_duty != -1) { setDuty(_duty); } else { if(duty < 10) { setDuty(0); } else if(duty > 90) { setDuty(100); } thumbView.setSelected(false); if(listener != null) { listener.onDutyChanged(duty); } } last_x = x; last_y = y; calculateThumbPosition(); thumbView.layout((int)thumbRect.left, (int)thumbRect.top, (int)thumbRect.right, (int)thumbRect.bottom); } break; case MotionEvent.ACTION_UP: Log.i("userLog", "action up"); if(thumbView.isSelected()) { thumbView.setSelected(false); if(listener != null) { listener.onDutyChanged(duty); } } break; default: break; } return true; } public interface onDutyChangedListener { void onDutyChanged(int currentDuty); } onDutyChangedListener listener = null; public void setOnDutyChangedListener(onDutyChangedListener listener) { this.listener = listener; } }
attr中
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="DutyView"> <attr name="viewType"> <enum name="progress" value="0"/> <enum name="thumb" value="1"/> </attr> <attr name="initDuty" format="integer"/> <attr name="progressBgColor" format="color"/> <attr name="progressColor" format="color"/> <attr name="arcWidth" format="dimension"/> <attr name="textColor" format="color"/> <attr name="textSize" format="dimension"/> </declare-styleable> </resources>布局中
<com.jian.View.DutyView android:id="@+id/dutyView" android:layout_width="200dp" android:layout_height="200dp" android:layout_centerInParent="true" DutyView:arcWidth="6dp" DutyView:initDuty="33" DutyView:progressBgColor="@android:color/darker_gray" DutyView:textSize="32sp"> <com.jian.View.DutyViewThumb android:layout_marginLeft="10dp" android:layout_width="30dp" android:layout_height="30dp" /> </com.jian.View.DutyView>
在activity中
DutyView dutyView=(DutyView)v.findViewById(R.id.dutyView); dutyView.setRotatDrawableResource(R.mipmap.cilcle);
r.mipmap.cicle为旋钮图片