Android 사용자 정의 컨트롤 의 원형/원 각 구현 코드
17300 단어 Android사용자 정의 컨트롤원형원 각
문 제 는 app 개발 에서 흔히 볼 수 있 는 장면 인 사용자 프로필 사진 을 원 으로 보 여 주 는 데 서 비롯 된다.
어떻게
슬기 로 운 저 는 첫 번 째 생각 은 중간 에 원형 이 투명 하고 사방 이 바탕색 과 같 으 며 사이즈 가 두상 과 같은 몽 판 그림 을 자 르 면 두상 에 덮 으 면 끝 이 잖 아 요.하하 하!
배경 이 순수한 전제 에서 이것 은 확실히 문 제 를 간단하게 해결 할 수 있 지만 배경 이 이렇게 간단 하지 않다 면?
이런 불규칙 한 배경 에서 두 가지 문제 가 있다.
1)배경 그림 은 핸드폰 너비 의 크기 조정 에 적응 되 고 두상 의 사 이 즈 는 너비 가 넓 고 DP 가 고정 되 어 있 기 때문에 고정된 몽 판 그림 은 서로 다른 기종 에서 배경 그림 과 일치 하 는 것 을 보장 할 수 없다.
2)、이런 순수한 색 이 아 닌 배경 에서 어느 날 이미지 위 치 를 조정 하려 면 다시 그림 을 바 꿔 야 합 니 다.유지 하기 가 너무 어렵 습 니 다..............................................
그래서 프로필 사진 이 네모 난 것 이 분명 하 다 면 ImageView 를 둥 글 게 합 시다.
일 을 시작 하 다
기본 적 인 사 고 는 ImageView 를 사용자 정의 하고 onDraw 를 다시 쓰 는 방법 으로 동 그 란 그림 을 그 리 는 것 입 니 다.
public class ImageViewPlus extends ImageView{
private Paint mPaintBitmap = new Paint(Paint.ANTI_ALIAS_FLAG);
private Bitmap mRawBitmap;
private BitmapShader mShader;
private Matrix mMatrix = new Matrix();
public ImageViewPlus(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
Bitmap rawBitmap = getBitmap(getDrawable());
if (rawBitmap != null){
int viewWidth = getWidth();
int viewHeight = getHeight();
int viewMinSize = Math.min(viewWidth, viewHeight);
float dstWidth = viewMinSize;
float dstHeight = viewMinSize;
if (mShader == null || !rawBitmap.equals(mRawBitmap)){
mRawBitmap = rawBitmap;
mShader = new BitmapShader(mRawBitmap, TileMode.CLAMP, TileMode.CLAMP);
}
if (mShader != null){
mMatrix.setScale(dstWidth / rawBitmap.getWidth(), dstHeight / rawBitmap.getHeight());
mShader.setLocalMatrix(mMatrix);
}
mPaintBitmap.setShader(mShader);
float radius = viewMinSize / 2.0f;
canvas.drawCircle(radius, radius, radius, mPaintBitmap);
} else {
super.onDraw(canvas);
}
}
private Bitmap getBitmap(Drawable drawable){
if (drawable instanceof BitmapDrawable){
return ((BitmapDrawable)drawable).getBitmap();
} else if (drawable instanceof ColorDrawable){
Rect rect = drawable.getBounds();
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
int color = ((ColorDrawable)drawable).getColor();
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawARGB(Color.alpha(color), Color.red(color), Color.green(color), Color.blue(color));
return bitmap;
} else {
return null;
}
}
}
코드 분석:canvas.draw Circle 은 그 려 진 모양 이 원형 이 고 동 그 란 내용 은 mPaintBitmap.setShader 를 통 해 이 루어 졌 다.
그 중에서 BitmapShader 는 Bitmap 가 ImageView 를 채 우 는 방식(CLAMP:스 트 레 칭 가장자리,MIRROR:미 러,REPEAT:전체 그림 중복)을 설정 해 야 합 니 다.
이것 은 사실 무엇 을 설정 하 는 지 중요 하지 않 습 니 다.왜냐하면 우리 가 실제 필요 로 하 는 것 은 Bitmap 를 미리 설정 한 세 가지 효과 가 아니 라 비례 에 따라 크기 를 조정 하 는 것 입 니 다.
그 러 니 mMatrix.setScale 과 mShader.setLocalMatrix 를 함께 사용 하여 그림 크기 를 조정 하 는 것 을 잊 지 마 세 요.
4.더 많은 게임 방법-테두리 지원
아래 효과 도 를 보 세 요.동 그 란 두상 에 테 두 리 를 두 르 려 면 어떻게 해 야 하나 요?
public class ImageViewPlus extends ImageView{
private Paint mPaintBitmap = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint mPaintBorder = new Paint(Paint.ANTI_ALIAS_FLAG);
private Bitmap mRawBitmap;
private BitmapShader mShader;
private Matrix mMatrix = new Matrix();
private float mBorderWidth = dip2px(15);
private int mBorderColor = 0xFF0080FF;
public ImageViewPlus(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
Bitmap rawBitmap = getBitmap(getDrawable());
if (rawBitmap != null){
int viewWidth = getWidth();
int viewHeight = getHeight();
int viewMinSize = Math.min(viewWidth, viewHeight);
float dstWidth = viewMinSize;
float dstHeight = viewMinSize;
if (mShader == null || !rawBitmap.equals(mRawBitmap)){
mRawBitmap = rawBitmap;
mShader = new BitmapShader(mRawBitmap, TileMode.CLAMP, TileMode.CLAMP);
}
if (mShader != null){
mMatrix.setScale((dstWidth - mBorderWidth * 2) / rawBitmap.getWidth(), (dstHeight - mBorderWidth * 2) / rawBitmap.getHeight());
mShader.setLocalMatrix(mMatrix);
}
mPaintBitmap.setShader(mShader);
mPaintBorder.setStyle(Paint.Style.STROKE);
mPaintBorder.setStrokeWidth(mBorderWidth);
mPaintBorder.setColor(mBorderColor);
float radius = viewMinSize / 2.0f;
canvas.drawCircle(radius, radius, radius - mBorderWidth / 2.0f, mPaintBorder);
canvas.translate(mBorderWidth, mBorderWidth);
canvas.drawCircle(radius - mBorderWidth, radius - mBorderWidth, radius - mBorderWidth, mPaintBitmap);
} else {
super.onDraw(canvas);
}
}
private Bitmap getBitmap(Drawable drawable){
if (drawable instanceof BitmapDrawable){
return ((BitmapDrawable)drawable).getBitmap();
} else if (drawable instanceof ColorDrawable){
Rect rect = drawable.getBounds();
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
int color = ((ColorDrawable)drawable).getColor();
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawARGB(Color.alpha(color), Color.red(color), Color.green(color), Color.blue(color));
return bitmap;
} else {
return null;
}
}
private int dip2px(int dipVal)
{
float scale = getResources().getDisplayMetrics().density;
return (int)(dipVal * scale + 0.5f);
}
}
코드 를 보면 테 두 리 를 넣 으 면 실제 적 으로 실심 단색 Paint 로 동 그 란 테 두 리 를 그 렸 고 이 를 바탕 으로 원래 의 두상 을 그리 면 된다.주의해 야 할 점 은 세 가지 가 있다.
1)원 틀 의 반지름 은 radius 가 아니 라 radius-mBorder Width/2.0f 여야 합 니 다.펜 을 들 고 선 을 그 리 는 것 을 상상 하 라.선 은 사실 오른쪽 그림 에 있 는 흰색 원 의 위 치 를 그 리 는 것 이지 만 매우 굵 을 뿐이다.
2)、ImageView 크기 가 변 하지 않 는 토대 에서 두상 의 실제 크기 는 테두리 가 없 을 때 보다 작 기 때문에 mMatrix.setScale 일 때 테두리 의 너 비 를 제거 해 야 합 니 다.
3)、비트 맵 을 그 릴 때 canvas.draw Circle(radius,radius,radius-mBorder Width,mPaintBitmap)을 직접 그 릴 수 없습니다.그러면 두상 의 오른쪽 과 아래쪽 가장자리 가 늘 어 난 것 을 발견 할 수 있 습 니 다(오른쪽 그림)
왜 일 까요?Paint 는 기본적으로 왼쪽 상단 을 기준 으로 그리 기 시 작 했 기 때문에 이때 두상 의 실제 영역 은 오른쪽 그림 에 있 는 빨간색 상자 이 고 빨간색 상자 가 넘 는 부분(원형의 오른쪽 과 아래쪽)은 자 연 스 럽 게 TileMode.ClaMP 효과 에 의 해 가장자리 로 늘 어 났 습 니 다.
따라서 좌표계 의 위 치 를 옮 기 고 원심 을 조정 해 야 두상 을 정확 한 구역(오른쪽 그림 녹색 상자)에 그 릴 수 있다.
5.더 많은 게임 방법--xml 설정 지원
테두리 가 생 겼 으 니 테두리 의 너비 와 색 을 설정 하려 면 어떻게 해 야 합 니까?
기본적으로 두 가지 사고방식:
1)ImageViewPlus 에 set 인 터 페 이 스 를 추가 하고 설정 이 완료 되면 invalidate()를 통과 합 니 다.다시 그리 면 됩 니 다.
2)xml 에서 사용자 정의 속성 을 설정 하 는 것 을 지원 합 니 다.이렇게 사용 하면 매우 편리 합 니 다.
xml 설정 사용자 정의 속성 을 지원 합 니 다.
사용자 정의 컨트롤 이 xml 설정 을 지원 하려 면 먼저\res\\values 에서 속성 을 정의 해 야 합 니 다.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="borderColor" format="color" />
<attr name="borderWidth" format="dimension" />
<declare-styleable name="ImageViewPlus">
<attr name="borderColor" />
<attr name="borderWidth" />
</declare-styleable>
</resources>
View attrs_imageviewplus.xml그리고 ImageView Plus 의 구조 함수 에서 사용자 정의 속성 을 읽 습 니 다.
private static final int DEFAULT_BORDER_COLOR = Color.TRANSPARENT;
private static final int DEFAULT_BORDER_WIDTH = 0;
public ImageViewPlus(Context context, AttributeSet attrs) {
super(context, attrs);
// xml
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ImageViewPlus);
mBorderColor = ta.getColor(R.styleable.ImageViewPlus_borderColor, DEFAULT_BORDER_COLOR);
mBorderWidth = ta.getDimensionPixelSize(R.styleable.ImageViewPlus_borderWidth, dip2px(DEFAULT_BORDER_WIDTH));
ta.recycle();
}
xml 레이아웃 에서 사용자 정의 속성 사용 하기:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:snser="http://schemas.android.com/apk/res/cc.snser.imageviewplus"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/wallpaper"
android:orientation="vertical"
tools:context="${relativePackage}.${activityClass}" >
<cc.snser.imageviewplus.ImageViewPlus
android:id="@+id/imgplus"
android:layout_width="200dp"
android:layout_height="300dp"
android:layout_marginBottom="50dp"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:src="@drawable/img_square"
snser:borderColor="#FF0080FF"
snser:borderWidth="15dp" />
</RelativeLayout>
6.더 많은 게임 방법--원 각 이미지 뷰원형 ImageView 와 대응 하 는 테 두 리 를 만 들 었 습 니 다.아래 의 원 각 ImageView 는 어떻게 실현 합 니까?
사실 원리 적 으로 canvas.draw Circle 대응 을 canvas.draw RoundRect 로 바 꾸 면 됩 니 다.코드 를 직접 붙 입 시다.
public class ImageViewPlus extends ImageView{
/**
* android.widget.ImageView
*/
public static final int TYPE_NONE = 0;
/**
*
*/
public static final int TYPE_CIRCLE = 1;
/**
*
*/
public static final int TYPE_ROUNDED_RECT = 2;
private static final int DEFAULT_TYPE = TYPE_NONE;
private static final int DEFAULT_BORDER_COLOR = Color.TRANSPARENT;
private static final int DEFAULT_BORDER_WIDTH = 0;
private static final int DEFAULT_RECT_ROUND_RADIUS = 0;
private int mType;
private int mBorderColor;
private int mBorderWidth;
private int mRectRoundRadius;
private Paint mPaintBitmap = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint mPaintBorder = new Paint(Paint.ANTI_ALIAS_FLAG);
private RectF mRectBorder = new RectF();
private RectF mRectBitmap = new RectF();
private Bitmap mRawBitmap;
private BitmapShader mShader;
private Matrix mMatrix = new Matrix();
public ImageViewPlus(Context context, AttributeSet attrs) {
super(context, attrs);
// xml
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ImageViewPlus);
mType = ta.getInt(R.styleable.ImageViewPlus_type, DEFAULT_TYPE);
mBorderColor = ta.getColor(R.styleable.ImageViewPlus_borderColor, DEFAULT_BORDER_COLOR);
mBorderWidth = ta.getDimensionPixelSize(R.styleable.ImageViewPlus_borderWidth, dip2px(DEFAULT_BORDER_WIDTH));
mRectRoundRadius = ta.getDimensionPixelSize(R.styleable.ImageViewPlus_rectRoundRadius, dip2px(DEFAULT_RECT_ROUND_RADIUS));
ta.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
Bitmap rawBitmap = getBitmap(getDrawable());
if (rawBitmap != null && mType != TYPE_NONE){
int viewWidth = getWidth();
int viewHeight = getHeight();
int viewMinSize = Math.min(viewWidth, viewHeight);
float dstWidth = mType == TYPE_CIRCLE ? viewMinSize : viewWidth;
float dstHeight = mType == TYPE_CIRCLE ? viewMinSize : viewHeight;
float halfBorderWidth = mBorderWidth / 2.0f;
float doubleBorderWidth = mBorderWidth * 2;
if (mShader == null || !rawBitmap.equals(mRawBitmap)){
mRawBitmap = rawBitmap;
mShader = new BitmapShader(mRawBitmap, TileMode.CLAMP, TileMode.CLAMP);
}
if (mShader != null){
mMatrix.setScale((dstWidth - doubleBorderWidth) / rawBitmap.getWidth(), (dstHeight - doubleBorderWidth) / rawBitmap.getHeight());
mShader.setLocalMatrix(mMatrix);
}
mPaintBitmap.setShader(mShader);
mPaintBorder.setStyle(Paint.Style.STROKE);
mPaintBorder.setStrokeWidth(mBorderWidth);
mPaintBorder.setColor(mBorderWidth > 0 ? mBorderColor : Color.TRANSPARENT);
if (mType == TYPE_CIRCLE){
float radius = viewMinSize / 2.0f;
canvas.drawCircle(radius, radius, radius - halfBorderWidth, mPaintBorder);
canvas.translate(mBorderWidth, mBorderWidth);
canvas.drawCircle(radius - mBorderWidth, radius - mBorderWidth, radius - mBorderWidth, mPaintBitmap);
} else if (mType == TYPE_ROUNDED_RECT){
mRectBorder.set(halfBorderWidth, halfBorderWidth, dstWidth - halfBorderWidth, dstHeight - halfBorderWidth);
mRectBitmap.set(0.0f, 0.0f, dstWidth - doubleBorderWidth, dstHeight - doubleBorderWidth);
float borderRadius = mRectRoundRadius - halfBorderWidth > 0.0f ? mRectRoundRadius - halfBorderWidth : 0.0f;
float bitmapRadius = mRectRoundRadius - mBorderWidth > 0.0f ? mRectRoundRadius - mBorderWidth : 0.0f;
canvas.drawRoundRect(mRectBorder, borderRadius, borderRadius, mPaintBorder);
canvas.translate(mBorderWidth, mBorderWidth);
canvas.drawRoundRect(mRectBitmap, bitmapRadius, bitmapRadius, mPaintBitmap);
}
} else {
super.onDraw(canvas);
}
}
private int dip2px(int dipVal)
{
float scale = getResources().getDisplayMetrics().density;
return (int)(dipVal * scale + 0.5f);
}
private Bitmap getBitmap(Drawable drawable){
if (drawable instanceof BitmapDrawable){
return ((BitmapDrawable)drawable).getBitmap();
} else if (drawable instanceof ColorDrawable){
Rect rect = drawable.getBounds();
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
int color = ((ColorDrawable)drawable).getColor();
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawARGB(Color.alpha(color), Color.red(color), Color.green(color), Color.blue(color));
return bitmap;
} else {
return null;
}
}
}
View ImageViewPlus.java
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:snser="http://schemas.android.com/apk/res/cc.snser.imageviewplus"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/wallpaper"
android:orientation="vertical"
tools:context="${relativePackage}.${activityClass}" >
<cc.snser.imageviewplus.ImageViewPlus
android:id="@+id/imgplus"
android:layout_width="200dp"
android:layout_height="300dp"
android:layout_marginBottom="50dp"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:src="@drawable/img_rectangle"
snser:type="rounded_rect"
snser:borderColor="#FF0080FF"
snser:borderWidth="10dp"
snser:rectRoundRadius="30dp" />
</RelativeLayout>
View layout
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="type">
<enum name="none" value="0" />
<enum name="circle" value="1" />
<enum name="rounded_rect" value="2" />
</attr>
<attr name="borderColor" format="color" />
<attr name="borderWidth" format="dimension" />
<attr name="rectRoundRadius" format="dimension" />
<declare-styleable name="ImageViewPlus">
<attr name="type" />
<attr name="borderColor" />
<attr name="borderWidth" />
<attr name="rectRoundRadius" />
</declare-styleable>
</resources>
View attrs_imageviewplus.xml
이상 은 본 고의 모든 내용 입 니 다.여러분 이 안 드 로 이 드 소프트웨어 프로 그래 밍 을 배 우 는 데 도움 이 되 기 를 바 랍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.