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 < circleX)
{
circleX = circleY;
}
mViewSize = circleX;
mViewCenterX = circleX/2;
mViewCenterY = circleY/2;
mViewRadisu = circleX/2 - mThumbWidth / 2;
setThumbPosition(Math.toRadians(mStartDegree));
}
private int getMeasuredLength(int length, boolean isWidth) {
int specMode = MeasureSpec.getMode(length);
int specSize = MeasureSpec.getSize(length);
int size;
int padding = isWidth ? getPaddingLeft() + getPaddingRight() : getPaddingTop() + getPaddingBottom();
if (specMode == MeasureSpec.EXACTLY) {
size = specSize;
} else {
size = default_size + padding;
if (specMode == MeasureSpec.AT_MOST) {
size = Math.min(size, specSize);
}
}
return size;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mRectF = new RectF(0+mThumbWidth/2, 0+mThumbWidth/2, mViewSize-mThumbWidth/2, mViewSize-mThumbWidth/2);
for (int i = 0; i < colors.length; i++)
{
mPaint.setColor(Color.parseColor(colors[i]));
canvas.drawArc(mRectF, i*sectionAngle-90, sectionAngle+1,false, mPaint);
}
mThumbDrawable.setBounds((int) mThumbLeft, (int) mThumbTop,
(int) (mThumbLeft + mThumbWidth), (int) (mThumbTop + mThumbHeight));
mThumbDrawable.draw(canvas);
textPaint.getTextBounds(text, 0, text.length(), mBounds);
float textWidth = mBounds.width();
float textHeight = mBounds.height();
float textLeft = (float) (mViewCenterX - textWidth/2);
float textTop = (float)(mViewCenterY + textHeight/2);
canvas.drawText(text, 0, text.length(), textLeft, textTop, textPaint);
}
private void setThumbPosition(double radian) {
double x = mViewCenterX + mViewRadisu * Math.cos(radian);
double y = mViewCenterY + mViewRadisu * Math.sin(radian);
mThumbLeft = (float) (x - mThumbWidth / 2);
mThumbTop = (float) (y - mThumbHeight / 2);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
seekTo(eventX, eventY, false);
break ;
case MotionEvent.ACTION_MOVE:
seekTo(eventX, eventY, false);
break ;
case MotionEvent.ACTION_UP:
// seekTo(eventX, eventY, true);
float part = sectionAngle / 4.0f;
for (int i = 0; i < sections; i++) {
if ( mSweepDegree > (i-1)*sectionAngle+part*3 && mSweepDegree < i *sectionAngle + part)
{
if (mSweepDegree < i*sectionAngle)
{
setThumbPosition(Math.toRadians((i-1)*sectionAngle+part*2));
}else {
setThumbPosition(Math.toRadians(i*sectionAngle+part*2));
}
}
}
if (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 && distance > (mViewSize / 2 - mThumbWidth)){
result = true;
}
return result;
}
public int getCurrentColor()
{
return preColor;
}
public void setStartColor(String color)
{
for (int i = 0; i < colors.length; i++)
{
if (colors[i].equals(color))
{
preColor = Color.parseColor(colors[i]);
int sweepAngle = (i- 90 /sectionAngle)*sectionAngle+sectionAngle/2;
// postDelayed(()->{
// setThumbPosition(Math.toRadians(sweepAngle));
// invalidate();
// },200);
mStartDegree = sweepAngle;
//
invalidate();
break;
}
}
}
public void setColor(String color) {
for (int i = 0; i < colors.length; i++)
{
if (colors[i].equals(color))
{
preColor = Color.parseColor(colors[i]);
int sweepAngle = (i- 90 /sectionAngle)*sectionAngle+sectionAngle/2;
setThumbPosition(Math.toRadians(sweepAngle));
invalidate();
break;
}
}
}
public interface OnColorChangeListener
{
void colorChange(int color);
}
public void setOnColorChangeListener(OnColorChangeListener onColorChangeListener) {
this.onColorChangeListener = onColorChangeListener;
}
private OnColorChangeListener onColorChangeListener;
}
주의 할 점:1.미 끄 러 질 수 있 는 위치 에 대한 판단 과 미 끄 러 지 는 각 도 를 어떻게 구 하 는 지,여기에 atan 2 라 는 삼각함수 도 뇌 에 보충 했다.
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 < circleX) {
circleX = circleY;
}
mViewSize = circleX;
mViewCenterX = circleX / 2;
mViewCenterY = circleY / 2;
mViewRadisu = circleX / 2 - mThumbWidth / 2;
}
private float sweepAngle;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mRectF = new RectF(0 + mThumbWidth / 2, 0 + mThumbWidth / 2, mViewSize - mThumbWidth / 2, mViewSize - mThumbWidth / 2);
for (int i = 0; i < colors.length; i++) {
mPaint.setColor(Color.parseColor(colors[i]));
canvas.drawArc(mRectF, i * sectionAngle - 90, sectionAngle + 1, false, mPaint);
}
int tempAng = (int) (tempStartAngle + sweepAngle);
int intervalAngle = interval * sectionAngle;
if (reverse) {
setThumbPosition(Math.toRadians(tempAng));
setThumbLowPosition(Math.toRadians(tempAng - intervalAngle));
canvas.drawArc(mRectF, tempAng, 360 - intervalAngle, false, arcPaint);
} else {
setThumbPosition(Math.toRadians(tempAng));
setThumbLowPosition(Math.toRadians(tempAng + intervalAngle));
canvas.drawArc(mRectF, (int) (tempAng + intervalAngle), 360 - intervalAngle, false, arcPaint);
}
mThumbHighDrawable.setBounds((int) mThumbLeft, (int) mThumbTop,
(int) (mThumbLeft + mThumbWidth), (int) (mThumbTop + mThumbHeight));
mThumbLowDrawable.setBounds((int) mThumbLowLeft, (int) mThumbLowTop, (int) (mThumbLowLeft + mThumbLowWidth), (int) (mThumbLowTop + mThumbLowHeight));
mThumbHighDrawable.draw(canvas);
mThumbLowDrawable.draw(canvas);
}
private void setThumbPosition(double radian) {
double x = mViewCenterX + mViewRadisu * Math.cos(radian);
double y = mViewCenterY + mViewRadisu * Math.sin(radian);
mThumbLeft = (float) (x - mThumbWidth / 2);
mThumbTop = (float) (y - mThumbHeight / 2);
}
private void setThumbLowPosition(double radian) {
double x = mViewCenterX + mViewRadisu * Math.cos(radian);
double y = mViewCenterY + mViewRadisu * Math.sin(radian);
mThumbLowLeft = (float) (x - mThumbLowWidth / 2);
mThumbLowTop = (float) (y - mThumbLowHeight / 2);
}
private boolean isDown = true;
@Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
getEventDegree(eventX, eventY);
// seekTo(eventX, eventY, false);
break;
case MotionEvent.ACTION_MOVE:
seekTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
postDelayed(() -> {
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<Integer> 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; i++) {
selectedColors.add(Color.parseColor(colors[i]));
}
for (int i = 0; i <= index; i++) {
selectedColors.add(Color.parseColor(colors[i]));
}
}else {
for (int i = startIndex+1; i <= index; i++) {
selectedColors.add(Color.parseColor(colors[i]));
}
}
}else {
startIndex = index+interval+1;
while (startIndex>colors.length)
{
startIndex = startIndex-colors.length;
}
if (startIndex < index)
{
for (int i = startIndex-1; i >= 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 && 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<Integer> colors);
}
public void setOnColorChangeListener(OnColorChangeListener onColorChangeListener) {
this.onColorChangeListener = onColorChangeListener;
}
private OnColorChangeListener onColorChangeListener;
}
주의 할 곳:1.제스처 를 들 때 postDelayed 방법 을 사 용 했 습 니까?아니면 그 려 진 선후 문 제 를 피 했 습 니까?
2.isDown 변 수 는 제스처 를 눌 렀 을 때 링 에 있 는 지 판단 하 는 역할 을 합 니 다.손짓 이 링 밖에서 링 위 에 미 끄 러 졌 을 때 표시 기 가 손가락 위치 로 튕 겨 나 가지 않도록 한다.
github 주소:colorpicker
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.