요즘 소셜 앱/웹을 보면 프로필 이미지를 둥근 라운딩 처리를 하는게 디자인적으로 트렌드인것 같다.
대표적으로 페이스북 메신저 앱과 Path앱 이다. 또한 구글+ 앱/웹 모두 프로필 이미지를 라운딩 처리 한 것을 볼 수있다.
그렇다면 안드로이드에서 사각형 이미지를 효율적으로 둥글게 라운딩 처리를 할 수 있을지 알아보자.
방법은 2가지로 방법으로
1. 이미지 위에 마스크 이미지를 얹는 방법
2. 이미지를 둥글게 잘라 내는 방법
첫번째 이미지 위에 마스크 이미지를 얹는 방법을 구현 해보자.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:foreground="@drawable/overlay" android:foregroundGravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@drawable/avatar" /> </FrameLayout> </FrameLayout>
이와 같은 레이아웃 구성을 통해서 이미지위에 마스크를 얹는 방법이다.
비 효율적
이 레이아웃 구성은 Background에 따라 마스크이미지가 바껴야 한다는 문제점이 있다. 백그라운드 이미지가 모두 같은 경우에는 이 방법이 효율적이긴 하나, 위의 이미지에서 보듯 배경 백그라운드가 화면별로 다양해질때는 배경과 맞는 Foreground 이미지가 필요하다.
두 번째 방법으로 Bitmap이미지를 라운드를 투명으로 라운딩 하는 방법이다.
public static Bitmap getRoundedBitmap(Bitmap bitmap) { final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); final Canvas canvas = new Canvas(output); final int color = Color.GRAY; final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); final RectF rectF = new RectF(rect); paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); canvas.drawOval(rectF, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); bitmap.recycle(); return output; }
인터넷을 보면 위와 같은 라운드 해주는 코드들이 많이돌아 다닌다. 새로운 비트맵을 만들어 라운딩 한다음 기존 비트맵을 recycle을 하고 새로 만든 비트맵을 반환 한다.
라운딩 된 부분이 투명으로 처리 되기 때문에 첫번째 방법과 같은 문제점은 없다.
성능/안정성 문제
현재 처럼 메인쓰레드(UI쓰레드)에서 작업을 하게 되면 여러 이미지를 한번에 생성 하게 되면 작업하는 동안 화면이 멈추게 되므로 별도의 쓰레드에서 작업을 해야 한다. 이 보다 더 문제점은 OutOfMemoryException이 일어날 가능성이 높다는 것이다. 기존 이미지를 recycle를 해준다고 해서 GC가 바로 메모리 해제를 해주지 않는다. 이러한 문제점으로 인해 OutOfMemoryException이 날 확률이 대단히 크다는 문제점이 있다.
위의 문제점은 자세히 설명한 아래 블로그를 통해 알아보면 되겠다.
http://blog.naver.com/PostView.nhn?blogId=nimbusob&logNo=147298809
이런 문제점을 모두 감안한 방법은 없을까?
안드로이드의 Drawable을 이용해서 이미지가 draw될때 이미지를 라운딩 처리해서 그리는 방법이다.
public class RoundedAvatarDrawable extends Drawable { private final Bitmap mBitmap; private final Paint mPaint; private final RectF mRectF; private final int mBitmapWidth; private final int mBitmapHeight; public RoundedAvatarDrawable(Bitmap bitmap) { mBitmap = bitmap; mRectF = new RectF(); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setDither(true); final BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mPaint.setShader(shader); mBitmapWidth = mBitmap.getWidth(); mBitmapHeight = mBitmap.getHeight(); } @Override public void draw(Canvas canvas) { canvas.drawOval(mRectF, mPaint); } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); mRectF.set(bounds); } @Override public void setAlpha(int alpha) { if (mPaint.getAlpha() != alpha) { mPaint.setAlpha(alpha); invalidateSelf(); } } @Override public void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } @Override public int getIntrinsicWidth() { return mBitmapWidth; } @Override public int getIntrinsicHeight() { return mBitmapHeight; } public void setAntiAlias(boolean aa) { mPaint.setAntiAlias(aa); invalidateSelf(); } @Override public void setFilterBitmap(boolean filter) { mPaint.setFilterBitmap(filter); invalidateSelf(); } @Override public void setDither(boolean dither) { mPaint.setDither(dither); invalidateSelf(); } public Bitmap getBitmap() { return mBitmap; } }
두번째 방법에서 새로운 Bitmap이미지를 만드는게 아닌 이미지를 화면에 그리는 시점에 라운딩 처리를 한다는 것이다. 위의 코드는 Bitmap을 Drawable의 Canvas에 그릴때 라운딩 처리한다. 성능과 효율을 한번에 해결 해준다.
The Good!
'안드로이드 개발 > View' 카테고리의 다른 글
Flat디자인의 핵심 안드로이드 이미지 Blur 효과 내기 (2) | 2013.08.12 |
---|---|
TextView의 이모티콘 문자를 이미지로된 이모티콘으로 바꾸기 (0) | 2013.07.06 |
Android View 관련된 오픈소스 정리 (4) | 2013.05.27 |