android自定义View实现圆环颜色选择器

这篇文章主要介绍了android自定义View实现圆环颜色选择器,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

最近工作需要,自定了一个颜色选择器,效果图如下:

这里写图片描述

颜色种类是固定的,圆环上有个指示器,指示选中的颜色,这个定义起来应该是很简单了,直接上代码。

 public class MyColorPicker extends View { private int mThumbHeight; private int mThumbWidth; private String[] colors ; private int sections; //每个小块的度数 private int sectionAngle; private Paint mPaint; private int ringWidth; private RectF mRectF; private Drawable mThumbDrawable = null; private float mThumbLeft; private float mThumbTop; private double mViewCenterX, mViewCenterY; private double mViewRadisu; //起始角度 private int mStartDegree = -90; //当前view的尺寸 private int mViewSize; private int textColor; private String text=""; private Paint textPaint; private Rect mBounds; private float textSize; private int colorType; private int default_size = 100; public MyColorPicker(Context context) { this(context, null); } public MyColorPicker(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyColorPicker(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray localTypedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleColorPicker); mThumbDrawable = localTypedArray.getDrawable(R.styleable.CircleColorPicker_thumb); ringWidth = (int) localTypedArray.getDimension(R.styleable.CircleColorPicker_ring_span, 30); colorType = localTypedArray.getInt(R.styleable.CircleColorPicker_color_type, 0); textColor = localTypedArray.getColor(R.styleable.CircleColorPicker_text_color, Color.BLACK); text = localTypedArray.getString(R.styleable.CircleColorPicker_text); textSize = localTypedArray.getDimension(R.styleable.CircleColorPicker_text_size, 20); localTypedArray.recycle(); default_size = SystemUtils.dip2px(context, 260); init(); } private void init() { colors = colorType == 1 ? ColorUtils.getMacaroon():ColorUtils.getAllColors(); sections = colors.length; mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(ringWidth); textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); textPaint.setColor(textColor); textPaint.setTextSize(textSize); mThumbWidth = this.mThumbDrawable.getIntrinsicWidth(); mThumbHeight = this.mThumbDrawable.getIntrinsicHeight(); sectionAngle = 360/sections; mBounds = new Rect(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //  super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(getMeasuredLength(widthMeasureSpec, true), getMeasuredLength(heightMeasureSpec, false)); int circleX = getMeasuredWidth(); int circleY = getMeasuredHeight(); if (circleY  (i-1)*sectionAngle+part*3 && mSweepDegree  ((sections-1)*sectionAngle)+part*3) { setThumbPosition(Math.toRadians((sections-1)*sectionAngle+part*2)); } invalidate(); break ; } return true; } private int preColor; private float mSweepDegree; private void seekTo(float eventX, float eventY, boolean isUp) { if (true == isPointOnThumb(eventX, eventY) && false == isUp) { //   mThumbDrawable.setState(mThumbPressed); double radian = Math.atan2(eventY - mViewCenterY, eventX - mViewCenterX); /* * 由于atan2返回的值为[-pi,pi] * 因此需要将弧度值转换一下,使得区间为[0,2*pi] */ if (radian <0){ radian = radian + 2*Math.PI; } setThumbPosition(radian); mSweepDegree = (float) Math.round(Math.toDegrees(radian)); int currentColor = getColor(mSweepDegree); if (currentColor != preColor) { preColor = currentColor; if (onColorChangeListener != null) { onColorChangeListener.colorChange(preColor); } } invalidate(); }else{ //   mThumbDrawable.setState(mThumbNormal); invalidate(); } } private int getColor(float mSweepDegree) { int tempIndex = (int) (mSweepDegree/sectionAngle); int num = 90 / sectionAngle; if (tempIndex ==sections) { tempIndex = 0; } int index = tempIndex; if (tempIndex >= 0) { index = tempIndex+num; } if (tempIndex >= (sections-num)) { index = tempIndex-(sections-num); } return Color.parseColor(colors[index]); } private boolean isPointOnThumb(float eventX, float eventY) { boolean result = false; double distance = Math.sqrt(Math.pow(eventX - mViewCenterX, 2) + Math.pow(eventY - mViewCenterY, 2)); if (distance  (mViewSize / 2 - mThumbWidth)){ result = true; } return result; } public int getCurrentColor() { return preColor; } public void setStartColor(String color) { for (int i = 0; i { //     setThumbPosition(Math.toRadians(sweepAngle)); //     invalidate(); //    },200); mStartDegree = sweepAngle; //最好加上 invalidate(); break; } } } public void setColor(String color) { for (int i = 0; i 

注意的几个地方:

1. 可滑动位置的判断以及如何求滑动的角度,这里还去脑补了下atan2这个三角函数
2. 设置指示器的开始的位置,外部调用setStartColor()方法时,这个View可能还没真正完成绘制。如果没有完成绘制,第几行的invalidate()方法其实是没多大作用。

上面是选择单个颜色,下面来个加强版,选择的是颜色区间,先上效果图:

这里写图片描述

区间可以自己选择,并且可以反转(低指示器在高指示器顺时针方向或逆时针方向)。

下面是代码:

 public class IntervalColorPicker extends View { private int mThumbHeight; private int mThumbWidth; private int mThumbLowHeight, mThumbLowWidth; private String[] colors = ColorUtils.getAllColors(); private int sections; //每个小块的度数 private int sectionAngle; private Paint mPaint; private Paint arcPaint; private int ringWidth; private RectF mRectF; private Drawable mThumbHighDrawable = null; private Drawable mThumbLowDrawable; private float mThumbLeft; private float mThumbTop; private float mThumbLowLeft, mThumbLowTop; private double mViewCenterX, mViewCenterY; private double mViewRadisu; //起始角度 private float mStartDegree = 270; //当前view的尺寸 private int mViewSize; //区间 private int interval = 7; private boolean reverse; private float tempStartAngle = mStartDegree; public IntervalColorPicker(Context context) { this(context, null); } public IntervalColorPicker(Context context, AttributeSet attrs) { this(context, attrs, 0); } public IntervalColorPicker(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray localTypedArray = context.obtainStyledAttributes(attrs, R.styleable.IntervalColorPicker); mThumbHighDrawable = localTypedArray.getDrawable(R.styleable.IntervalColorPicker_thumbHigh); mThumbLowDrawable = localTypedArray.getDrawable(R.styleable.IntervalColorPicker_thumbLow); ringWidth = (int) localTypedArray.getDimension(R.styleable.IntervalColorPicker_ring_breadth, 30); localTypedArray.recycle(); init(); } private void init() { sections = colors.length; mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(ringWidth); arcPaint = new Paint(Paint.ANTI_ALIAS_FLAG); arcPaint.setStyle(Paint.Style.STROKE); arcPaint.setStrokeWidth(ringWidth + 1); arcPaint.setColor(Color.GRAY); mThumbWidth = this.mThumbHighDrawable.getIntrinsicWidth(); mThumbHeight = this.mThumbHighDrawable.getIntrinsicHeight(); mThumbLowHeight = mThumbLowDrawable.getIntrinsicHeight(); mThumbLowWidth = mThumbHighDrawable.getIntrinsicWidth(); sectionAngle = 360 / sections; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int circleX = getMeasuredWidth(); int circleY = getMeasuredHeight(); if (circleY  { tempStartAngle = tempStartAngle + sweepAngle; sweepAngle = 0; getSelectedColor(); if (onColorChangeListener != null) { onColorChangeListener.colorChange(selectedColors); } }, 100); break; } return true; } private float downDegree; private void getEventDegree(float eventX, float eventY) { if (isPointOnThumb(eventX, eventY)) { double radian = Math.atan2(eventY - mViewCenterY, eventX - mViewCenterX); /* * 由于atan2返回的值为[-pi,pi] * 因此需要将弧度值转换一下,使得区间为[0,2*pi] */ if (radian <0) { radian = radian + 2 * Math.PI; } isDown = true; downDegree = Math.round(Math.toDegrees(radian)); } else { isDown = false; } } private void seekTo(float eventX, float eventY) { if (true == isPointOnThumb(eventX, eventY)) { //   mThumbHighDrawable.setState(mThumbPressed); if (!isDown) { getEventDegree(eventX, eventY); isDown = true; } double radian = Math.atan2(eventY - mViewCenterY, eventX - mViewCenterX); /* * 由于atan2返回的值为[-pi,pi] * 因此需要将弧度值转换一下,使得区间为[0,2*pi] */ if (radian <0) { radian = radian + 2 * Math.PI; } setThumbPosition(radian); float mSweepDegree = (float) Math.round(Math.toDegrees(radian)); sweepAngle = mSweepDegree - downDegree; invalidate(); } } //选中的颜色 private ArrayList selectedColors = new ArrayList<>(interval); public void getSelectedColor() { int tempIndex = (int) (tempStartAngle / sectionAngle); int num = 90 / sectionAngle; if (tempIndex == sections) { tempIndex = 0; } int index = tempIndex; if (tempIndex >= 0) { index = tempIndex + num; } if (tempIndex >= (sections - num)) { index = tempIndex - (sections - num); } if (index>colors.length) index = index%colors.length; while (index<0) { index = colors.length+index; } selectedColors.clear(); int startIndex = 0; if (reverse) { startIndex = index - interval -1; while (startIndex <0) { startIndex = startIndex+colors.length; } if (startIndex > index) { for (int i = startIndex+1; i colors.length) { startIndex = startIndex-colors.length; } if (startIndex = 0; i--) { selectedColors.add(Color.parseColor(colors[i])); } for (int i = colors.length-1; i >= index; i--) { selectedColors.add(Color.parseColor(colors[i])); } }else { for (int i = startIndex-1; i >=index; i--) { selectedColors.add(Color.parseColor(colors[i])); } } } } private boolean isPointOnThumb(float eventX, float eventY) { boolean result = false; double distance = Math.sqrt(Math.pow(eventX - mViewCenterX, 2) + Math.pow(eventY - mViewCenterY, 2)); if (distance  (mViewSize / 2 - mThumbWidth)) { result = true; } return result; } public boolean isReverse() { return reverse; } public void setReverse(boolean reverse) { this.reverse = reverse; invalidate(); } public interface OnColorChangeListener { void colorChange(ArrayList colors); } public void setOnColorChangeListener(OnColorChangeListener onColorChangeListener) { this.onColorChangeListener = onColorChangeListener; } private OnColorChangeListener onColorChangeListener; }

注意的地方:

1. 手势抬起时用了一个postDelayed方法,还是避免绘制的先后问题。
2. isDown变量的作用是判断,手势按下时是否在圆环上。当手势从圆环外滑倒圆环上时,避免指示器一下弹到手指位置。

github地址:colorpicker

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持html中文网。

以上就是android自定义View实现圆环颜色选择器的详细内容,更多请关注0133技术站其它相关文章!

赞(0) 打赏
未经允许不得转载:0133技术站首页 » 移动