com.xiaoi.app.zkSmartHome.R;
/** * auther: Crazy.Mo * Date: 2016/12/13 * Time:10:27 * Des:自定义的调色板,可以绘制圆形指示器,也可以自定义图标指示器,但是指示器会超出边界 */publicclass RainbowPalette extends View {privateContext context;
privatePaint borderPaint;
//色环外圈的彩虹圆环privatePaint palettePaint;
//渐变色环的画笔privatePaint centerPaint;
//中间圆画笔,用于显示当前选中的颜色privatePaint indictorPaint;
// 可移动小球画笔privateintindictorColor;
privateint[] gradientColors;
//渐变色环颜色privateintcenterCircleColor;
privateintwidth;
//当前调色板的宽度privateintheight;
//当前调色板的高度privatefloatpaletteRadius;
//色环半径,整个环形外径,直接决定这个调色板的整体的大小,画渐变环可以看成画一个完整的圆形再挖掉一个小圆privatefloatcenterRadius;
//中心圆半径privatefloatpaletteWidth;
//色环的宽度privatefloatindictorRadius;
//小球的半径privatePoint indictorPosition;
// 小球当前位置privatePoint centerPosition;
//圆心的位置,色环圆心的位置privateBitmap indicatorBitmap;
// 指示器小球的图标privateintindictorResId;
//指示器图标的idprivateRainbowPalette.OnColorChangedListen listen;
privatestaticbooleanisShowIndictor=
true;
privatefinalstaticintBORDER_WIDTH=
2;
privatefinalstaticintPALETTE_WIDTH=
100;
privatefinalstaticintCENTER_CIRCLE_WIDTH=
5;
privatefinalstaticintINDICTOR_WIDTH=
5;
privatefinalstaticintDEF_INDICTOR_COLOR=
0xFFc9f5f1;
//设置指示小圆形的颜色privatefinalstaticintDEF_CIRCLE_COLOR=
0xFF0511FB;
//设置中间圆的默认颜色publicRainbowPalette(Context context) {
super}
(context);
publicRainbowPalette(Context context, AttributeSet attrs) {
super(context, attrs);
this}
init(attrs);
.context = context;
publicRainbowPalette(Context context, AttributeSet attrs,
intdefStyleAttr){
super(context, attrs, defStyleAttr);
this}
init(attrs);
.context=context;
privatevoidinit}
initRadiusWidth(attrs);
initPosition();
initPaint();
initAttrColor(attrs);
setPaletteSize();
(AttributeSet attrs){
/** * 用于设置中间圆的颜色 * @param color */publicvoidsetCenterPaint(
int}
centerPaint.setColor(color);
color){
/** * 设置调色板的尺寸 */privatevoidsetPaletteSizeWindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
(){
//获取WM对象intheight = (
int) (manager.getDefaultDisplay().getHeight() *
0.5f);
//获取屏幕的高度*0.5intwidth = (
int) (manager.getDefaultDisplay().getWidth() *
0.7f);
//获取屏幕宽度的0.7this.height = height -
36;
thissetMinimumHeight(height -
.width = width;
36}
setMinimumWidth(width);
);
/** * 设置颜色指示器的位置 * @param point */publicvoidsetIndictorPosition(Point point){
if(point!=
null) {
this.indictorPosition.x = point.x;
this}
}
.indictorPosition.y = point.y;
/** * 设置是否显示颜色指示器 * @param isShow */publicstaticvoidsetIndictorShow(
boolean}
RainbowPalette.isShowIndictor=isShow;
isShow){
/** * 设置指示器小球Color的默认值 * @param color */publicvoidsetBallColor(
intcolor){
this}
.indictorColor=color;
/** * 初始化各种Paint对象 */privatevoidinitPaintShader shader =
setGradientColors();
(){
newSweepGradient(
0,
0, gradientColors,
null);
//SweepGradient渐变//外层彩虹光环borderPaint =
newPaint(Paint.ANTI_ALIAS_FLAG);
//在画图的时候,图片如果旋转或缩放之后,总是会出现那些华丽的锯齿。给Paint加上抗锯齿标志borderPaint.setAntiAlias(
trueborderPaint.setShader(shader);
);
//传入着色器borderPaint.setStyle(Paint.Style.STROKE);
//设置仅描边borderPaint.setStrokeWidth(BORDER_WIDTH);
//设置描边的宽度,直接对应//初始化色环的Paint对象palettePaint =
newPaint(Paint.ANTI_ALIAS_FLAG);
//在画图的时候,图片如果旋转或缩放之后,总是会出现那些华丽的锯齿。给Paint加上抗锯齿标志palettePaint.setAntiAlias(
truepalettePaint.setShader(shader);
);
//传入着色器palettePaint.setStyle(Paint.Style.STROKE);
//设置仅描边palettePaint.setStrokeWidth(PALETTE_WIDTH);
//设置描边的宽度,直接对应//初始化中心圆的Paint对象centerPaint =
newcenterPaint.setAntiAlias(
Paint(Paint.ANTI_ALIAS_FLAG);
truecenterPaint.setStrokeWidth(CENTER_CIRCLE_WIDTH);
centerPaint.setColor(centerCircleColor);
);
//初始化小球对象indictorPosition=
newindictorPaint=
Point();
newindictorPaint.setAntiAlias(
Paint(Paint.ANTI_ALIAS_FLAG);
true}
indictorPaint.setStrokeWidth(INDICTOR_WIDTH);
indictorPaint.setColor(indictorColor);
);
privatevoidinitAttrColorR.styleable.rainbow_palette);
TypedArray types = context.obtainStyledAttributes(attrs,
(AttributeSet attrs){
try}
indictorColor = types.getColor( R.styleable.rainbow_palette_indicator_color,DEF_INDICTOR_COLOR );
centerCircleColor = types.getColor( R.styleable.rainbow_palette_center_circle_defcolor,DEF_CIRCLE_COLOR );
{
finallytypes.recycle();
{
// TypeArray用完需要recycle}
}
/** * 设置色环和中心圆、圆形指示小球的半径,宽度 */privatevoidinitRadiusWidthR.styleable.rainbow_palette);
TypedArray types = context.obtainStyledAttributes(attrs,
(AttributeSet attrs){
trypaletteRadius=types.getDimensionPixelOffset(R.styleable.rainbow_palette_palette_radius,(
paletteWidth = types.getDimensionPixelOffset( R.styleable.rainbow_palette_palette_width, PALETTE_WIDTH);
{
int)(width /
2- palettePaint.getStrokeWidth()*
1.2centerRadius=types.getDimensionPixelOffset(R.styleable.rainbow_palette_palette_radius,(
f));
int)((paletteRadius - palettePaint.getStrokeWidth() /
2) *
0.5indictorResId=types.getResourceId(R.styleable.rainbow_palette_ic_indicator,
f));
0);
if(indictorResId==
0) {
//未指定指示器的图标采用默认的绘制一个小圆形indictorRadius = (
float) (centerRadius *
0.5}
);
elseinitIndictorImg();
{
//使用设置的指示器目标}
}
finallytypes.recycle();
{
// TypeArray用完需要recycle}
}
/** * 初始化颜色指示器,设置指定图片 */privatevoidinitIndictorImg(){
// 将背景图片大小设置为属性设置的直径indicatorBitmap = BitmapFactory.decodeResource(getResources(), indictorResId );
//indicatorBitmap = Bitmap.createScaledBitmap(indicatorBitmap, (int)centerRadius,(int)centerRadius, false);indicatorBitmap= Bitmap.createScaledBitmap(indicatorBitmap,indicatorBitmap.getWidth(),indicatorBitmap.getHeight(),
true}
indictorRadius=indicatorBitmap.getHeight();
);
/** * 设置色环的绘制圆心 */privatevoidinitPositioncenterPosition=
(){
newcenterPosition.set(width/
Point();
2,height/
2-
50indictorPosition.set(
);
0,
0}
);
/** * 设置渐变环的颜色取值 */publicvoidsetGradientColorsgradientColors =
(){
newint[] {
0xFFFF0000,
0xFFFF00FF,
0xFF0000FF,
0xFF00FFFF,
0xFF00FF00,
0xFFFFFF00,
0xFFFF0000}
};
privatevoiddrawBorderborderPaint.setAlpha(
(Canvas canvas){
220canvas.drawOval(
);
newRectF(-(paletteRadius+
55), -(paletteRadius+
55), (paletteRadius+
55), (paletteRadius+
55)), borderPaint);
//画次外圈borderPaint.setAlpha(
100canvas.drawOval(
);
newRectF(-(paletteRadius+
60), -(paletteRadius+
60), (paletteRadius+
60), (paletteRadius+
60)), borderPaint);
//画外圈borderPaint.setAlpha(
60canvas.drawOval(
);
newRectF(-(paletteRadius+
65), -(paletteRadius+
65), (paletteRadius+
65), (paletteRadius+
65)), borderPaint);
//画外圈}
@OverrideprotectedvoidonDraw(Canvas canvas) {
supercanvas.translate(centerPosition.x,centerPosition.y);
.onDraw(canvas);
//移动中心,要不然会导致画出来之后不能完全显示,此时圆心相当于是由(0,0)变为(width / 2, height / 2 - 50)canvas.drawCircle(
0,
0, centerRadius, centerPaint);
//画中心圆canvas.drawOval(
newRectF(-paletteRadius, -paletteRadius, paletteRadius, paletteRadius), palettePaint);
//画色环drawBorder(canvas);
if(isShowIndictor) {
if(indictorResId ==
0canvas.drawCircle(indictorPosition.x, indictorPosition.y, (
) {
float) (centerRadius *
0.5), indictorPaint);
//画颜色指示器小球}
elsecanvas.drawBitmap(indicatorBitmap, indictorPosition.x, indictorPosition.y, indictorPaint);
{
//画指示器 指定图片Log.e(
}
}
"Position",
"indictorPosition: X:"+indictorPosition.x+
"Y:"}
+indictorPosition.y );
@OverrideprotectedvoidonMeasure(
intwidthMeasureSpec,
intheightMeasureSpec) {
super.onMeasure(width, height);
//重新设置View的位置,若不重写的话,则不会布局,即使设置centerInParent为true也无效//setMeasuredDimension(width,height);}
// 可以实现点击的时候显示对应的指示点,但会超过边界@OverridepublicbooleanonTouchEvent(MotionEvent event) {
floatx = event.getX() - width /
2;
//event.getX()以父视图的左上角作为原点floaty = event.getY() - height /
2+
50;
booleanpaletteRadius + palettePaint.getStrokeWidth() /
isEcfect = isEfectiveTouch(x, y,
2, paletteRadius - palettePaint.getStrokeWidth() /
2);
intchoosedColor;
switch(event.getAction()) {
caseMotionEvent.ACTION_DOWN:
if(isEcfect){
floatangle = (
float) Math.atan2(y, x);
floatunit = (
float) (angle / (
2* Math.PI));
if(unit <
0unit +=
) {
1indictorPosition.set((
choosedColor=getColorByTouchPalette(gradientColors,unit);
}
;
int) (event.getX()-(width /
2)), (
int) (event.getY()-(width /
2centerPaint.setColor(choosedColor);
)));
if(listen!=
null}
}
listen.onColorChange(choosedColor);
) {
else{
returnfalse}
;
break;
caseMotionEvent.ACTION_MOVE:
if(isEcfect){
floatangle = (
float) Math.atan2(y, x);
floatunit = (
float) (angle / (
2* Math.PI));
if(unit <
0unit +=
) {
1indictorPosition.set((
choosedColor=getColorByTouchPalette(gradientColors,unit);
}
;
int) (event.getX()-(width /
2)), (
int) (event.getY()-(width /
2}
invalidate();
centerPaint.setColor(choosedColor);
)));
break;
caseMotionEvent.ACTION_UP:
if(isEcfect){
floatangle = (
float) Math.atan2(y, x);
floatunit = (
float) (angle / (
2* Math.PI));
if(unit <
0unit +=
) {
1indictorPosition.set((
choosedColor=getColorByTouchPalette(gradientColors,unit);
}
;
int) (event.getX()-(width /
2)), (
int) (event.getY()-(width /
2centerPaint.setColor(choosedColor);
)));
if(listen!=
nulllisten.onColorChangeUp((
listen.onColorChange(choosedColor);
) {
int) (event.getX()-(width /
2)), (
int) (event.getY()-(width /
2}
}
)));
returntrue;
default:
break}
;
if}
invalidate();
(isEcfect) {
returntrue}
;
/** * 获取圆环上颜色 * @param colors * @param unit * @return */privateintgetColorByTouchPalette(
intcolors[],
floatunit) {
if(unit <=
0) {
returncolors[
0}
];
if(unit >=
1) {
returncolors[colors.length -
1}
];
floatp = unit * (colors.length -
1);
inti = (
intp -= i;
)p;
// now p is just the fractional part [0...1) and i is the indexintc0 = colors[i];
intc1 = colors[i+
1];
inta = ave(Color.alpha(c0), Color.alpha(c1), p);
intr = ave(Color.red(c0), Color.red(c1), p);
intg = ave(Color.green(c0), Color.green(c1), p);
intb = ave(Color.blue(c0), Color.blue(c1), p);
return}
Color.argb(a, r, g, b);
privateintave(
ints,
intd,
floatp) {
return}
s + Math.round(p * (d - s));
/** * 是否是有效Touch即是否是按在圆环之上的 * @return */privatebooleanisEfectiveTouch(
floatx,
floaty,
floatoutRadius,
floatinRadius){
doubleoutCircle = Math.PI * outRadius * outRadius;
doubleinCircle = Math.PI * inRadius * inRadius;
doublefingerCircle = Math.PI * (x * x + y * y);
if(fingerCircle < outCircle && fingerCircle > inCircle) {
returntrue}
;
else{
returnfalse}
}
;
/** * @describe 勾股定理求触摸点与圆心之间直线与水平方向的夹角角度 * @param a 触摸点 * @param b 圆心 * @return */publicfloatgetRadian(Point a, Point b) {
floatlenA = Math.abs(b.x - a.x);
floatlenB = Math.abs(b.y - a.y);
floatlenC = (
float) Math.sqrt(lenA * lenA + lenB * lenB);
floatang = (
floatang = ang * (b.y < a.y ? -
) Math.acos(lenA / lenC);
1:
1);
return}
ang;
/** * 设置小球的绘制位置,只能绘制在色环内 * @return */privatePoint
setIndictorPositionBorder(
intx,
intPoint touchPosition=
y){
newPoint centerCircle=
Point(x,y);
newPoint(
0,
0);
floatradian=getRadian(touchPosition,centerCircle);
floatdistance=getTwoPointDistance(centerCircle,touchPosition);
//touch点和圆心之间的距离floattouchToBallDistance;
//touch点和内切时小球圆心所在的位置之间的距离,如果不超出色环之外,这两点位置重合,如果超出了则自动移到内切位置处if(distance+indictorRadius>(
inttouchToBallDistance= Math.abs(distance-paletteRadius+indictorRadius);
)paletteRadius){
//touch点和内切(与外环)时小球圆心所在的位置之间的距离if(Math.abs(Math.cos(radian))==
1){
//如果夹角为0或者180°if(x<
0indictorPosition.set(-(
){
int)(paletteRadius-
20),
0}
);
elseindictorPosition.set((
{
int)(paletteRadius-
20),
0indictorPosition.set((
}
}
);
int)(x-(Math.cos(radian)*touchToBallDistance)),(
int}
)(y-(Math.sin(radian)*touchToBallDistance)));
elseif(distance<((
int)paletteRadius-
160touchToBallDistance= Math.abs(paletteRadius-
)){
160-distance+indictorRadius);
//touch点和外切(与内环)时小球圆心所在的位置之间的距离indictorPosition.set((
int)(x+(Math.cos(radian)*touchToBallDistance)),(
int}
)(y+(Math.sin(radian)*touchToBallDistance)));
else}
indictorPosition.set(x,y);
{
return}
indictorPosition;
/** * 求两点之间的距离 * @param a * @param b * @return */publicfloatgetTwoPointDistance(Point a, Point b){
return(
float) Math.sqrt(Math.pow(a.x - b.x,
2) + Math.pow(a.y - b.y,
2}
));
publicvoidsetOnChangeListen(OnColorChangedListen listen){
this}
.listen=listen;
publicinterface OnColorChangedListen{voidonColorChange(
intcolor);
//自定义的颜色切换的时候触发的回调voidonColorChangeUp(
intx,
int}
}
y);
来源: http://www.bubuko.com/infodetail-1962707.html