如何在Android';什么是帆布?

如何在Android';什么是帆布?,android,android-widget,Android,Android Widget,我正在使用Android的类。我的onDraw方法剪辑画布,为内圈制作一个孔,然后在孔上绘制完整的外圈: clip = new Path(); clip.addRect(outerCircle, Path.Direction.CW); clip.addOval(innerCircle, Path.Direction.CCW); canvas.save(); canvas.clipPath(clip); canvas.drawOval(outerC

我正在使用Android的类。我的onDraw方法剪辑画布,为内圈制作一个孔,然后在孔上绘制完整的外圈:

    clip = new Path();
    clip.addRect(outerCircle, Path.Direction.CW);
    clip.addOval(innerCircle, Path.Direction.CCW);

    canvas.save();
    canvas.clipPath(clip);
    canvas.drawOval(outerCircle, lightGrey);
    canvas.restore();
结果是一个具有漂亮的抗锯齿外边缘和锯齿状丑陋内边缘的环:

如何对内边缘进行抗锯齿处理


我不想因为在中间画一个灰色的圆圈而作弊,因为对话框是稍微透明的。(这种透明度在其他背景上没有那么微妙。)

据我所知,您不能对区域进行反锯齿剪裁

我建议改为使用位图掩蔽。将粉色、白色和浅灰色前景渲染为一个位图,将外/内圆遮罩(灰度alpha通道)渲染为另一个位图,然后使用
Paint.setXfermode
以遮罩作为其alpha通道渲染前景位图


可以在ApiDemos的源代码中找到一个例子。

我知道这不是一个一般的答案,但在这种特殊情况下,您可以绘制具有粗笔划宽度的圆弧,而不是圆+遮罩。

您可以尝试以下代码:

public class GrowthView extends View {
private static final String TAG = "GrowthView";
private int bgColor = Color.parseColor("#33485d");
private int valColor = Color.parseColor("#ecb732");
private int[] scores = new int[]{0, 10, 80, 180, 800, 5000, 20000, 50000, 100000};

private Context mContext;

private float w;
private float h;

private Paint bgPaint;
private Paint growthPaint;
private Paint textPaint;
private Paint clipPaint;
private Path bgPath;
private Path bgClipPath;
private Path growthPath;

private int growthValue = 0;

private float bgFullAngle = 240.0f;
private float gapAngle = bgFullAngle / (scores.length - 1);

private float gapRadius = 21.5f;//实际为21px 略大半个像素避免path无法缝合error
private float outerRadius = 240.0f;
private float innerRadius = outerRadius - gapRadius * 2;

private RectF outerRecF;
private RectF innerRecF;
private RectF leftBoundRecF;
private RectF rightBoundRecF;

public GrowthView(Context context) {
    this(context, null);
}

public GrowthView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public GrowthView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    this.mContext = context;
    init();
}

private void init() {
    Xfermode xFermode = new PorterDuffXfermode(PorterDuff.Mode.DARKEN);

    bgPaint = new Paint();
    bgPaint.setStyle(Paint.Style.FILL);
    bgPaint.setColor(bgColor);
    bgPaint.setStrokeWidth(0.1f);
    bgPaint.setAntiAlias(true);

    growthPaint = new Paint();
    growthPaint.setStyle(Paint.Style.FILL_AND_STROKE);
    growthPaint.setColor(valColor);
    growthPaint.setStrokeWidth(1f);
    growthPaint.setAntiAlias(true);

    clipPaint = new Paint();
    clipPaint.setStyle(Paint.Style.FILL);
    clipPaint.setColor(Color.WHITE);
    clipPaint.setStrokeWidth(.1f);
    clipPaint.setAntiAlias(true);
    clipPaint.setXfermode(xFermode);

    textPaint = new Paint();
    textPaint.setTextSize(96);//todo comfirm the textSize
    textPaint.setStrokeWidth(1f);
    textPaint.setAntiAlias(true);
    textPaint.setTextAlign(Paint.Align.CENTER);
    textPaint.setColor(valColor);



    bgPath = new Path();
    growthPath = new Path();

    //todo 暂定中心点为屏幕中心
    DisplayMetrics metrics = new DisplayMetrics();
    WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
    wm.getDefaultDisplay().getMetrics(metrics);
    w = metrics.widthPixels;
    h = metrics.heightPixels;

    outerRecF = new RectF(w / 2 - outerRadius, h / 2 - outerRadius, w / 2 + outerRadius, h / 2 + outerRadius);
    innerRecF = new RectF(w / 2 - innerRadius, h / 2 - innerRadius, w / 2 + innerRadius, h / 2 + innerRadius);

    rightBoundRecF = new RectF(w / 2 + (float) Math.pow(3, 0.5) * (innerRadius + gapRadius) / 2 - gapRadius,
            h / 2 + (innerRadius + gapRadius) / 2 - gapRadius,
            w / 2 + (float) Math.pow(3, 0.5) * (innerRadius + gapRadius) / 2 + gapRadius,
            h / 2 + (innerRadius + gapRadius) / 2 + gapRadius);

    leftBoundRecF = new RectF(w / 2 - (float) Math.pow(3, 0.5) * (innerRadius + gapRadius) / 2 - gapRadius,
            h / 2 + (innerRadius + gapRadius) / 2 - gapRadius,
            w / 2 - (float) Math.pow(3, 0.5) * (innerRadius + gapRadius) / 2 + gapRadius,
            h / 2 + (innerRadius + gapRadius) / 2 + gapRadius);

    bgClipPath = new Path();
    bgClipPath.arcTo(innerRecF, 150.0f, 359.9f, true);
    bgClipPath.close();
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //bg
    float startAngle = 150.0f;
    float endRecfFullAngle = 180.0f;
    bgPath.arcTo(outerRecF, startAngle, bgFullAngle, true);
    bgPath.arcTo(rightBoundRecF, 30.0f, endRecfFullAngle, true);
    bgPath.arcTo(innerRecF, startAngle, bgFullAngle);
    bgPath.arcTo(leftBoundRecF, -30.0f, endRecfFullAngle);
    bgPath.rMoveTo(w / 2 - outerRadius * (float) Math.pow(3, 0.5) / 2, h / 2 + outerRadius / 2);
    bgPath.setFillType(Path.FillType.WINDING);
    bgPath.close();

    //growth
    if (getGrowthVal() != 0) {
        float temp = getGrowthAngle(getGrowthVal());
        growthPath.arcTo(outerRecF, startAngle, temp, true);
        growthPath.arcTo(getDynamicRecF(getGrowthVal()), getDynamicOriginAngle(getGrowthVal()), endRecfFullAngle, true);
        growthPath.arcTo(innerRecF, startAngle, temp);
        growthPath.arcTo(leftBoundRecF, -30.0f, endRecfFullAngle);
        growthPath.rMoveTo(w / 2 - outerRadius * (float) Math.pow(3, 0.5) / 2, h / 2 + outerRadius / 2);
        growthPath.close();
    }
    canvas.drawText(formatVal(getGrowthVal()), w / 2, h / 2, textPaint);
    canvas.clipPath(bgClipPath, Region.Op.DIFFERENCE);
    canvas.drawPath(bgPath, bgPaint);
    canvas.drawPath(growthPath, growthPaint);
    canvas.drawPath(bgClipPath, clipPaint);
}

private float getDynamicOriginAngle(int growthVal) {
    return growthVal <= 30 ? getGrowthAngle(growthVal) + 150 :
            getGrowthAngle(growthVal) - 210;
}

private RectF getDynamicRecF(int growthVal) {
    float dynamicAngle = getGrowthAngle(growthVal);
    //动态圆心
    float _w = w / 2 + (float) Math.sin(Math.toRadians(dynamicAngle - 120)) * (outerRadius - gapRadius);
    float _y = h / 2 - (float) Math.sin(Math.toRadians(dynamicAngle - 30)) * (outerRadius - gapRadius);
    return new RectF(_w - gapRadius, _y - gapRadius, _w + gapRadius, _y + gapRadius);
}

private int getGrowthVal() {
    return this.growthValue;
}

public void setGrowthValue(int value) {
    if (value < 0 || value > 100000) {
        try {
            throw new Exception("成长值不在范围内");
        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
            e.printStackTrace();
        }
    }
    this.growthValue = value;
    invalidate();
}

private float getGrowthAngle(int growthVal) {
    return gapAngle * (getLevel(growthVal) - 1)
            + gapAngle * (growthVal - scores[getLevel(growthVal) - 1]) /
            (scores[getLevel(growthVal)] - scores[getLevel(growthVal) - 1]);
}

private int getLevel(int score) {
    return score < 0 ? -1 : score <= 10 ? 1 : score <= 80 ? 2 : score <= 180 ? 3 : score <= 800 ?
            4 : score <= 5000 ? 5 : score <= 20000 ? 6 : score <= 50000 ? 7 : 8;
}

private String formatVal(int value) {
    StringBuilder builder = new StringBuilder(String.valueOf(value));
    return value < 1000 ? builder.toString() : builder.insert(builder.length() - 3, ',').toString();
}
公共类GrowthView扩展了视图{
私有静态最终字符串TAG=“GrowthView”;
private int bgColor=Color.parseColor(“#33485d”);
private int valColor=Color.parseColor(#ecb732”);
私有整数[]分数=新整数[]{0,10,80,180,800,5000,20000,50000,100000};
私有上下文;
私人浮动w;
私有浮动h;
私人涂料;
私人涂料;
私人涂料;
私人油漆剪贴画;
专用路径;
专用路径bgClipPath;
私有路径增长路径;
私有整数增长值=0;
专用浮球bgFullAngle=240.0f;
私人浮动gapAngle=bgFullAngle/(分数.length-1);
私人浮球gapRadius=21.5f//实际为21px略大半个像素避免路径无法缝合错误
专用浮球外表面=240.0f;
专用浮动内半径=外半径-加普拉半径*2;
私有RectF outerRecF;
私有RectF-innerRecF;
私有RectF leftBoundRecF;
私有RectF rightbundrecf;
公共增长视图(上下文){
这个(上下文,空);
}
公共增长视图(上下文、属性集属性){
这(上下文,属性,0);
}
公共增长视图(上下文、属性集属性、int-defStyle){
超级(上下文、属性、定义样式);
this.mContext=上下文;
init();
}
私有void init(){
Xfermode Xfermode=newporterduffxfermode(PorterDuff.Mode.DARKEN);
bgPaint=新油漆();
bgPaint.setStyle(Paint.Style.FILL);
bgPaint.setColor(bgColor);
bgPaint.设置行程宽度(0.1f);
bgPaint.setAntiAlias(真);
growthPaint=新油漆();
growthPaint.setStyle(绘制、样式、填充和笔划);
growthPaint.setColor(valColor);
生长涂料。设置行程宽度(1f);
growthPaint.setAntiAlias(真);
clipPaint=新油漆();
clipPaint.setStyle(绘制、样式、填充);
clipPaint.setColor(Color.WHITE);
clipPaint.setStrokeWidth(.1f);
clipPaint.setAntiAlias(true);
clipPaint.setXfermode(xFermode);
text油漆=新油漆();
textPaint.setTextSize(96);//要确认textSize
textPaint.设置行程宽度(1f);
textPaint.setAntiAlias(true);
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setColor(valColor);
bgPath=新路径();
growthPath=新路径();
//待办事项暂定中心点为屏幕中心
DisplayMetrics=新的DisplayMetrics();
WindowManager wm=(WindowManager)mContext.getSystemService(Context.WINDOW\u服务);
wm.getDefaultDisplay().getMetrics(metrics);
w=度量。像素;
h=度量。高度像素;
outerRecF=新的RectF(w/2-外层,h/2-外层,w/2+外层,h/2+外层);
innerRecF=新的RectF(w/2-innerRadius,h/2-innerRadius,w/2+innerRadius,h/2+innerRadius);
rightBoundRecF=新的RectF(w/2+(float)数学功率(3,0.5)*(innerRadius+gapRadius)/2-gapRadius,
h/2+(内半径+gapRadius)/2-gapRadius,
w/2+(浮点数)数学功率(3,0.5)*(内半径+gapRadius)/2+gapRadius,
h/2+(内半径+gapRadius)/2+gapRadius);
leftBoundRecF=新的RectF(w/2-(浮点)数学功率(3,0.5)*(内半径+gapRadius)/2-gapRadius,
h/2+(内半径+gapRadius)/2-gapRadius,
w/2-(浮动)数学功率(3,0.5)*(内半径+加普拉迪乌斯)/2+加普拉迪乌斯,
h/2+(内半径+gapRadius)/2+gapRadius);
bgClipPath=新路径();
bgClipPath.arcTo(innerRecF,150.0f,359.9f,真);
bgClipPath.close();
}
@凌驾
受保护的void onDraw(画布){
super.onDraw(帆布);
//背景
浮式startAngle=150.0f;
浮动端回冲角=180.0f;
arcTo(outerRecF、startAngle、bgpall、true);
bgPath.arcTo(rightbundrecf,30.0f,endRecfFullAngle,true);
arcTo(innerRecF、startAngle、bgFullAngle);
bgPath.arcTo(leftBoundRecF,-30.0f,endRecfFullAngle);
bgPath.rmovito(w/2-外差*(浮点)数学功率(3,0.5)/2,h/2+外差/2);
bgPath.setFillType(Path.FillType.WINDING);
bgPath.close();
//生长
如果(getGrowthVal()!=0){
浮动温度=getGrowthAngle(getGrowthVal());
生长路径.arcTo(outerRecF、startAngle、temp、true);
arcTo(getDynamicRecF(getGrowthVal()),getdynamicCoriginAngle(getGrowthVal()),endRecfFullAngle,true);
生长路径arcTo(innerRecF、startAngle、temp);
生长路径弧(leftBoundRecF,-30.0f,endRecfFullAngle);
生长路径rmovito(w/2-外层*(浮动)数学功率(3,0.5)/2,h/2+外层/2);
growthPath.close();
}
drawText(formatVal(getGrowthVal()),w/2,h/2,textPaint);
canvas.clipPath(bgClipPath,Region.Op.DIFFERENCE);
canvas.drawPath(bgPath,bgPaint);
canvas.drawPath(growthPath、growthPaint);
canvas.drawPath(bgClipPath,clipPaint);
}