2009-11-10 8 views

답변

41

더 제어 된 방법을 사용하려면 둥근 사각형을 그려서 페인트의 포터 - 더프 Xfer 모드를 사용하여 이미지 위에가립니다.

XFER 페인트를 먼저 설치하고 둥근 비트 맵 :

Bitmap myCoolBitmap = ... ; // <-- Your bitmap you want rounded  
int w = myCoolBitmap.getWidth(), h = myCoolBitmap.getHeight(); 

// We have to make sure our rounded corners have an alpha channel in most cases 
Bitmap rounder = Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888); 
Canvas canvas = 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.RED); 

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

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

지금 이미지의 ontop을이 비트 맵을 적용 둥근 모서리

Bitmap result = Bitmap.createBitmap(myCoolBitmap.getWidth(), myCoolBitmap.getHeight() ,Bitmap.Config.ARGB_8888); 
Canvas resultCanvas = new Canvas(result) 
resultCanvas.drawBitmap(myCoolBitmap, 0, 0, null); 
resultCanvas.drawBitmap(rounder, 0, 0, xferPaint); 

비트 맵은 이제 결과에 있습니다.

+0

와우, 아주 좋아! 이 방법에 대한 유일한 관심은 속도입니다.이 기술을 한 번에 9 개의 이미지에 적용하면 앱이 엉망이됩니까? – iamkoa

+1

고성능 그래픽 상황에서이 기술을 사용합니다. 프로파일 링 후에도 아무런 문제가 없습니다. xferPaint와 둥근 비트 맵을 클래스의 필드로 저장하면 비트 맵이 느려지지만 그리는 것은 비교적 빠릅니다. – Ralphleon

+0

게시물에 사용하는 매개 변수에 대한 설명을 편집 할 수 있다면 좋을 것입니다. 샘플 코드는 멋지지만 이미이 클래스로 작업하지 않았다면 쉽게 이해할 수 있습니다. – Janusz

5

모서리가 둥근 투명 몸체를 가진 NinePatchDrawable 이미지를 만드는 것은 어떻습니까? 적절한 크기의 NinePatchDrawable 버전으로 이미지를 오버레이합니다.

+1

아주 좋은 생각이지만 내 둥근 모서리 이미지가 그라데이션 배경 위에 배치되면 어떻게 될까요? 여전히 작동할까요? – iamkoa

+1

나는 이것이 이것을 달성하기위한 덜 해킹 방법이라는 것에 동의한다. 이미지와 이미지 프레임을 FrameLayout에 순서대로 넣으면 작업이 완료됩니다. – Matthias

+0

@iamkoa : 둥근 모서리 이미지의 빈 부분이 투명해야합니다. 구석에서 그라데이션을 사용하는 경우 픽셀의 알파 채널을 사용하십시오. (저는 Gimp를 사용하여 그라디언트를 설정하여 투명에서 색상으로 바꿉니다.) – idbrii

28

왜 clipPath를 사용하지 않습니까?

protected void onDraw(Canvas canvas) { 
    Path clipPath = new Path(); 
    float radius = 10.0f; 
    float padding = radius/2; 
    int w = this.getWidth(); 
    int h = this.getHeight(); 
    clipPath.addRoundRect(new RectF(padding, padding, w - padding, h - padding), radius, radius, Path.Direction.CW); 
    canvas.clipPath(clipPath); 
    super.onDraw(canvas); 
} 
+0

아직 테스트를 해보지는 않았지만 이렇게 할 것 같습니다. Jerry에게 감사드립니다! – iamkoa

+2

참고 :이 시도한 후 참고 : 1 - 캔버스 클립 먼저 다음 비트 맵 2 그리기 - 그것은 비트 맵 마스크 및 xfer 모드 오버레이 3을 사용하는 것보다 빠르다 3 하나 앤티 앨리어스 clipPath 수 있지만 하나는 앤티 앨리어스 xfer 모드 오버레이의 마스크를 묘화하는 페인트. – Lumis

+0

둥근 모서리가 있지만 전체보기가있는 비트 맵을 그리지는 않았지만 찾고자하는 경우에 유용했습니다. – Jes

4
package com.pkg; 

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 

import android.app.Activity; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Canvas; 
import android.graphics.Paint; 
import android.graphics.PorterDuffXfermode; 
import android.graphics.Rect; 
import android.graphics.RectF; 
import android.graphics.Bitmap.Config; 
import android.graphics.PorterDuff.Mode; 
import android.os.Bundle; 
import android.os.Environment; 
import android.widget.ImageView; 

public class RoundedImage extends Activity { 
    /** Called when the activity is first created. */ 
    ImageView imag; 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     imag=(ImageView)findViewById(R.id.image); 

     //ImageView img1=(ImageView)findViewById(R.id.imageView1); 
     BitmapFactory.Options bitopt=new BitmapFactory.Options(); 
     bitopt.inSampleSize=1; 
     // String img=Environment.getExternalStorageDirectory().toString(); 
     // String filepath =Environment.getExternalStorageDirectory().toString(); 
     String filepath ="/mnt/sdcard/LOST.DIR"; 
     File imagefile = new File(filepath + "/logo.jpg"); 
     FileInputStream fis = null; 
     try 
     { 
     fis = new FileInputStream(imagefile); 
     } 
     catch (FileNotFoundException e1) 
     { 
     // TODO Auto-generated catch block 
     e1.printStackTrace(); 
     } 
     Bitmap bi = BitmapFactory.decodeStream(fis); 
     if(bi!=null){ 
      imag.setImageBitmap(getRoundedCornerBitmap(bi)); 
     } 

    } 

    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) { 
    Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), 
     bitmap.getHeight(), 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 = 12; 

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

    canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 

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

    return output; 
    } 
} 
+0

이 코드는 둥근 이미지를 얻는 데 도움이됩니다. – Swati

+1

하지만이 코드는 투명하게 처리해야 할 때 둥근 모서리를 얻는 데 도움이되지 않습니다. 그 방법을 알고 있습니까? – Thiago

15

로맹 가이 자신 his blog 이것에 대해 글을 참고하세요 : 이 Canvas.drawRoundRect를 사용하여 모서리가 둥근 직사각형()를 그립니다

은 단순히 사용자 정의 드로어 블을 쓴 둥근 이미지를 생성합니다. 트릭은 으로 BitmapShader와 함께 페인트를 사용하여 둥근 사각형을 채우고 은 단순한 색상 대신 질감을 사용합니다.

BitmapShader shader; 
shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 

Paint paint = new Paint(); 
paint.setAntiAlias(true); 
paint.setShader(shader); 

RectF rect = new RectF(0.0f, 0.0f, width, height); 

// rect contains the bounds of the shape 
// radius is the radius in pixels of the rounded corners 
// paint contains the shader that will texture the shape 
canvas.drawRoundRect(rect, radius, radius, paint); 

샘플 애플리케이션은 조금 더 나아가와 RadialGradient는 함께 BitmapShader을 결합하여 네트 효과를 가짜 : 다음과 같은 코드가 모습입니다.

6

다음은 ImageView에서 발견 한 방법입니다. 나는 여기와 비슷한 질문에 대한 답변을 포함하여 다른 방법을 시도했지만 이미지 뷰에 적용 할 코너가 필요하고 비트 맵에 직접 적용하지 않아도 제대로 작동하지 않는 것으로 나타났습니다. 비트 맵에 직접 적용하는 것은 비트 맵을 크기 조정/자르기/패닝하는 경우 작동하지 않습니다. 모서리도 크기 조정/자르기/패닝되기 때문입니다. 여기

public class RoundedCornersImageView extends ImageView { 
    private final Paint restorePaint = new Paint(); 
    private final Paint maskXferPaint = new Paint(); 
    private final Paint canvasPaint = new Paint(); 

    private final Rect bounds = new Rect(); 
    private final RectF boundsf = new RectF(); 

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

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

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

    private void init() { 
     canvasPaint.setAntiAlias(true); 
     canvasPaint.setColor(Color.argb(255, 255, 255, 255)); 
     restorePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); 
     maskXferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     canvas.getClipBounds(bounds); 
     boundsf.set(bounds); 

     canvas.saveLayer(boundsf, restorePaint, Canvas.ALL_SAVE_FLAG); 
     super.onDraw(canvas); 

     canvas.saveLayer(boundsf, maskXferPaint, Canvas.ALL_SAVE_FLAG); 
     canvas.drawARGB(0, 0, 0, 0); 
     canvas.drawRoundRect(boundsf, 75, 75, canvasPaint); 

     canvas.restore(); 
     canvas.restore(); 
    } 
} 

최종 레이어 합성을위한 하드웨어 레이어를 사용하는 대안이다 :

public class RoundedCornersImageView extends ImageView { 
    private final Paint restorePaint = new Paint(); 
    private final Paint maskXferPaint = new Paint(); 
    private final Paint canvasPaint = new Paint(); 

    private final Rect bounds = new Rect(); 
    private final RectF boundsf = new RectF(); 

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

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

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

    private void init() { 
     canvasPaint.setAntiAlias(true); 
     canvasPaint.setColor(Color.argb(255, 255, 255, 255)); 
     restorePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); 
     maskXferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); 

     setLayerType(View.LAYER_TYPE_HARDWARE, restorePaint); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     canvas.getClipBounds(bounds); 
     boundsf.set(bounds); 

     super.onDraw(canvas); 

     canvas.saveLayer(boundsf, maskXferPaint, Canvas.ALL_SAVE_FLAG); 
     canvas.drawARGB(0, 0, 0, 0); 
     canvas.drawRoundRect(boundsf, 75, 75, canvasPaint); 

     canvas.restore(); 
    } 
} 

가 처음에는 내 모서리는 검은 색이되고 있었기 때문에이 방법으로 작업을 얻을 수 없습니다; 나는이 문제를 읽은 후 문제가 무엇인지 깨달았다 : Android how to apply mask on ImageView?. 캔버스에서 알파를 수정하는 것은 실제로 화면에서 직접 "긁어 내고"검은 색 바탕 창에 구멍을내는 것입니다. 이것이 마스크를 적용하는 레이어와 합성 된 이미지를 스크린에 적용하는 레이어가 필요한 이유입니다.

+1

은 매력처럼 작동합니다. – Softlion

관련 문제