【问题标题】:How to Clip a Star in android ? But the appearance of the star is clear如何在 android 中剪辑星星?但是明星的样子很清晰
【发布时间】: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。

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

【问题讨论】:

    标签: android path android-canvas paint clipping


    【解决方案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 :)
    猜你喜欢
    • 1970-01-01
    • 2016-01-13
    • 1970-01-01
    • 2019-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-21
    • 2016-02-03
    相关资源
    最近更新 更多