问题
First to see the below images.
package com.syncfusion.rating;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Region;
import android.view.View;
/**
* Created by chozarajan.pandiyarajan on 10/9/2015.
*/
public class SfRatingItem extends View {
private int fillColor,minDim,topXPoint,topYPoint;
private double bigHypot,bigA,bigB,littleHypot,littleA,littleB,value;
private Paint starPaint;
private Path path;
public SfRatingItem(Context context) {
super(context);
starPaint=new Paint();
fillPaint=new Paint();
path = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
starPaint.setStyle(Paint.Style.FILL_AND_STROKE);
starPaint.setAntiAlias(true);
minDim = Math.min(this.getWidth() - this.getPaddingLeft() -this.getPaddingRight(), this.getHeight() - this.getPaddingTop() - this.getPaddingBottom());
bigHypot = (minDim / Math.cos(Math.toRadians(18)));
bigB = minDim;
bigA = Math.tan(Math.toRadians(18)) * bigB;
littleHypot = bigHypot / (2 + Math.cos(Math.toRadians(72)) + Math.cos(Math.toRadians(72)));
littleA = Math.cos(Math.toRadians(72)) * littleHypot;
littleB = Math.sin(Math.toRadians(72)) * littleHypot;
topXPoint = (this.getWidth() - this.getPaddingLeft() -this.getPaddingRight()) / 2;
topYPoint =this.getPaddingTop();
path.moveTo(topXPoint, topYPoint);
path.lineTo((int) (topXPoint + bigA), (int) (topYPoint + bigB));
path.lineTo((int) (topXPoint - littleA - littleB), (int) (topYPoint + littleB));
path.lineTo((int) (topXPoint + littleA + littleB), (int) (topYPoint + littleB));
path.lineTo((int) (topXPoint - bigA), (int) (topYPoint + bigB));
path.lineTo(topXPoint, topYPoint);
path.close();
starPaint.setColor(Color.RED);
//Use below code to paint the star
canvas.drawPath(path, starPaint);
// Use below code to clip the star path.
// canvas.clipPath(path, Region.Op.DIFFERENCE);
// canvas.drawColor(Color.WHITE);
super.onDraw(canvas);
}
If you see the above images, you know the difference of this two images.
First one is clipped image. The clipped star of the edges is not clear.
Second one is Painted image. The painted star of the edges are clear.
Because in painted image, i am use to set true of setAntiAlise() property.
My question is how to get the clipped image edges are clear?
回答1:
It seems that you can't perform Anti Aliasing with clipPath
. Instead of using clipPath
for masking, try bitmap masking (it's a bit more complicated that clipPath
, but it gives a clear edges for the star). I have modified your code to use bitmap masking instead of clip path.
Code:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by chozarajan.pandiyarajan on 10/9/2015.
*/
public class SfRatingItem extends View {
private int fillColor, minDim, topXPoint, topYPoint;
private double bigHypot, bigA, bigB, littleHypot, littleA, littleB, value;
private Paint starPaint;
private Path path;
private Bitmap starBitmap;
private Bitmap backBitmap;
public SfRatingItem(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public SfRatingItem(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
public SfRatingItem(Context context) {
super(context);
initialize();
}
@Override
protected void onDraw(Canvas canvas) {
initialDraw();
Paint q = new Paint(Paint.ANTI_ALIAS_FLAG);
//canvas.saveLayer(0,0,canvas.getWidth(),canvas.getHeight(),q); // expensive call, instead set a hardware layer
setLayerType(LAYER_TYPE_HARDWARE, q);
canvas.drawBitmap(backBitmap, 0, 0, q);
q.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(starBitmap, 0, 0, q);
q.setXfermode(null);
}
private void initialDraw() {
starPaint.setStyle(Paint.Style.FILL_AND_STROKE);
starPaint.setAntiAlias(true);
minDim = Math.min(this.getWidth() - this.getPaddingLeft() - this.getPaddingRight(), this.getHeight() - this.getPaddingTop() - this.getPaddingBottom());
bigHypot = (minDim / Math.cos(Math.toRadians(18)));
bigB = minDim;
bigA = Math.tan(Math.toRadians(18)) * bigB;
littleHypot = bigHypot / (2 + Math.cos(Math.toRadians(72)) + Math.cos(Math.toRadians(72)));
littleA = Math.cos(Math.toRadians(72)) * littleHypot;
littleB = Math.sin(Math.toRadians(72)) * littleHypot;
topXPoint = (this.getWidth() - this.getPaddingLeft() - this.getPaddingRight()) / 2;
topYPoint = this.getPaddingTop();
path.moveTo(topXPoint, topYPoint);
path.lineTo((int) (topXPoint + bigA), (int) (topYPoint + bigB));
path.lineTo((int) (topXPoint - littleA - littleB), (int) (topYPoint + littleB));
path.lineTo((int) (topXPoint + littleA + littleB), (int) (topYPoint + littleB));
path.lineTo((int) (topXPoint - bigA), (int) (topYPoint + bigB));
path.lineTo(topXPoint, topYPoint);
path.close();
// Draw the STAR mask in a bitmap
RectF bounds = new RectF();
path.computeBounds(bounds, true);
starBitmap = Bitmap.createBitmap((int) bounds.width(), (int) bounds.height(), Bitmap.Config.ARGB_8888);
Canvas starCanvas = new Canvas(starBitmap);
starPaint.setColor(Color.BLACK);
starCanvas.drawPath(path, starPaint);
// Draw the background rectangle in a bitmap
starPaint.setColor(Color.RED);
backBitmap = Bitmap.createBitmap((int) bounds.width(), (int) bounds.height(), Bitmap.Config.ARGB_8888);
Canvas backCanvas = new Canvas(backBitmap);
final Rect backRect = new Rect(0, 0, backBitmap.getWidth(), backBitmap.getHeight());
backCanvas.drawRect(backRect, starPaint);
}
private void initialize() {
starPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
path = new Path();
}
}
Here I have created two bitmaps, one for the star mask and the other for the background rectangle. Then using Paint.setXfermode()
, I have masked one bitmap over the other. You can dynamically show the partial filling
by modifying the width of the background rectangle (i.e, width of backRect
). Currently I am creating the bitmaps in the onDraw()
method, but this is a bad idea and you need to do this in the `constructor itself, based on the size of the star required.
来源:https://stackoverflow.com/questions/33301655/how-to-clip-a-star-in-android-but-the-appearance-of-the-star-is-clear