如何在 android 中剪辑星星?但是明星的样子很清晰

Posted

技术标签:

【中文标题】如何在 android 中剪辑星星?但是明星的样子很清晰【英文标题】:How to Clip a Star in android ? But the appearance of the star is clear 【发布时间】:2016-01-22 22:47:28 【问题描述】:

先看下图。

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

如果你看到上面的图片,你就知道这两张图片的区别了。

第一个是剪辑图像。边缘被剪掉的星形不清晰。

第二个是画图。边缘的彩绘星形清晰。

因为在绘制的图像中,我习惯于将 setAntiAlise() 属性设置为 true。

我的问题是如何让剪裁的图像边缘清晰?

【问题讨论】:

【参考方案1】:

您似乎无法使用clipPath 执行抗锯齿。不要使用clipPath 进行遮罩,而是尝试位图遮罩(它比clipPath 稍微复杂一点,但它为星星提供了清晰的边缘)。我已修改您的代码以使用位图遮罩而不是剪辑路径。

代码:

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

在这里,我创建了两个位图,一个用于星形蒙版,另一个用于背景矩形。然后使用Paint.setXfermode(),我将一个位图遮盖在另一个位图上。您可以通过修改背景矩形的宽度(即backRect的宽度)来动态显示partial filling。目前我正在onDraw() 方法中创建位图,但这是一个坏主意,您需要根据所需星的大小在`构造函数本身中执行此操作。

【讨论】:

谢谢,但请避免在onDraw 中创建对象(特别是Paint :)

以上是关于如何在 android 中剪辑星星?但是明星的样子很清晰的主要内容,如果未能解决你的问题,请参考以下文章

hdu 6110 …&&百度之星 T6

如何在android中剪辑圆圈

如何在 Flash 中为 MovieClip 分配属性并在 Flex 中访问它们?

如何在 android/andengine 中剪辑或屏蔽实体?

如何在 Xamarin Android 中剪辑滚动视图的边界

2017"百度之星"程序设计大赛 - 初赛(B)小小粉丝度度熊