2015-12-03 145 views
6

我製作了這個自定義繪製,可以將任何可繪製的圓形剪裁成圓形。但是在我的實現中,所傳遞的drawable是原始形式的輸出,而不是循環形式。Android:圓形可繪製

public class CircularDrawable extends Drawable { 
    Paint mPaint,xfermodePaint; 
    Drawable mDrawable; 
    int[] vinylCenter = new int[2]; 
    int radius; 
    Bitmap src; 
    PorterDuffXfermode xfermode; 
    Rect rect; 
    Canvas testCanvas; 
    public CircularDrawable(Drawable drawable) { 
     mDrawable = drawable; 
     mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
     mPaint.setColor(0xffffffff); 
     mPaint.setStyle(Paint.Style.FILL); 
     xfermodePaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
     xfermode=new PorterDuffXfermode(PorterDuff.Mode.SRC_IN); 
     xfermodePaint.setXfermode(xfermode); 
     testCanvas=new Canvas(); 
    } 

    @Override 
    public void setBounds(Rect bounds) { 
     super.setBounds(bounds); 
     mDrawable.setBounds(bounds); 
    } 

    @Override 
    public void setBounds(int left, int top, int right, int bottom) { 
     super.setBounds(left, top, right, bottom); 
     mDrawable.setBounds(left, top, right, bottom); 
    } 

    @Override 
    protected void onBoundsChange(Rect bounds) { 
     super.onBoundsChange(bounds); 
     vinylCenter[0] = bounds.width()/2; 
     vinylCenter[1] = bounds.height()/2; 
     radius = (bounds.right - bounds.left)/2; 
     src = Bitmap.createBitmap(bounds.width(), bounds.height(), Bitmap.Config.ARGB_8888); 
     testCanvas.setBitmap(src); 
    } 


    @Override 
    public void draw(Canvas canvas) { 
     canvas.save(); 
     canvas.drawARGB(0, 0, 0, 0); 
     canvas.drawCircle(vinylCenter[0],vinylCenter[1],radius,mPaint); 
     mDrawable.draw(testCanvas); 
     canvas.drawBitmap(src,0f,0f,xfermodePaint); 
    } 



    @Override 
    public void setAlpha(int alpha) {/*ignored*/} 

    @Override 
    public void setColorFilter(ColorFilter colorFilter) {/*ignored*/} 

    @Override 
    public int getOpacity() { 
     /*ignored*/ 
     return 0; 
    } 
} 

我的錯誤是什麼?

此外,我正在使用SquareImageview來顯示這個只在onMeasure中使視圖平方的drawable。 此問題不適用於Circular Imageview。

+2

見[此](http://androidxref.com/6.0.0_r1/xref/frameworks/support/v4/donut/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java)作爲參考 – pskink

+0

@pskink,但這是其他的實現。我想知道在Porter/Duff實施中我的錯誤是什麼。 –

+0

如果是正方形,則表示您正在繪製整個DST區域 – pskink

回答

3

當使用Porter/Duff xfermode模式時(根據我的經驗,我的這個在android中),canvas默認沒有alpha通道。這就是整個圖像(src)成爲輸出的原因。 Porter/Duff xfermode基於Alpha Channel進行操作。

在圓形可繪製2畫布的許多實現中,其中一個給出了RGB圖像位圖,而另一個僅給出了帶有圓形遮罩的alpha通道位圖。 Porter/Duff xfermode應用,結果繪製在主畫布上。

我的錯誤是,我沒有指定繪製函數的畫布,即在使用xfermode畫布上的圖層時要考慮alpha通道。

抽籤功能將變得

@Override 
public void draw(Canvas canvas) { 
    int sc = canvas.saveLayer(null, null, 
        Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | 
        ); 
    canvas.drawCircle(vinylCenter[0],vinylCenter[1],radius,mPaint); 
    mDrawable.draw(testCanvas); 
    canvas.drawBitmap(src,0f,0f,xfermodePaint); 
    canvas.restoreToCount(sc); 
} 

保存層以指示與所述標誌alpha通道,然後使用xfermode。最後將其恢復到保存計數。

3

所以基本上我用這種方法來獲得圓角圖片

public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) { 
    Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); 
    Canvas canvas = new Canvas(output); 

    final int color = 0xff424242; 
    final Paint paint = new Paint(); 
    final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); 
    final RectF rectF = new RectF(rect); 
    final float roundPx = pixels; 

    paint.setAntiAlias(true); 
    canvas.drawARGB(0, 0, 0, 0); 
    paint.setColor(color); 
    canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 

    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 
    canvas.drawBitmap(bitmap, rect, rect, paint); 

    return output; 

但像你指出的,有時它不工作,以及它的工作,但會發生什麼的大部分時間是你的ImageView的可能它的scaletype設置爲centerCrop和其他類型,我所做的是我首先將我的圖像高度壓縮到與我的imageview相同的高度和寬度,以便整個圖像將適合imageview,並且不會發生縮放或我只計算多少根據身高使用此功能使角部高度變圓

private int calculatePercentage(int percentage, int target) 
{ 
    int k = (int)(target*(percentage/100.0f)); 
    return k; 

} 

所以我用我的代碼,如:圖像高度這給了我同樣的曲線所有圖像的new Bitmap(getRoundedCornerBitmap(bmp, calculatePercentage(5, bmp.getHeight()))); where 5 is 5是它的一些圖像比其他的大 `

+0

另一個解決方法沒有問。你對scaletype的假設是錯誤的。默認的scaletype是fitCenter。 –

+0

@Paritosh Tonk你可以採取我的幫助或沒有任何方式我的作品完美 –

+0

我感謝您的幫助。這個想法不是關於工作。它關於概念和爲什麼發生這種情況。 –

2
For rounded imageview you can use this code 

    public class RoundedImageView extends ImageView { 

    public RoundedImageView(Context context) { 
     super(context); 
     // TODO Auto-generated constructor stub 
    } 

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

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

    @Override 
    protected void onDraw(Canvas canvas) { 

     Drawable drawable = getDrawable(); 

     if (drawable == null) { 
      return; 
     } 

     if (getWidth() == 0 || getHeight() == 0) { 
      return; 
     } 
     Bitmap b = ((BitmapDrawable) drawable).getBitmap(); 
     Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true); 

     int w = getWidth();//, h = getHeight(); 

     Bitmap roundBitmap = getCroppedBitmap(bitmap, w); 
     canvas.drawBitmap(roundBitmap, 0, 0, null); 

    } 

    public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) 
    { 
     Bitmap sbmp; 
     if (bmp.getWidth() != radius || bmp.getHeight() != radius) 
      sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false); 
     else 
      sbmp = bmp; 
     Bitmap output = Bitmap.createBitmap(sbmp.getWidth(), sbmp.getHeight(),Config.ARGB_8888); 
     Canvas canvas = new Canvas(output); 

//  final int color = 0xffa19774; 
     final Paint paint = new Paint(); 
     final Rect rect = new Rect(0, 0, sbmp.getWidth(), sbmp.getHeight()); 

     paint.setAntiAlias(true); 
     paint.setFilterBitmap(true); 
     paint.setDither(true); 
     canvas.drawARGB(0, 0, 0, 0); 
//  paint.setColor(Color.parseColor("#BAB399")); 
     paint.setColor(Color.parseColor("#FF0000")); 
     canvas.drawCircle(sbmp.getWidth()/2 + 0.7f, sbmp.getHeight()/2 + 0.7f, sbmp.getWidth()/2 + 0.1f, paint); 
     paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 
     canvas.drawBitmap(sbmp, rect, rect, paint); 

     return output; 
    } 
} 
4

您圓繪製已經優化的實現支持庫V4:

Google reference

/** 
* A Drawable that wraps a bitmap and can be drawn with rounded corners. You can create a 
* RoundedBitmapDrawable from a file path, an input stream, or from a 
* {@link android.graphics.Bitmap} object. 
* <p> 
* Also see the {@link android.graphics.Bitmap} class, which handles the management and 
* transformation of raw bitmap graphics, and should be used when drawing to a 
* {@link android.graphics.Canvas}. 
* </p> 
*/ 
public abstract class RoundedBitmapDrawable extends Drawable .... 
3
For circular imageview use the below code 

public class RoundedImageView extends ImageView { 

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

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

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

    @Override 
    protected void onDraw(Canvas canvas) { 
     BitmapDrawable drawable = (BitmapDrawable) getDrawable(); 

     if (drawable == null) { 
      return; 
     } 

     if (getWidth() == 0 || getHeight() == 0) { 
      return; 
     } 

     Bitmap fullSizeBitmap = drawable.getBitmap(); 

     int scaledWidth = getMeasuredWidth(); 
     int scaledHeight = getMeasuredHeight(); 

     /* 
     * scaledWidth = scaledWidth/2; scaledHeight = scaledHeight/2; 
     */ 

     Bitmap mScaledBitmap; 
     if (scaledWidth == fullSizeBitmap.getWidth() 
       && scaledHeight == fullSizeBitmap.getHeight()) { 
      mScaledBitmap = fullSizeBitmap; 
     } else { 
      mScaledBitmap = Bitmap.createScaledBitmap(fullSizeBitmap, 
        scaledWidth, scaledHeight, true /* filter */); 
     } 

     // Bitmap roundBitmap = getRoundedCornerBitmap(mScaledBitmap); 

     // Bitmap roundBitmap = getRoundedCornerBitmap(getContext(), 
     // mScaledBitmap, 10, scaledWidth, scaledHeight, false, false, 
     // false, false); 
     // canvas.drawBitmap(roundBitmap, 0, 0, null); 

     Bitmap circleBitmap = getCircledBitmap(mScaledBitmap); 

     canvas.drawBitmap(circleBitmap, 0, 0, null); 

    } 

    public Bitmap getRoundedCornerBitmap(Context context, Bitmap input, 
      int pixels, int w, int h, boolean squareTL, boolean squareTR, 
      boolean squareBL, boolean squareBR) { 

     Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888); 
     Canvas canvas = new Canvas(output); 
     final float densityMultiplier = context.getResources() 
       .getDisplayMetrics().density; 

     final int color = 0xff424242; 

     final Paint paint = new Paint(); 
     final Rect rect = new Rect(0, 0, w, h); 
     final RectF rectF = new RectF(rect); 

     // make sure that our rounded corner is scaled appropriately 
     final float roundPx = pixels * densityMultiplier; 

     paint.setAntiAlias(true); 
     canvas.drawARGB(0, 0, 0, 0); 
     paint.setColor(color); 
     canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 

     // draw rectangles over the corners we want to be square 
     if (squareTL) { 
      canvas.drawRect(0, 0, w/2, h/2, paint); 
     } 
     if (squareTR) { 
      canvas.drawRect(w/2, 0, w, h/2, paint); 
     } 
     if (squareBL) { 
      canvas.drawRect(0, h/2, w/2, h, paint); 
     } 
     if (squareBR) { 
      canvas.drawRect(w/2, h/2, w, h, paint); 
     } 

     paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 
     canvas.drawBitmap(input, 0, 0, paint); 

     return output; 
    } 

    Bitmap getCircledBitmap(Bitmap bitmap) { 

     Bitmap result = Bitmap.createBitmap(bitmap.getWidth(), 
       bitmap.getHeight(), Bitmap.Config.ARGB_8888); 

     Canvas canvas = new Canvas(result); 

     int color = Color.BLUE; 
     Paint paint = new Paint(); 
     Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); 

     paint.setAntiAlias(true); 
     canvas.drawARGB(0, 0, 0, 0); 
     paint.setColor(color); 
     // canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 
     canvas.drawCircle(bitmap.getWidth()/2, bitmap.getHeight()/2, 
       bitmap.getHeight()/2, paint); 

     paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 
     canvas.drawBitmap(bitmap, rect, rect, paint); 

     return result; 
    } 

} 
0

嘗試禁用硬件加速,如果你使用的是PorterDuffXfermode

在艙單整個活動:

<activity android:hardwareAccelerated="false" /> 

或特定視圖在其上使用xfermode:

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);