2010-04-27 8 views
26

Utilizzo la classe android.graphics.Canvas di Android to draw a ring. Il mio metodo clip OnDraw la tela per fare un buco per il cerchio interno, e quindi disegna il cerchio esterno completo sopra il foro:Come si esegue il antialias del limite della clip nell'area di lavoro di Android?

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(); 

Il risultato è un anello con un bordo esterno anti-aliasing bella e una frastagliata , brutta bordo interno:

aliased

Cosa posso fare per antialias bordo interno?

Non voglio imbrogliare disegnando un cerchio grigio nel mezzo perché la finestra di dialogo è leggermente trasparente. (Questa trasparenza non è così sottile su altri sfondi.)

risposta

19

AFAIK, non è possibile eseguire le regioni di clip antialias.

Suggerirei invece di utilizzare il mascheramento bitmap. Rendere il primo piano rosa, bianco e grigio chiaro a una bitmap, rendere la maschera del cerchio esterno/interno (il canale alfa della scala di grigi) a un'altra bitmap, quindi utilizzare Paint.setXfermode per rendere la bitmap in primo piano con la maschera come canale alfa.

Un esempio può essere trovato nel codice ApiDemos sorgente qui:


EDIT: per buona misura, questa è una schermata di tale attività nel Demos API, illustrating masking:

Xfermodes screenshot http://nikonizer.yfrog.com/Himg46/scaled.php?tn=0&server=46&filename=xfermodes.png&xsize=640&ysize=640

+0

Non sarebbe 'DstOut' funzionare se prima disegna il cerchio interno? –

+1

Uno dei due 'DstOut',' DstIn', 'SrcOut',' SrcIn' farebbe il trucco - dipende solo da come si struttura il codice. –

+0

Grazie! Ci proverò. –

2

So che questa non è una risposta generale, ma in questo caso particolare, è possibile disegnare archi con una larghezza di traccia spessa, invece dei cerchi + maschera.

0

si può provare il seguente codice:

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(); 
} 

}

Utilizzare il Xfermode Api con canvas.clipPath() può risolvere questo problema ... Result

0

Anch'io ho avuto questo stesso problema. Ho provato a usare il mascheramento Bitmap (xFermode) per correggere l'aliasing, ma era pesante.

Quindi per API < 19, ho utilizzato il modo mascheratura Bitmap e per API> = 19, ho utilizzato Path.Op. Invece di tagliare il tracciato e quindi disegnare la forma. Ho effettuato uno REVERSE_DIFFERENCE dello path e lo shape (che è di tipo Percorso). È possibile eseguire operazioni su Path dall'API 19 e versioni successive.

Funziona perfettamente per me!

+0

puoi fornire qualsiasi codice? – iscariot

+0

@iscariot è semplice. https://developer.android.com/reference/android/graphics/Path.html#op(android.graphics.Path,%20android.graphics.Path,%20android.graphics.Path.Op) – Henry

Problemi correlati