当前位置:主页 > 移动开发 > Android代码 >

Android自定义控件实现颜色选择器

时间:2020-12-28 13:02:19 | 栏目:Android代码 | 点击:

ColorPickerView 是之前一个智能家居项目实战中所写的自定义控件,主要用于取得RGB 0~255范围的值,然后转换成十六进制0~FF的值,发送给网关控制RGB彩灯。参考的是网上一个朋友的源码写的,多的不说了,先看效果图

这里写图片描述

activity_mian.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent">

 <TextView
 android:id="@+id/tv_info"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_above="@+id/ll_color"
 android:layout_centerHorizontal="true"
 android:layout_marginBottom="20dp"
 android:gravity="center_horizontal"
 android:text="颜色取值" />

 <LinearLayout
 android:id="@+id/ll_color"
 android:layout_width="match_parent"
 android:layout_height="300dp"
 android:layout_centerInParent="true"
 android:gravity="center"
 android:orientation="vertical"></LinearLayout>
</RelativeLayout>

MainActivity.java文件

package zxz.colorpickerdemo;

import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.TextView;

import zxz.colorpickerdemo.view.ColorPickerView;

public class MainActivity extends AppCompatActivity {

 private LinearLayout ll;
 private TextView tv;
 private ColorPickerView colorPickerView;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 ll = (LinearLayout) findViewById(R.id.ll_color);
 tv = (TextView) findViewById(R.id.tv_info);

 colorPickerView = new ColorPickerView(this);
 ll.addView(colorPickerView);
 colorPickerView.setOnColorBackListener(new ColorPickerView.OnColorBackListener() {
  @Override
  public void onColorBack(int a, int r, int g, int b) {
  tv.setText("R:" + r + "\nG:" + g + "\nB:" + b + "\n" + colorPickerView.getStrColor());
  tv.setTextColor(Color.argb(a, r, g, b));
  }
 });
 }
}

可以发现,这里自定义控件并没有直接在布局文件使用,原因是因为需要用户根据不同的需求通过自定义控件的构造函数传递给控件,所以通过ViewGroup.add()将ColorPickerView添加进去!

ColorPickerView colorPickerView = new ColorPickerView(context);
 ll.addView(colorPickerView);

-核心部分

就是ColorPickerView的实现代码

package zxz.colorpickerdemo.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.view.MotionEvent;
import android.view.View;

public class ColorPickerView extends View {
 private static final float PI = (float) Math.PI;

 private Paint paintCirclePhantom;
 private Paint paintCircle;
 private Paint paintCenterShadow;
 private Paint paintCenter;
 private Paint paintGrayShadow;
 private Paint paintGray;
 private Paint paintLightShadow;
 private Paint paintLight;
 private double Zoom;
 private int[] arrColorGray;
 private final int[] arrColorCircle = new int[]{0xFFFF0000, 0xFFFF00FF,
  0xFF0000FF, 0xFF00FFFF, 0xFF00FF00, 0xFFFFFF00, 0xFFFF0000};
 private boolean mRedrawHSV;
 private boolean IsPressCenter;
 private boolean IsMoveCenter;

 private int CenterX = 100;
 private int CenterY = 100;
 private int CenterRadius = 30;
 private String strColor = "";

 private OnColorBackListener l;

 public ColorPickerView(Context context) {
 super(context);
 float density = getContext().getResources().getDisplayMetrics().density;
 double Zoom = (double) (density / 2.0 + 0.5);
 int color = Color.parseColor("#FFFFFF");
 init(color, Zoom);
 }

 public ColorPickerView(Context context, int color, double Zoom) {
 super(context);
 init(color, Zoom);
 }

 private void init(int color, double Zoom) {
 this.Zoom = Zoom;
 CenterX = (int) (100 * Zoom);
 CenterY = (int) (100 * Zoom);
 CenterRadius = (int) (30 * Zoom);
 paintCirclePhantom = new Paint(Paint.ANTI_ALIAS_FLAG);
 paintCircle = new Paint(Paint.ANTI_ALIAS_FLAG);
 paintCenterShadow = new Paint(Paint.ANTI_ALIAS_FLAG);
 paintCenter = new Paint(Paint.ANTI_ALIAS_FLAG);
 paintGrayShadow = new Paint(Paint.ANTI_ALIAS_FLAG);
 paintGray = new Paint(Paint.ANTI_ALIAS_FLAG);
 paintLightShadow = new Paint(Paint.ANTI_ALIAS_FLAG);
 paintLight = new Paint(Paint.ANTI_ALIAS_FLAG);
 paintCirclePhantom.setColor(0xFF000000);
 paintCirclePhantom.setStyle(Paint.Style.STROKE);
 paintCirclePhantom.setStrokeWidth((float) (32 * Zoom));

 paintCircle.setShader(new SweepGradient(0, 0, arrColorCircle, null));
 paintCircle.setStyle(Paint.Style.STROKE);
 paintCircle.setStrokeWidth((float) (32 * Zoom));

 paintCenterShadow.setColor(0xFF000000);
 paintCenterShadow.setStrokeWidth((float) (5 * Zoom));

 paintCenter.setColor(color);
 paintCenter.setStrokeWidth((float) (5 * Zoom));

 paintGrayShadow.setColor(0xFF000000);
 paintGrayShadow.setStrokeWidth((float) (30 * Zoom));

 arrColorGray = new int[]{0xFFFFFFFF, color, 0xFF000000};
 paintGray.setStrokeWidth((float) (30 * Zoom));

 paintLightShadow.setColor(0xFF000000);
 paintLightShadow.setStrokeWidth((float) (60 * Zoom));

 paintLight.setStrokeWidth((float) (60 * Zoom));

 mRedrawHSV = true;
 }

 @Override
 protected void onDraw(Canvas canvas) {
 canvas.translate(CenterX, CenterY);
 float r = CenterX - paintCircle.getStrokeWidth() * 0.5f; 
 int color = paintCenter.getColor();
 strColor = "#" + Integer.toHexString(color).substring(2).toUpperCase();

 if (mRedrawHSV) {
  arrColorGray[1] = color;
  paintGray.setShader(new LinearGradient(CenterX, -CenterY, CenterX,
   (float) (100 * Zoom), arrColorGray, null,
   Shader.TileMode.CLAMP));
 }

 canvas.drawOval(new RectF(-r + 3, -r + 3, r + 3, r + 3),
  paintCirclePhantom);
 canvas.drawOval(new RectF(-r, -r, r, r), paintCircle);
 canvas.drawCircle(3, 3, CenterRadius, paintCenterShadow);
 canvas.drawCircle(0, 0, CenterRadius, paintCenter);
 canvas.drawRect(new RectF(CenterX + (float) (18 * Zoom), -CenterY + 3,
   CenterX + (float) (48 * Zoom), (float) (103 * Zoom)),
  paintGrayShadow);
 canvas.drawRect(new RectF(CenterX + (float) (15 * Zoom), -CenterY,
  CenterX + (float) (45 * Zoom), (float) (100 * Zoom)), paintGray); 

 if (IsPressCenter) {
  paintCenter.setStyle(Paint.Style.STROKE);

  if (IsMoveCenter)
  paintCenter.setAlpha(0xFF);
  else
  paintCenter.setAlpha(0x66);

  canvas.drawCircle(0, 0,
   CenterRadius + paintCenter.getStrokeWidth(), paintCenter);
  paintCenter.setStyle(Paint.Style.FILL);
  paintCenter.setColor(color);
 }

 mRedrawHSV = true;
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 setMeasuredDimension(CenterX * 2 + 50, CenterY * 2 + 23);
 }

 private int ave(int s, int d, float p) {
 return s + java.lang.Math.round(p * (d - s));
 }

 private int interpColor(int colors[], float unit) {
 if (unit <= 0) {
  return colors[0];
 }
 if (unit >= 1) {
  return colors[colors.length - 1];
 }

 float p = unit * (colors.length - 1);
 int i = (int) p;
 p -= i;

 int c0 = colors[i];
 int c1 = colors[i + 1];
 int a = ave(Color.alpha(c0), Color.alpha(c1), p);
 int r = ave(Color.red(c0), Color.red(c1), p);
 int g = ave(Color.green(c0), Color.green(c1), p);
 int b = ave(Color.blue(c0), Color.blue(c1), p);
 if (l != null) {
  l.onColorBack(a, r, g, b);
 }
 return Color.argb(a, r, g, b);
 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
 float x = event.getX() - CenterX;
 float y = event.getY() - CenterY;
 boolean inCenter = java.lang.Math.sqrt(x * x + y * y) <= CenterRadius;

 switch (event.getAction()) {
  case MotionEvent.ACTION_DOWN: {
  IsPressCenter = inCenter;
  if (inCenter) {
   IsMoveCenter = true;
   invalidate();
   break;
  }
  }
  case MotionEvent.ACTION_MOVE: {
  if (IsPressCenter) {
   if (IsMoveCenter != inCenter) {
   IsMoveCenter = inCenter;
   invalidate();
   }
  } else if ((x >= -CenterX && x <= CenterX)
   && (y >= -CenterY && y <= CenterY)) {
   float angle = (float) java.lang.Math.atan2(y, x);
   float unit = angle / (2 * PI);
   if (unit < 0)
   unit += 1;
   paintCenter.setColor(interpColor(arrColorCircle, unit));
   invalidate();
  } else {
   int a, r, g, b, c0, c1;
   float p;

   if (y < 0) {
   c0 = arrColorGray[0];
   c1 = arrColorGray[1];
   p = (y + 100) / 100;
   } else {
   c0 = arrColorGray[1];
   c1 = arrColorGray[2];
   p = y / 100;
   }

   a = ave(Color.alpha(c0), Color.alpha(c1), p);
   r = ave(Color.red(c0), Color.red(c1), p);
   g = ave(Color.green(c0), Color.green(c1), p);
   b = ave(Color.blue(c0), Color.blue(c1), p);

   paintCenter.setColor(Color.argb(a, r, g, b));
   mRedrawHSV = false;
   if (l != null) {
   l.onColorBack(a, r, g, b);
   }
   invalidate();
  }
  break;
  }
  case MotionEvent.ACTION_UP: {
  if (IsPressCenter) {
   IsPressCenter = false;
   invalidate();
  }
  break;
  }
 }
 return true;
 }

 public Paint getpaintCirclePhantom() {
 return paintCirclePhantom;
 }

 public void setpaintCirclePhantom(Paint paintCirclePhantom) {
 this.paintCirclePhantom = paintCirclePhantom;
 }

 public Paint getPaintCircle() {
 return paintCircle;
 }

 public void setPaintCircle(Paint paintCircle) {
 this.paintCircle = paintCircle;
 }

 public Paint getPaintCenterShadow() {
 return paintCenterShadow;
 }

 public void setPaintCenterShadow(Paint paintCenterShadow) {
 this.paintCenterShadow = paintCenterShadow;
 }

 public Paint getPaintCenter() {
 return paintCenter;
 }

 public void setPaintCenter(Paint paintCenter) {
 this.paintCenter = paintCenter;
 }

 public Paint getPaintGrayShadow() {
 return paintGrayShadow;
 }

 public void setPaintGrayShadow(Paint paintGrayShadow) {
 this.paintGrayShadow = paintGrayShadow;
 }

 public Paint getPaintGray() {
 return paintGray;
 }

 public void setPaintGray(Paint paintGray) {
 this.paintGray = paintGray;
 }

 public int[] getArrColorGray() {
 return arrColorGray;
 }

 public void setArrColorGray(int[] arrColorGray) {
 this.arrColorGray = arrColorGray;
 }

 public boolean ismRedrawHSV() {
 return mRedrawHSV;
 }

 public void setmRedrawHSV(boolean mRedrawHSV) {
 this.mRedrawHSV = mRedrawHSV;
 }

 public boolean isIsPressCenter() {
 return IsPressCenter;
 }

 public void setIsPressCenter(boolean isPressCenter) {
 IsPressCenter = isPressCenter;
 }

 public boolean isIsMoveCenter() {
 return IsMoveCenter;
 }

 public void setIsMoveCenter(boolean isMoveCenter) {
 IsMoveCenter = isMoveCenter;
 }

 public int[] getArrColorCircle() {
 return arrColorCircle;
 }

 public String getStrColor() {
 return strColor;
 }

 public void setStrColor(String strColor) {
 this.strColor = strColor;
 }

 public double getZoom() {
 return Zoom;
 }

 public void setZoom(double zoom) {
 Zoom = zoom;
 }

 public void setOnColorBackListener(OnColorBackListener l) {
 this.l = l;
 }

 public interface OnColorBackListener {
 public void onColorBack(int a, int r, int g, int b);
 }
}

注意:

1、ColorPickerView重写了两个构造方法,第一个ColorPickerView(context) 这个方法创建的取色器默认绘制的大小比为屏幕密度,默认的颜色为白色;第二个ColorPickerView(context, color, zoom) color为默认颜色,zoom为绘制大小比例。

2、调用colorPickerView的setOnColorBackListener方法监听颜色的变化,回调 a r g b 0~255的值。colorPickerView.getStrColor()获取rgb对应的十六进制值,比如#FF00FF

下载体验一下吧~!

demo下载地址:AndroidStudio工程:ColorPicker

您可能感兴趣的文章:

相关文章