2012-09-10 38 views
3

我有以下一段代码用于渲染带圆角的imageView。在Android上为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个角落全部为黑色。

我应该怎么做才能使裁剪后的角部变得透明而不是黑色?另外,如果有人能向我解释为什么它会变黑,而不是其他任何颜色,那就太棒了!

在此先感谢。

回答

1

这是因为您使用的Canvas不透明。不透明的Canvas有黑色背景。

This answerSurfaceViewCanvas设置为透明。对你而言,这可能与将Bitmap的背景设置为透明一样简单。

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

你也可以试试这个在您的ImageView,其背景设定为100%透明:

setBackgroundColor(0); 
+0

设置视图的背景将不起作用。 –

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

+1

谢谢,在这个页面上找到了你的解决方案(http://tech.chitgoks。com/2012/08/28/how-to-add-round-corners-on-imageview-xml-in-android /),但它没有声明需要禁用硬件加速才能使视图正常工作 –

+0

剪辑顺便说一句,不支持反对。 –

3

加入这一行,使画布透明:

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