The previous article simply shared how to customize a color palette.
This looks too low. Here we add the function of sliding to get the color, and add a sliding ball at the same time.
As an upgraded version, the effect map is shown first.
Considering the example of dynamically judging the center of a circle to a ball, we can't deal with it as we did in the previous article. The center of the disc is treated as a variable. First initialized code:
private Paint mDiskPaint;//Palette brush private float mDiskPaintWidth;//Color Disk Width private float mDiskPoint;//Disc dot private Paint mPointPaint;//Dot brush private Shader shader; // Divergence position of color ring private Paint bgPaint;//Background brush private float r_bgPaint;//Background circle radius private float r_shaderPaint;// private float centerX;// Centroid X private float centerY;// Centroid Y private int mColor;//Current color selection //Gradient color ring private int[] mCircleColors = new int[] { 0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00, 0xFFFFFF00, 0xFFFF0000 }; private float[] colorPotXY = new float[2]; // White point coordinates private float markPointX;//Current sliding point x coordinates private float markPointY;//Current sliding point Y coordinates public ColorDiskView(Context context) { super(context); init(); } public ColorDiskView(Context context, AttributeSet attrs) { //this(context, attrs,0); super(context,attrs); init(); } public ColorDiskView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mDiskPaint=new Paint(Paint.ANTI_ALIAS_FLAG); mDiskPaint.setStyle(Paint.Style.STROKE); bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); LinearGradient gradient = new LinearGradient(0, 0, 700, 700, 0XFF222222, 0xFF909090, Shader.TileMode.CLAMP); bgPaint.setShader(gradient); mPointPaint=new Paint(Paint.ANTI_ALIAS_FLAG); mPointPaint.setColor(Color.WHITE); }
Initialization is relatively simple. The onMeasure method is still rewritten here. It's the same as before.
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSpecMode=MeasureSpec.getMode(widthMeasureSpec); int widthSpecSize=MeasureSpec.getSize(widthMeasureSpec); int heightSpecMode=MeasureSpec.getMode(heightMeasureSpec); int heightSpecSize=MeasureSpec.getSize(heightMeasureSpec); if (widthSpecMode==MeasureSpec.AT_MOST&&heightSpecMode==MeasureSpec.AT_MOST){ setMeasuredDimension(500,500); }else if(widthSpecMode==MeasureSpec.AT_MOST){ setMeasuredDimension(500,heightSpecSize); }else if (heightSpecMode==MeasureSpec.AT_MOST){ setMeasuredDimension(widthSpecSize,500); } }
The key point is that onDraw's method should pay attention to, first code:
protected void onDraw(Canvas canvas) { super.onDraw(canvas); final int paddingLeft=getPaddingLeft(); final int paddingRight=getPaddingRight(); final int paddingTop=getPaddingTop(); final int paddingBottom=getPaddingBottom(); int width=getWidth()-paddingLeft-paddingRight; int height=getHeight()-paddingTop-paddingBottom; //Shift, move the origin of the canvas's coordinates to width/2 in left and right direction, and height/2 in up and down direction. canvas.translate(width / 2, height / 2); centerX=Math.min(width,height)/2; centerY= height / 2; r_bgPaint=centerX; mDiskPaintWidth=r_bgPaint/12*5; mDiskPoint=mDiskPaintWidth/5; r_shaderPaint=r_bgPaint-mDiskPaintWidth/2; mDiskPaint.setStrokeWidth(mDiskPaintWidth); colorPotXY[0] =centerX -mDiskPaintWidth/2; colorPotXY[1] = 0; //Centroid determination and refilling shader=new SweepGradient(0,0,mCircleColors,null); mDiskPaint.setShader(shader); canvas.drawCircle(0,0,r_bgPaint,bgPaint); //Circle size canvas.drawCircle(0,0, r_shaderPaint, mDiskPaint);//Color Disk Size if (markPointX==0&&markPointY==0){ markPointX=colorPotXY[0]; markPointY=colorPotXY[1]; } canvas.drawCircle(markPointX, markPointY,mDiskPoint,mPointPaint); }
Note: Why: canvas.translate(width / 2, height / 2);
Look at several methods of canvas:
1.translate(x,y): translate, move the coordinate origin of the canvas to X in the left and right direction, and move y.canvas up and down at (0, 0) by default.
2.scale (x,y): Expansion. X is the magnification factor in the horizontal direction and Y is the magnification factor in the vertical direction.
3.rotate(angel): Rotate. Angle refers to the angle of rotation, clockwise rotation.
4.transform(): shear. The so-called shear, in fact, is to push the top or bottom of the image aside.
Because the starting point of the custom coordinates above is 0, 0, so I need to move to the middle.
Focus on these lines of code:
if (markPointX==0&&markPointY==0){ markPointX=colorPotXY[0]; markPointY=colorPotXY[1]; } canvas.drawCircle(markPointX, markPointY,mDiskPoint,mPointPaint);
}
This involves the processing of sliding, sliding is changing, markPointX, markPointY is changing.
@Override public boolean onTouchEvent(MotionEvent event) { float x=event.getX(); float y=event.getY(); //Limiting the Sliding Range of Small Balls if (Math.pow(x-centerX,2)+Math.pow(y-centerY,2)>Math.pow(centerX-mDiskPoint*2/3,2)|| Math.pow(x-centerX,2)+Math.pow(y-centerY,2)<Math.pow(centerX-mDiskPaintWidth+mDiskPoint*2/3,2)){ return true; } switch (event.getAction()){ case MotionEvent.ACTION_DOWN: moved(x, y); break; case MotionEvent.ACTION_MOVE: moved(x, y); break; case MotionEvent.ACTION_UP: moved(x, y); //Obtaining Angle float angle=calculateAngle(x,y); //Get the selected color mColor=calculateColor(angle); break; } return true; }
Finally, there are several ways to do this: stick it all out. It's not difficult:
private float calculateAngle(float x, float y) { return (float) Math.atan2(y - centerY, x - centerX); } private int calculateColor(float angle) { float unit = (float) (angle / (2 * Math.PI)); if (unit < 0) { unit += 1; } if (unit <= 0) { mColor = mCircleColors[0]; return mCircleColors[0]; } if (unit >= 1) { mColor = mCircleColors[mCircleColors.length - 1]; return mCircleColors[mCircleColors.length - 1]; } float p = unit * (mCircleColors.length - 1); int i = (int) p; p -= i; int c0 = mCircleColors[i]; int c1 = mCircleColors[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); Log.e("rgb","rgb"+r+":"+g+":"+b); mColor = Color.argb(a, r, g, b); return Color.argb(a, r, g, b); } private int ave(int s, int d, float p) { return s + Math.round(p * (d - s)); } private void moved(float x, float y) { //Calculating the coordinates of X.Y according to the trigonometric function tangent theorem markPointX =x-this.getWidth()/2 ;/*(float) ((r_bgPaint-mDiskPaintWidth/2) * Math.cos(Math.atan2(x - centerX, centerY - y) - (Math.PI / 2)));*/ markPointY =y-this.getHeight()/2 ;/*(float) ((r_bgPaint-mDiskPaintWidth/2) * Math.sin(Math.atan2(x - centerX, centerY - y) - (Math.PI / 2)));*/ invalidate(); }
Remember, invalidate() is used in the moved method.
Of course, these are written in the customization. Your Activity interface, or fragment interface, definitely needs to get color for further processing. You can choose to write interface or public method. I've just given you a way.
public int getColor(){ return mColor; }
Well, that's all for today.