Android Custom Disk Upgrade, Slide to Get RGB Colors

The previous article simply shared how to customize a color palette.

Android custom 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.


Upgraded version of palette. png

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.

Keywords: Android Fragment

Added by efficacious on Mon, 08 Jul 2019 00:09:58 +0300