在项目开发中,我们经常需要用到圆形图片效果,典型案例是用户头像的显示。
如图所示。
下面我们使用开源控件CircleImageView来实现该效果。
CircleImageView项目下载地址:
https://github.com/hdodenhof/CircleImageView
(1).CircleImageView的使用
首先我们将CircleImageView添加到gradle。
- dependencies {
- compile 'de.hdodenhof:circleimageview:2.1.0'
- }
然后看一下自定义属性attrs:
- <declare-styleable name="CircleImageView">
- <attr name="civ_border_width" format="dimension" />
- <attr name="civ_border_color" format="color" />
- <attr name="civ_border_overlay" format="boolean" />
- <attr name="civ_fill_color" format="color" />
- </declare-styleable>
属性介绍:civ_border_width: 设置边框的宽度,默认为0,即无边框。
civ_border_color: 设置边框的颜色,默认为黑色。
civ_border_overlay:设置边框是否覆盖在图片上,默认为false,即边框在图片外圈。
civ_fill_color: 设置图片的底色,默认透明。
接下来在布局文件中引入CircleImageView。
- <de.hdodenhof.circleimageview.CircleImageView
- xmlns:circleimageview="http://schemas.android.com/apk/res-auto"
- android:id="@+id/imageview"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/profile"
- circleimageview:civ_border_color="@android:color/holo_red_light"
- circleimageview:civ_border_overlay="false"
- circleimageview:civ_border_width="2dp"
- circleimageview:civ_fill_color="@android:color/holo_blue_light"/>
注意:CircleImageView的默认ScaleType为CENTER_CROP,且只能为CENTER_CROP。
(2).CircleImageView的源码分析
通过查看源码可以看到,内部核心方法主要是对Paint、Canvas、BitmapShader、Matrix、RectF类的使用。
我们分析一下代码的执行流程。首先可以通过布局文件中的src属性或者java代码的setImageXxx()方法来设置图片,控件在构造方法中获取到自定义属性的参数值,然后会执行到setup()这个方法。
我们来分析一下setup()方法,该方法是CircleImageView的核心。
- private void setup() {
-
-
- if (!mReady) {
- mSetupPending = true;
- return;
- }
-
-
- if (getWidth() == 0 && getHeight() == 0) {
- return;
- }
-
-
- if (mBitmap == null) {
- invalidate();
- return;
- }
-
-
-
- mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
-
-
- mBitmapPaint.setAntiAlias(true);
-
- mBitmapPaint.setShader(mBitmapShader);
-
-
- mBorderPaint.setStyle(Paint.Style.STROKE);
-
- mBorderPaint.setAntiAlias(true);
-
- mBorderPaint.setColor(mBorderColor);
-
- mBorderPaint.setStrokeWidth(mBorderWidth);
-
-
- mFillPaint.setStyle(Paint.Style.FILL);
-
- mFillPaint.setAntiAlias(true);
-
- mFillPaint.setColor(mFillColor);
-
-
- mBitmapHeight = mBitmap.getHeight();
-
- mBitmapWidth = mBitmap.getWidth();
-
-
- mBorderRect.set(calculateBounds());
-
- mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f);
-
-
- mDrawableRect.set(mBorderRect);
-
- if (!mBorderOverlay && mBorderWidth > 0) {
- mDrawableRect.inset(mBorderWidth - 1.0f, mBorderWidth - 1.0f);
- }
-
- mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f);
-
-
- applyColorFilter();
- updateShaderMatrix();
- invalidate();
- }
上述setup()方法中使用到了updateShaderMatrix()方法。
- private void updateShaderMatrix() {
- float scale;
- float dx = 0;
- float dy = 0;
-
- mShaderMatrix.set(null);
-
-
-
-
- if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
- scale = mDrawableRect.height() / (float) mBitmapHeight;
- dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
- } else {
- scale = mDrawableRect.width() / (float) mBitmapWidth;
- dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
- }
-
-
- mShaderMatrix.setScale(scale, scale);
-
- mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
-
-
- mBitmapShader.setLocalMatrix(mShaderMatrix);
- }
该方法的作用是设置mBitmapShader变量的mShaderMatrix参数,对图片进行缩放setScale()和平移postTranslate(),使图片的显示区域缩放到与mDrawableRect一致,并通过平移确保显示图片的中心位置。
在setup()方法中最后一行执行invalidate(),触发View的onDraw()方法。
- @Override
- protected void onDraw(Canvas canvas) {
-
- if (mDisableCircularTransformation) {
- super.onDraw(canvas);
- return;
- }
-
-
- if (mBitmap == null) {
- return;
- }
-
-
- if (mFillColor != Color.TRANSPARENT) {
- canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mFillPaint);
- }
-
- canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mBitmapPaint);
-
- if (mBorderWidth > 0) {
- canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint);
- }
- }
在onDraw()方法中,使用setup()中设置好的各项参数,完成图片、底色和边框的绘制。到这里,流程执行结束。
转载地址:http://blog.csdn.net/ruancoder/article/details/51889505