Android——RoundedImageView应用及源码总结笔记
2017-08-19 15:47
274 查看
介绍
源码参考文章,RoundedImageView是用来对图片进行裁剪,可以在代码块中实现,也可以在布局xml中实现。github源码地址:https://github.com/vinc3m1/RoundedImageView
作者对这个开源框架的评价就是
There are many ways to create rounded corners in android, but this is the fastest and best one that I know of because it:
does not create a copy of the original bitmap
does not use a clipPath which is not hardware accelerated and not anti-aliased.
does not use setXfermode to clip the bitmap and draw twice to the canvas.
第一是无需对原始的bitmap进行复制,第二是不需硬件上的加速和反锯齿,第三是没有使用用Xfermode,所以需要使用画布处理两次
应用
第一个当然是对库的支持compile 'com.makeramen:roundedimageview:2.3.0'
在xml文件中引用:
<com.makeramen.roundedimageview.RoundedImageView xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/imageView1" android:src="@drawable/photo1" android:scaleType="fitCenter" app:riv_corner_radius="30dip" app:riv_border_width="2dip" app:riv_border_color="#333333" app:riv_mutate_background="true" app:riv_tile_mode="repeat" app:riv_oval="true" />
在代码中引用:
RoundedImageView riv = new RoundedImageView(context); riv.setScaleType(ScaleType.CENTER_CROP); riv.setCornerRadius((float) 10); riv.setBorderWidth((float) 2); riv.setBorderColor(Color.DKGRAY); riv.mutateBackground(true); riv.setImageDrawable(drawable); riv.setBackground(backgroundDrawable); riv.setOval(true); riv.setTileModeX(Shader.TileMode.REPEAT); riv.setTileModeY(Shader.TileMode.REPEAT);
可以参考下别人详细的实现过程http://blog.csdn.net/aaawqqq/article/details/38057145
开始
RoundedImageView主要的核心是在RoundedDrawer所以核心是对于RoundedDrawer的分析一、Drawable转化为圆角的Drawable
1、构造方法public RoundedDrawable(Bitmap bitmap) { mBitmap = bitmap; mBitmapWidth = bitmap.getWidth(); mBitmapHeight = bitmap.getHeight(); mBitmapRect.set(0, 0, mBitmapWidth, mBitmapHeight); mBitmapPaint = new Paint(); mBitmapPaint.setStyle(Paint.Style.FILL); mBitmapPaint.setAntiAlias(true); mBorderPaint = new Paint(); mBorderPaint.setStyle(Paint.Style.STROKE); mBorderPaint.setAntiAlias(true); mBorderPaint.setColor(mBorderColor.getColorForState(getState(), DEFAULT_BORDER_COLOR)); mBorderPaint.setStrokeWidth(mBorderWidth); }
用到了2个Paint,分别是mBitmapPaint和mBorderPaint。一个用于绘制内部具体内容,比如填充什么的,一个用于绘制边框。
这里就能用来解释为什么上面作者说的第三点没使用setXfermode所以需要使用画布画两次,如果使用setXfermode进行绘制就只需要一次。
2、fromDrawable方法
public static Drawable fromDrawable(Drawable drawable) { if (drawable != null) { if (drawable instanceof RoundedDrawable) { // just return if it's already a RoundedDrawable return drawable; } else if (drawable instanceof LayerDrawable) { LayerDrawable ld = (LayerDrawable) drawable; int num = ld.getNumberOfLayers(); // loop through layers to and change to RoundedDrawables if possible for (int i = 0; i < num; i++) { Drawable d = ld.getDrawable(i); ld.setDrawableByLayerId(ld.getId(i), fromDrawable(d)); } return ld; } // try to get a bitmap from the drawable and Bitmap bm = drawableToBitmap(drawable); if (bm != null) { return new RoundedDrawable(bm); } } return drawable; }
这个方法中我们可以看到如果drawable本身就是RoundedDrawable,那么直接返回,如果不是就每一个LayoutDrawable的item改造成RoundedDrawable,我们可以看到其中使用fromDrawable的递归调用改造。
后将drawable转成bitmap后直接返回RoundedDrawable
3、生成圆角Draw
@Override public void draw(@NonNull Canvas canvas) { if (mRebuildShader) { BitmapShader bitmapShader = new BitmapShader(mBitmap, mTileModeX, mTileModeY); if (mTileModeX == Shader.TileMode.CLAMP && mTileModeY == Shader.TileMode.CLAMP) { bitmapShader.setLocalMatrix(mShaderMatrix); } mBitmapPaint.setShader(bitmapShader); mRebuildShader = false; } if (mOval) { if (mBorderWidth > 0) { canvas.drawOval(mDrawableRect, mBitmapPaint); canvas.drawOval(mBorderRect, mBorderPaint); } else { canvas.drawOval(mDrawableRect, mBitmapPaint); } } else { if (any(mCornersRounded)) { float radius = mCornerRadius; if (mBorderWidth > 0) { canvas.drawRoundRect(mDrawableRect, radius, radius, mBitmapPaint); canvas.drawRoundRect(mBorderRect, radius, radius, mBorderPaint); redrawBitmapForSquareCorners(canvas); redrawBorderForSquareCorners(canvas); } else { canvas.drawRoundRect(mDrawableRect, radius, radius, mBitmapPaint); redrawBitmapForSquareCorners(canvas); } } else { canvas.drawRect(mDrawableRect, mBitmapPaint); if (mBorderWidth > 0) { canvas.drawRect(mBorderRect, mBorderPaint); } } } }
我们先看看第4行代码,这里用到BitmapShader,这里表明,圆角是通过BitmapShader实现的。接下来我们看到BitmapShader调用了setLocalMatrix方法,最后mBitmapPaint.setShader(bitmapShader);将bitmapShader设置给mBitmapPaint。
我们可以看到里面有一个判断就是判断是否要求剪裁为圆角,如果是那么就就对其四周都剪裁成圆角,如果不是的话就使用
redrawBitmapForSquareCorners(canvas);方法,将已经是圆角的恢复成直角,有兴趣可以看下源码,他是绘制一个正方形填充圆角的部分。
4、ScaleType
public RoundedDrawable setScaleType(ScaleType scaleType) { if (scaleType == null) { scaleType = ScaleType.FIT_CENTER; } if (mScaleType != scaleType) { mScaleType = scaleType; updateShaderMatrix(); } return this; }
这里就是对于ScaleType的支持,相关的操作在updateShaderMatrix()方法里面,就fitCenter等等,有兴趣可以进去看看
二、src属性
1、重写setImageDrawable,setImageBitmap和setImageResource@Override public void setImageDrawable(Drawable drawable) { mResource = 0; mDrawable = RoundedDrawable.fromDrawable(drawable); updateDrawableAttrs(); super.setImageDrawable(mDrawable); } @Override public void setImageBitmap(Bitmap bm) { mResource = 0; mDrawable = RoundedDrawable.fromBitmap(bm); updateDrawableAttrs(); super.setImageDrawable(mDrawable); } @Override public void setImageResource(@DrawableRes int resId) { if (mResource != resId) { mResource = resId; mDrawable = resolveResource(); updateDrawableAttrs bc68 (); super.setImageDrawable(mDrawable); } }
这两个方法都是获取Drawable之后进入UpdateDrawableAttrs(),那我们就进去看看里面是什么
private void updateDrawableAttrs() { updateAttrs(mDrawable); }继续进入updateAttrs
private void updateAttrs(Drawable drawable) { if (drawable == null) { return; } if (drawable instanceof RoundedDrawable) { ((RoundedDrawable) drawable) .setScaleType(mScaleType) .setBorderWidth(mBorderWidth) .setBorderColor(mBorderColor) .setOval(mIsOval) .setTileModeX(mTileModeX) .setTileModeY(mTileModeY); if (mCornerRadii != null) { ((RoundedDrawable) drawable).setCornerRadius( mCornerRadii[Corner.TOP_LEFT], mCornerRadii[Corner.TOP_RIGHT], mCornerRadii[Corner.BOTTOM_RIGHT], mCornerRadii[Corner.BOTTOM_LEFT]); } applyColorMod(); } else if (drawable instanceof LayerDrawable) { // loop through layers to and set drawable attrs LayerDrawable ld = ((LayerDrawable) drawable); for (int i = 0, layers = ld.getNumberOfLayers(); i < layers; i++) { updateAttrs(ld.getDrawable(i)); } } }
这部分代码跟第一点的fromDrawable()方法有点类似,判断如果是RoundedDrawable那我们就设置相关属性,如果不是那就把LayoutDrawable重新提取传去updateAttrs(),到这里的圆角属性就可以实现
三、background属性
@Override public void setBackground(Drawable background) { setBackgroundDrawable(background); } @Override @Deprecated public void setBackgroundDrawable(Drawable background) { mBackgroundDrawable = background; updateBackgroundDrawableAttrs(true); super.setBackgroundDrawable(mBackgroundDrawable); }
这两个函数都用到了setBackgroundDrawable(),那我们进去看看
private void updateBackgroundDrawableAttrs(boolean convert) { if (mMutateBackground) { if (convert) { mBackgroundDrawable = RoundedDrawable.fromDrawable(mBackgroundDrawable); } updateAttrs(mBackgroundDrawable); } }
这里面涉及到mMutateBackground属性,如果mMutateBackground为true,并且传入的参数也为true的话,会调用RoundedDrawable的方法把mBackgroundDrawable转化为圆角,最后通过之前讲的updateAttrs(Drawable)方法实现更新mBackgroundDrawable有关RoundedDrawable的属性。
这里就是设置背景是否设置为圆角,可以在xml里面设置也可以在代码里面设置
xml里面设置app:riv_mutate_background="true"或者再代码里面riv.mutateBackground(true)。
相关文章推荐
- Android 应用开发: APP Resource && ImageView
- Android:ImageView应用之图片浏览器
- Android应用系列:完美运行GIF格式的ImageView(附源码
- Android控件-圆形头像RoundedImageView
- Android中使用selector动态改变imageView或ImageButton的背景和在GridView中应用
- android应用开发之ImageView,SeekBar,TableHost,ProgressBar的使用
- Android中自定义圆形图片的CircleImageView和RoundedImageView基本使用效果
- android imageview图片居中技巧应用
- Android 应用开发笔记 - 图片视图(ImageView)
- SelectableRoundedImageView——Android图片圆角类库
- Android应用系列:完美运行GIF格式的ImageView(附源码)
- Android应用开发——Animation Drawable ImageView显示动画
- 二、Android应用的界面编程(七)ViewAnimator及其子类[ ViewSwitcher、ImageSwitcher、TextSwitcher、ViewFlipper ]
- android imageview图片居中技巧应用
- Android应用中在ImageView中显示SD卡上的图片
- android imageview图片居中技巧应用
- android 之开源控件roundedimageview
- Android深入浅出系列之实例应用—简单的手指拖动图片,图片滑来滑去显示应用Gallery和BaseAdapter以及ImageView的使用
- android开源项目---RoundedImageView制作圆角矩形,椭圆形以其圆形控件
- Android应用中在ImageView中显示SD卡上的图片