Final result
- Chess with gradient color

- Chess without gradient color

Measurement
1. Get the width and height
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
useWidth = mWidth;
if (mWidth > mHeight) {
useWidth = mHeight;
}
}
Code language: JavaScript (javascript)
2. Define the minimum length of measurement
Divide the layout into 10 parts. The standard points are the multiples of 1, 3, 5, 7, and 9 of minwidth.
minwidth = useWidth / 10;
Draw the background (chess board)
1. Initialize the brush
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(4f);
mPaint.setAntiAlias(true);
mPaint.setAlpha(255);
Code language: JavaScript (javascript)
2. Draw a chessboard
canvas.drawLine(minwidth, 3 * minwidth, 9 * minwidth, 3 * minwidth, mPaint);
canvas.drawLine(minwidth, 5 * minwidth, 9 * minwidth, 5 * minwidth, mPaint);
canvas.drawLine(minwidth, 7 * minwidth, 9 * minwidth, 7 * minwidth, mPaint);
canvas.drawLine(3 * minwidth, minwidth, 3 * minwidth, 9 * minwidth, mPaint);
canvas.drawLine(5 * minwidth, minwidth, 5 * minwidth, 9 * minwidth, mPaint);
canvas.drawLine(7 * minwidth, minwidth, 7 * minwidth, 9 * minwidth, mPaint);
mPaint.setStrokeWidth(8f);
canvas.drawLine(minwidth, minwidth, 9 * minwidth, minwidth, mPaint);
canvas.drawLine(minwidth, 9 * minwidth, 9 * minwidth, 9 * minwidth, mPaint);
canvas.drawLine(minwidth, minwidth, minwidth, 9 * minwidth, mPaint);
canvas.drawLine(9 * minwidth, minwidth, 9 * minwidth, 9 * minwidth, mPaint);
Code language: CSS (css)
3. Make up for chessboard flaws
canvas.drawPoint(minwidth, minwidth, mPaint);
canvas.drawPoint(9 * minwidth, minwidth, mPaint);
canvas.drawPoint(minwidth, 9 * minwidth, mPaint);
canvas.drawPoint(9 * minwidth, 9 * minwidth, mPaint);
Code language: CSS (css)
Effect

Draw an immutable chess piece (in order to understand the animation movement position)
Position scale
(3,3) (3,5) (3,7)
(5,3) (5,5) (5,7)
(7,3) (7,5) (7,7)
canvas.drawCircle(3*minwidth, 3*minwidth, useWidth/16, mPaint); canvas.drawCircle(3*minwidth, 7*minwidth, useWidth/16, mPaint); canvas.drawCircle(5*minwidth, 5*minwidth, useWidth/16, mPaint); canvas.drawCircle(7*minwidth, 3*minwidth, useWidth/16, mPaint); canvas.drawCircle(7*minwidth, 7*minwidth, useWidth/16, mPaint); mPaint.setColor(rightcolor); canvas.drawCircle(3*minwidth, 5*minwidth, useWidth/16, mPaint); canvas.drawCircle(5*minwidth, 3*minwidth, useWidth/16, mPaint); canvas.drawCircle(5*minwidth, 7*minwidth, useWidth/16, mPaint); canvas.drawCircle(7*minwidth, 5*minwidth, useWidth/16, mPaint);
Preparing for the start of animation and animation
1. Three auxiliary classes prepare for animation (parameters imitate Android official Demo)
Mainly for get set construction, the code will be pasted at the end
2. Customize the interface instance to control the update calculation expression of the animation
public class XYEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
XYHolder startXY = (XYHolder) startValue;
XYHolder endXY = (XYHolder) endValue;
return new XYHolder(startXY.getX() + fraction * (endXY.getX() - startXY.getX()),
startXY.getY() + fraction * (endXY.getY() - startXY.getY()));
}
}
Code language: PHP (php)
3. Creation of chess pieces
private ShapeHolder createBall(float x, float y, int color) {
OvalShape circle = new OvalShape();
circle.resize(useWidth / 8f, useWidth / 8f);
ShapeDrawable drawable = new ShapeDrawable(circle);
ShapeHolder shapeHolder = new ShapeHolder(drawable);
shapeHolder.setX(x - useWidth / 16f);
shapeHolder.setY(y - useWidth / 16f);
Paint paint = drawable.getPaint();
paint.setColor(color);
return shapeHolder;
}
Code language: PHP (php)
4. Creation of animation
private void createAnimation() {
if (bounceAnim == null) {
XYHolder lstartXY = new XYHolder(3 * minwidth - useWidth / 16f, 3 * minwidth - useWidth / 16f);
XYHolder processXY = new XYHolder(7 * minwidth - useWidth / 16f, 3 * minwidth - useWidth / 16f);
XYHolder lendXY = new XYHolder(7 * minwidth - useWidth / 16f, 7 * minwidth - useWidth / 16f);
bounceAnim = ObjectAnimator.ofObject(ballHolder, "xY",
new XYEvaluator(), lstartXY, processXY, lendXY, lstartXY);
bounceAnim.setDuration(animaltime);
bounceAnim.setRepeatCount(ObjectAnimator.INFINITE);
bounceAnim.setRepeatMode(ObjectAnimator.RESTART);
bounceAnim.addUpdateListener(this);
}
if (bounceAnim1 == null) {
XYHolder lstartXY = new XYHolder(7 * minwidth - useWidth / 16f, 7 * minwidth - useWidth / 16f);
XYHolder processXY = new XYHolder(3 * minwidth - useWidth / 16f, 7 * minwidth - useWidth / 16f);
XYHolder lendXY = new XYHolder(3 * minwidth - useWidth / 16f, 3 * minwidth - useWidth / 16f);
bounceAnim1 = ObjectAnimator.ofObject(ballHolder1, "xY",
new XYEvaluator(), lstartXY, processXY, lendXY, lstartXY);
bounceAnim1.setDuration(animaltime);
bounceAnim1.setRepeatCount(ObjectAnimator.INFINITE);
bounceAnim1.setRepeatMode(ObjectAnimator.RESTART);
bounceAnim1.addUpdateListener(this);
}
}
Code language: JavaScript (javascript)
5. Synchronous execution of two animations
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bounceAnim).with(bounceAnim1);
animatorSet.start();
Code language: JavaScript (javascript)
6. Add a gradient to the pawn creation method
RadialGradient gradient = new RadialGradient(useWidth / 16f, useWidth / 16f,
useWidth / 8f, color, Color.GRAY, Shader.TileMode.CLAMP);
paint.setShader(gradient);
shapeHolder.setPaint(paint);
Code language: JavaScript (javascript)
Effect

Custom properties
attrs file:
<declare-styleable name="WeiqiView">
<attr name="leftscolor" format="reference|color"/>
<attr name="rightscolor" format="reference|color"/>
<attr name="qipancolor" format="reference|color"/>
<attr name="animalstime" format="integer"/>
</declare-styleable>
Code language: HTML, XML (xml)
private void initCustomAttrs(Context context, AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.WeiqiView);
leftcolor = ta.getColor(R.styleable.WeiqiView_leftscolor, Color.BLACK);
rightcolor = ta.getColor(R.styleable.WeiqiView_rightscolor, Color.WHITE);
qipancolor = ta.getColor(R.styleable.WeiqiView_qipancolor, Color.BLACK);
animaltime = ta.getInt(R.styleable.WeiqiView_animalstime, 2000);
ta.recycle();
}
Code language: JavaScript (javascript)
Running effect after custom attribute setting

Source code
WeiqiView.java
public class WeiqiView extends View implements ValueAnimator.AnimatorUpdateListener {
private Paint mPaint;
private int mWidth;
private int mHeight;
private int useWidth, minwidth;
private int leftcolor;
private int rightcolor;
private int qipancolor;
private int animaltime;
ValueAnimator bounceAnim, bounceAnim1 = null;
ShapeHolder ball, ball1 = null;
QiziXYHolder ballHolder, ballHolder1 = null;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public WeiqiView(Context context) {
this(context, null);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public WeiqiView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public WeiqiView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
initCustomAttrs(context, attrs);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public WeiqiView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
private void init() {
initPaint();
}
private void initCustomAttrs(Context context, AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.WeiqiView);
leftcolor = ta.getColor(R.styleable.WeiqiView_leftscolor, Color.BLACK);
rightcolor = ta.getColor(R.styleable.WeiqiView_rightscolor, Color.WHITE);
qipancolor = ta.getColor(R.styleable.WeiqiView_qipancolor, Color.BLACK);
animaltime = ta.getInt(R.styleable.WeiqiView_animalstime, 2000);
ta.recycle();
}
private void initPaint() {
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(4f);
mPaint.setAntiAlias(true);
mPaint.setAlpha(255);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
useWidth = mWidth;
if (mWidth > mHeight) {
useWidth = mHeight;
}
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
init();
minwidth = useWidth / 10;
mPaint.setColor(qipancolor);
if (ball == null) {
ball = createBall(3 * minwidth, 3 * minwidth, leftcolor);
ballHolder = new QiziXYHolder(ball);
}
if (ball1 == null) {
ball1 = createBall(7 * minwidth, 7 * minwidth, rightcolor);
ballHolder1 = new QiziXYHolder(ball1);
}
canvas.drawLine(minwidth, 3 * minwidth, 9 * minwidth, 3 * minwidth, mPaint);
canvas.drawLine(minwidth, 5 * minwidth, 9 * minwidth, 5 * minwidth, mPaint);
canvas.drawLine(minwidth, 7 * minwidth, 9 * minwidth, 7 * minwidth, mPaint);
canvas.drawLine(3 * minwidth, minwidth, 3 * minwidth, 9 * minwidth, mPaint);
canvas.drawLine(5 * minwidth, minwidth, 5 * minwidth, 9 * minwidth, mPaint);
canvas.drawLine(7 * minwidth, minwidth, 7 * minwidth, 9 * minwidth, mPaint);
mPaint.setStrokeWidth(8f);
canvas.drawLine(minwidth, minwidth, 9 * minwidth, minwidth, mPaint);
canvas.drawLine(minwidth, 9 * minwidth, 9 * minwidth, 9 * minwidth, mPaint);
canvas.drawLine(minwidth, minwidth, minwidth, 9 * minwidth, mPaint);
canvas.drawLine(9 * minwidth, minwidth, 9 * minwidth, 9 * minwidth, mPaint);
canvas.drawPoint(minwidth, minwidth, mPaint);
canvas.drawPoint(9 * minwidth, minwidth, mPaint);
canvas.drawPoint(minwidth, 9 * minwidth, mPaint);
canvas.drawPoint(9 * minwidth, 9 * minwidth, mPaint);
canvas.save();
canvas.translate(ball.getX(), ball.getY());
ball.getShape().draw(canvas);
canvas.restore();
canvas.save();
canvas.translate(ball1.getX(), ball1.getY());
ball1.getShape().draw(canvas);
canvas.restore();
}
private ShapeHolder createBall(float x, float y, int color) {
OvalShape circle = new OvalShape();
circle.resize(useWidth / 8f, useWidth / 8f);
ShapeDrawable drawable = new ShapeDrawable(circle);
ShapeHolder shapeHolder = new ShapeHolder(drawable);
shapeHolder.setX(x - useWidth / 16f);
shapeHolder.setY(y - useWidth / 16f);
Paint paint = drawable.getPaint();
paint.setColor(color);
RadialGradient gradient = new RadialGradient(useWidth / 16f, useWidth / 16f,
useWidth / 8f, color, Color.GRAY, Shader.TileMode.CLAMP);
paint.setShader(gradient);
shapeHolder.setPaint(paint);
return shapeHolder;
}
private void createAnimation() {
if (bounceAnim == null) {
XYHolder lstartXY = new XYHolder(3 * minwidth - useWidth / 16f, 3 * minwidth - useWidth / 16f);
XYHolder processXY = new XYHolder(7 * minwidth - useWidth / 16f, 3 * minwidth - useWidth / 16f);
XYHolder lendXY = new XYHolder(7 * minwidth - useWidth / 16f, 7 * minwidth - useWidth / 16f);
bounceAnim = ObjectAnimator.ofObject(ballHolder, "xY",
new XYEvaluator(), lstartXY, processXY, lendXY, lstartXY);
bounceAnim.setDuration(animaltime);
bounceAnim.setRepeatCount(ObjectAnimator.INFINITE);
bounceAnim.setRepeatMode(ObjectAnimator.RESTART);
bounceAnim.addUpdateListener(this);
}
if (bounceAnim1 == null) {
XYHolder lstartXY = new XYHolder(7 * minwidth - useWidth / 16f, 7 * minwidth - useWidth / 16f);
XYHolder processXY = new XYHolder(3 * minwidth - useWidth / 16f, 7 * minwidth - useWidth / 16f);
XYHolder lendXY = new XYHolder(3 * minwidth - useWidth / 16f, 3 * minwidth - useWidth / 16f);
bounceAnim1 = ObjectAnimator.ofObject(ballHolder1, "xY",
new XYEvaluator(), lstartXY, processXY, lendXY, lstartXY);
bounceAnim1.setDuration(animaltime);
bounceAnim1.setRepeatCount(ObjectAnimator.INFINITE);
bounceAnim1.setRepeatMode(ObjectAnimator.RESTART);
bounceAnim1.addUpdateListener(this);
}
}
public void startAnimation() {
createAnimation();
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bounceAnim).with(bounceAnim1);
animatorSet.start();
}
@Override
public void onAnimationUpdate(ValueAnimator animation) {
invalidate();
}
}
Code language: PHP (php)
QiziXYHolder.java
public class QiziXYHolder {
private ShapeHolder mBall;
public QiziXYHolder(ShapeHolder ball) {
mBall = ball;
}
public void setXY(XYHolder xyHolder) {
mBall.setX(xyHolder.getX());
mBall.setY(xyHolder.getY());
}
public XYHolder getXY() {
return new XYHolder(mBall.getX(), mBall.getY());
}
}
Code language: PHP (php)
ShapeHolder.java
public class ShapeHolder {
private float x = 0, y = 0;
private ShapeDrawable shape;
private int color;
private RadialGradient gradient;
private float alpha = 1f;
private Paint paint;
public void setPaint(Paint value) {
paint = value;
}
public Paint getPaint() {
return paint;
}
public void setX(float value) {
x = value;
}
public float getX() {
return x;
}
public void setY(float value) {
y = value;
}
public float getY() {
return y;
}
public void setShape(ShapeDrawable value) {
shape = value;
}
public ShapeDrawable getShape() {
return shape;
}
public int getColor() {
return color;
}
public void setColor(int value) {
shape.getPaint().setColor(value);
color = value;
}
public void setGradient(RadialGradient value) {
gradient = value;
}
public RadialGradient getGradient() {
return gradient;
}
public void setAlpha(float alpha) {
this.alpha = alpha;
shape.setAlpha((int)((alpha * 255f) + .5f));
}
public float getWidth() {
return shape.getShape().getWidth();
}
public void setWidth(float width) {
Shape s = shape.getShape();
s.resize(width, s.getHeight());
}
public float getHeight() {
return shape.getShape().getHeight();
}
public void setHeight(float height) {
Shape s = shape.getShape();
s.resize(s.getWidth(), height);
}
public ShapeHolder(ShapeDrawable s) {
shape = s;
}
}
Code language: PHP (php)
XYEvaluator.java
public class XYEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
XYHolder startXY = (XYHolder) startValue;
XYHolder endXY = (XYHolder) endValue;
return new XYHolder(startXY.getX() + fraction * (endXY.getX() - startXY.getX()),
startXY.getY() + fraction * (endXY.getY() - startXY.getY()));
}
}
Code language: PHP (php)
XYHolder.java
public class XYHolder {
private float mX;
private float mY;
public XYHolder(float x, float y) {
mX = x;
mY = y;
}
public float getX() {
return mX;
}
public void setX(float x) {
mX = x;
}
public float getY() {
return mY;
}
public void setY(float y) {
mY = y;
}
}
Code language: PHP (php)
attrs.xml
<resources>
<declare-styleable name="WeiqiView">
<attr name="leftscolor" format="reference|color"/>
<attr name="rightscolor" format="reference|color"/>
<attr name="qipancolor" format="reference|color"/>
<attr name="animalstime" format="integer"/>
</declare-styleable>
</resources>
Code language: HTML, XML (xml)
layout call
<com.shenzhen.jimeng.lookui.UI.WeiqiView
android:layout_centerInParent="true"
android:id="@+id/weiqi"
android:layout_width="400dp"
android:layout_height="400dp"/>
Code language: HTML, XML (xml)
Start animation in activity file
weiqi = (WeiqiView) findViewById(R.id.weiqi);
weiqi.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
weiqi.startAnimation();
}
});
Code language: JavaScript (javascript)