1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Android BitmapShader实现圆角 圆形ImageView

Android BitmapShader实现圆角 圆形ImageView

时间:2020-03-05 12:46:05

相关推荐

Android BitmapShader实现圆角 圆形ImageView

项目中,有时候我们会有需要圆角,或者是圆形的ImageView,自身的ImageView不带啊,不像Button可以利用shape来简单的实现圆角啊。。啊。。不要急,小司机来和大家一起实现你的需求。

今天小司机就和大家来利用BitmapShader来实现圆角、圆形ImageView,

本篇博客将会继续按照自定义View四大步骤来写,将会直接继承ImageView结合BitmapShader。开始我们的旅途吧。

浅显的的了解BitmapShader

BitmapShader是Shader的子类,可以通过Paint.setShader(Shader shader)进行设置、

这里我们只关注BitmapShader,构造方法:

mBitmapShader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);

参数1:bitmap

参数2,参数3:TileMode;

TileMode的取值有三种:

CLAMP 拉伸 REPEAT 重复MIRROR 镜像

如果大家给电脑屏幕设置屏保的时候,如果图片太小,可以选择重复、拉伸、镜像;

重复:就是横向、纵向不断重复这个bitmap

镜像:横向不断翻转重复,纵向不断翻转重复;

拉伸:这个和电脑屏保的模式应该有些不同,这个拉伸的是图片最后的那一个像素;

横向的最后一个横行像素,不断的重复,纵项的那一列像素,不断的重复;

现在大概明白了,BitmapShader通过设置给mPaint,然后用这个mPaint绘图时,就会根据你设置的TileMode,对绘制区域进行着色。

这里需要注意一点:就是BitmapShader是从你的画布的左上角开始绘制的,不在view的右下角绘制个正方形,它不会在你正方形的左上角开始。

开始我们的项目BitmapShader实战

1、自定义属性

values/attr.xml

<?xml version="1.0" encoding="utf-8"?><resources><declare-styleable name="RoundImageView"><attr name="borderRadius" format="reference|dimension"/><attr name="type"><enum name="circle" value="0"/><enum name="round" value="1"/></attr></declare-styleable></resources>

2、代码中获取自定义属性

基本都加了注释;然后在构造方法中获取了我们的自定义属性,以及部分变量的初始化。

public class RoundImageView extends ImageView {private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;private static final int COLORDRAWABLE_DIMENSION = 2;private int type; //picture typepublic static final int TYPE_CIRCLE = 0;public static final int TYPE_ROUND = 1;private static final int BODER_RADIUS_DEFAULT = 10; //default rectange border radiusprivate int mBorderRadius;private Paint mBitmapPaint;private int mRadius; //circle radiusprivate Matrix mMatrix; //matrix for scaleprivate BitmapShader mBitmapShader; //bitmapshaderprivate int mWidth; //views widthprivate RectF mRoundRect;public RoundImageView(Context context) {this(context,null);}public RoundImageView(Context context, AttributeSet attrs) {this(context, attrs,0);}public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.RoundImageView);mBorderRadius = array.getDimensionPixelSize(R.styleable.RoundImageView_borderRadius, (int) TypedValue.applyDimension(PLEX_UNIT_DIP,BODER_RADIUS_DEFAULT, getResources().getDisplayMetrics()));// default is 10type = array.getInt(R.styleable.RoundImageView_type, TYPE_CIRCLE);// circle defaultarray.recycle();// init paint and matrixmMatrix = new Matrix();mBitmapPaint = new Paint();mBitmapPaint.setAntiAlias(true);}

3、重写onMeasure

代码如下:

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);/*** if the shape is circle ,choose the min in width and height*/if (type == TYPE_CIRCLE) {mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());mRadius = mWidth / 2;setMeasuredDimension(mWidth, mWidth);}}

4、初始化BitmapShader

代码如下:

// init bitmapshaderprivate void initBitmapShader() {Drawable drawable = getDrawable();if (drawable == null) {return;}Bitmap bitmap = bitmapToDrawable(drawable);if (bitmap == null) {invalidate();return;}// use bitmap Aas a shader, is drawn in the specified areamBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);float scale = 1.0f;if (type == TYPE_CIRCLE) {// get the min of bitmap width or heightint bSize = Math.min(bitmap.getWidth(), bitmap.getHeight());scale = mWidth * 1.0f / bSize;} else if (type == TYPE_ROUND) {if (!(bitmap.getWidth() == getWidth() && bitmap.getHeight() == getHeight())) {/*If the width of the picture or the width of the view does not matchthe width of the need to calculate the need to scale the scale; zoom pictureafter the width and height, must be greater than the width of our view;so we take a large value*/scale = Math.max(getWidth() * 1.0f / bitmap.getWidth(),getHeight() * 1.0f / bitmap.getHeight());}}// shader transformation matrix, we mainly used here to zoom in or outmMatrix.setScale(scale, scale);// set the transformation matrixmBitmapShader.setLocalMatrix(mMatrix);// set shadermBitmapPaint.setShader(mBitmapShader);}

首先对drawable转化为我们的bitmap;

然后初始化mBitmapShader = new BitmapShader(bmp, TileMode.CLAMP, TileMode.CLAMP);

接下来,根据类型以及bitmap和view的宽高,计算scale;

关于scale的计算:

圆形时:取bitmap的宽或者高的小值作为基准,如果采用大值,缩放后肯定不能填满我们的圆形区域。然后,view的mWidth/bSize ; 得到的就是scale。

圆角时:因为设计到宽/高比例,我们分别getWidth() * 1.0f / bmp.getWidth() 和 getHeight() * 1.0f / bmp.getHeight() ;最终取大值,因为我们要让最终缩放完成的图片一定要大于我们的view的区域,有点类似centerCrop;

比如:view的宽高为10*20;图片的宽高为5*100 ; 最终我们应该按照宽的比例放大,而不是按照高的比例缩小;因为我们需要让缩放后的图片,自定大于我们的view宽高,并保证原图比例。

有了scale,就可以设置给我们的matrix;

然后使用mBitmapShader.setLocalMatrix(mMatrix);

最后将bitmapShader设置给paint。

关于drawable转bitmap的代码:

/*** @param drawable used for convert Bitmap to Drawable*/private Bitmap bitmapToDrawable(Drawable drawable) {if (drawable == null) {return null;}if (drawable instanceof BitmapDrawable) {return ((BitmapDrawable) drawable).getBitmap();}try {Bitmap bitmap;if (drawable instanceof ColorDrawable) {bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);} else {bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);}Canvas canvas = new Canvas(bitmap);drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());drawable.draw(canvas);return bitmap;} catch (Exception e) {e.printStackTrace();return null;}}

最后在onDraw里面调用initBitmapShader(),然后进行绘制。

5、重写onDraw()

最后一步绘制了,范围,缩放都完成了,只剩下绘制了。

代码如下:

@Overrideprotected void onDraw(Canvas canvas) {if (getDrawable() == null) {return;}initBitmapShader();if (type == TYPE_ROUND) {canvas.drawRoundRect(mRoundRect, mBorderRadius, mBorderRadius,mBitmapPaint);} else // circle{canvas.drawCircle(mRadius, mRadius, mRadius, mBitmapPaint);}}

6、状态的存储与恢复

防止突发事件,用来存储他的状态

存储当前的type以及mBorderRadius

private static final String STATE_INSTANCE = "state_instance"; private static final String STATE_TYPE = "state_type"; private static final String STATE_BORDER_RADIUS = "state_border_radius"; @Override protected Parcelable onSaveInstanceState() { Bundle bundle = new Bundle(); bundle.putParcelable(STATE_INSTANCE, super.onSaveInstanceState()); bundle.putInt(STATE_TYPE, type); bundle.putInt(STATE_BORDER_RADIUS, mBorderRadius); return bundle; } @Override protected void onRestoreInstanceState(Parcelable state) { if (state instanceof Bundle) { Bundle bundle = (Bundle) state; super.onRestoreInstanceState(((Bundle) state) .getParcelable(STATE_INSTANCE)); this.type = bundle.getInt(STATE_TYPE); this.mBorderRadius = bundle.getInt(STATE_BORDER_RADIUS); } else { super.onRestoreInstanceState(state); } }

此自定义的ImageView,提供了两个方法,用于动态修改圆角大小和type

/*Provide the usual setting method*/public void setBorderRadius(int borderRadius){int pxVal = dp2px(borderRadius);if (this.mBorderRadius != pxVal){this.mBorderRadius = pxVal;invalidate();}}public void setType(int type){if (this.type != type){this.type = type;if (this.type != TYPE_ROUND && this.type != TYPE_CIRCLE){this.type = TYPE_CIRCLE;}requestLayout();}}public int dp2px(int dpVal){return (int) TypedValue.applyDimension(PLEX_UNIT_DIP,dpVal, getResources().getDisplayMetrics());}

7、使用方法

<?xml version="1.0" encoding="utf-8"?><RelativeLayoutxmlns:android="/apk/res/android"xmlns:tools="/tools"xmlns:custom="/apk/res-auto"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.shanlovana.rcimageview.MainActivity"><com.shanlovana.rcimageview.views.RoundImageViewandroid:id="@+id/roundone"android:layout_width="100dp"android:layout_height="100dp"android:src="@drawable/damimi"custom:type="circle"/><com.shanlovana.rcimageview.views.RoundImageViewandroid:id="@+id/roundtwo"android:layout_marginTop="20dp"android:layout_below="@+id/roundone"android:layout_width="100dp"android:layout_height="100dp"android:src="@drawable/pangdi"custom:type="round"/><com.shanlovana.rcimageview.views.RoundImageViewandroid:id="@+id/roundthree"android:layout_marginTop="20dp"android:layout_below="@+id/roundtwo"android:layout_width="100dp"android:layout_height="100dp"custom:borderRadius="20dp"android:src="@drawable/luozhengying"custom:type="round"/><ImageViewandroid:id="@+id/roundfour"android:layout_marginTop="20dp"android:layout_below="@+id/roundthree"android:layout_width="100dp"android:layout_height="100dp"android:scaleType="fitXY"android:src="@drawable/pangdi"/></RelativeLayout>

存在bug和不足之处,欢迎指出,多谢。

Github地址:/Shanlovana/RCImageView

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。