3

角が丸いimageViewをレンダリングするための次のコードがあります。

public class RoundedCornerImageView extends ImageView {

private int rounded;
public RoundedCornerImageView(Context context) {
    super(context);
}

public RoundedCornerImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public RoundedCornerImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}


public int getRounded() {
    return rounded;
}

public void setRounded(int rounded) {
    this.rounded = rounded;

}


@Override
public void onDraw(Canvas canvas)
{


    Drawable drawable = getDrawable();

    int w = drawable.getIntrinsicHeight(),
        h = drawable.getIntrinsicWidth();

    Bitmap rounder = Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
    Canvas tmpCanvas = new Canvas(rounder);

    // We're going to apply this paint eventually using a porter-duff xfer mode.
    // This will allow us to only overwrite certain pixels. RED is arbitrary. This
    // could be any color that was fully opaque (alpha = 255)
    Paint xferPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    xferPaint.setColor(Color.WHITE);

    // We're just reusing xferPaint to paint a normal looking rounded box, the 20.f
    // is the amount we're rounding by.
    tmpCanvas.drawRoundRect(new RectF(0,0,w,h), 10.0f, 10.0f, xferPaint);

    // Now we apply the 'magic sauce' to the paint
    xferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

    drawable.draw(canvas);
    canvas.drawBitmap(rounder, 0, 0, xferPaint);
}
}



<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:background='#a3deef'
    >
<com.example.scheduling_android.view.RoundedCornerImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/eventImageView"
        android:adjustViewBounds="false"/>
</LinearLayout>

実際に画像の角を切り落としているという点で機能します。ただし、背景色 #a3deef を持つ linearLayout 内でこれをレンダリングしようとすると、問題が発生します。結果として表示されるのは #a3deef の背景色で、各画像は丸みを帯びた角で表示され、トリミングされた 4 つの角はすべて黒になります。

トリミングされた角を黒ではなく透明にするにはどうすればよいですか? また、他の色ではなく黒である理由を誰かが説明してくれたら素晴らしいと思います!

前もって感謝します。

4

3 に答える 3

6

ソースがまだ ではない場合、あなたが取っているアプローチは実際にはうまく機能しませんBitmap.境界が期待どおりに設定されないため、他の場所Canvasで呼び出すと正しい結果が得られません。Drawable.draw()

これを行うためのより効率的な方法は、ソース データを変更せず、丸みを帯びたクリップを図面に適用することCanvasです。半径が非常に大きい場合、これにより少しエイリアシングが発生する可能性がありますが、10px では目立ちません。このアプローチの他の唯一の欠点clipPath()は、現在ハードウェア アクセラレーションでサポートされていないことです。そのため、Android 3.0 以降でレンダリングを機能させるには、このビューのレイヤー タイプをソフトウェアに設定する必要があります。

public class RoundedCornerImageView extends ImageView {

    private Path roundedPath;
    private int rounded;

    public RoundedCornerImageView(Context context) {
        super(context);
        init();
    }

    public RoundedCornerImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RoundedCornerImageView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        // If the application is hardware accelerated,
        // must disable it for this view.
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        // Set a default radius
        setRounded(10);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        if (w != oldw || h != oldh) {
            roundedPath = new Path();
            roundedPath.addRoundRect(new RectF(0, 0, w, h),
                    rounded, rounded, Path.Direction.CW);
        }
    }

    public int getRounded() {
        return rounded;
    }

    public void setRounded(int rounded) {
        this.rounded = rounded;
        roundedPath = new Path();
        roundedPath.addRoundRect(new RectF(0, 0, getWidth(), getHeight()),
                rounded, rounded, Path.Direction.CW);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //Apply the clip
        canvas.clipPath(roundedPath);
        //Let the view draw as normal
        super.onDraw(canvas);
    }
}

変更されたバージョンでは、ビューまたは半径のサイズが変更されるたびにクリッピング パスを更新し、それを描画前にPathクリップとして適用するだけです。Canvas

HTH

于 2012-09-10T21:45:37.887 に答える
4

次の行を追加して、キャンバスを透明にします。

canvas.saveLayerAlpha(0, 0, canvas.getWidth(), canvas.getHeight(), 255, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);

また、逆塗りの丸みを帯びた四角形のパスを使用してビットマップをマスクするので、あなたのように中間マスキング ビットマップは必要ありません。

public class RoundedImageView extends ImageView {

    private Path mMaskPath;
    private Paint mMaskPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private int mCornerRadius = 10;

    public RoundedImageView(Context context) {
        super(context);

        init();
    }

    public RoundedImageView(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);

        init();
    }

    public RoundedImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        init();
    }

    private void init() {
        ViewCompat.setLayerType(this, ViewCompat.LAYER_TYPE_SOFTWARE, null);
        mMaskPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
    }

    /**
     * Set the corner radius to use for the RoundedRectangle.
     * 
     * @param Primitive int - The corner radius of the rounded rectangle.
     */
    public void setCornerRadius(int cornerRadius) {
        mCornerRadius = cornerRadius;
        generateMaskPath(getWidth(), getHeight());
        invalidate();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldW, int oldH) {
        super.onSizeChanged(w, h, oldW, oldH);

        if (w != oldW || h != oldH) {
            generateMaskPath(w, h);
        }
    }

    private void generateMaskPath(int w, int h) {
        mMaskPath = new Path();
        mMaskPath.addRoundRect(new RectF(0,0,w,h), mCornerRadius, mCornerRadius, Direction.CW);
        mMaskPath.setFillType(FillType.INVERSE_WINDING);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if(canvas.isOpaque()) { // If canvas is opaque, make it transparent
            canvas.saveLayerAlpha(0, 0, canvas.getWidth(), canvas.getHeight(), 255, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);
        }

        super.onDraw(canvas);

        if(mMaskPath != null) {
            canvas.drawPath(mMaskPath, mMaskPaint);
        }
    }
}
于 2012-11-30T06:19:04.260 に答える
1

これは、Canvasあなたが作業しているものが透明ではないためです。非透明Canvasの背景は黒です。

この回答は、 aを透過的に設定しますSurfaceView。あなたにとっては、 の背景を透明Canvasに設定するのと同じくらい簡単かもしれません。Bitmap

Bitmap rounder = Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
rounder.eraseColor(Color.TRANSPARENT);

でこれを試してImageView、背景を 100% 透明に設定することもできます。

setBackgroundColor(0);
于 2012-09-10T19:52:05.360 に答える