• [原创]android开源项目源码解析(一)----CircleImageView的源码解析


    CircleImageView的代码很简洁,因此先将此工程作为源码解析系列的第一篇文章.

    解析说明都在代码里了。

      1 /*
      2  * Copyright 2014 - 2015 Henning Dodenhof
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package de.hdodenhof.circleimageview;
     17 
     18 import android.content.Context;
     19 import android.content.res.TypedArray;
     20 import android.graphics.Bitmap;
     21 import android.graphics.BitmapShader;
     22 import android.graphics.Canvas;
     23 import android.graphics.Color;
     24 import android.graphics.ColorFilter;
     25 import android.graphics.Matrix;
     26 import android.graphics.Paint;
     27 import android.graphics.RectF;
     28 import android.graphics.Shader;
     29 import android.graphics.drawable.BitmapDrawable;
     30 import android.graphics.drawable.ColorDrawable;
     31 import android.graphics.drawable.Drawable;
     32 import android.net.Uri;
     33 import android.support.annotation.ColorInt;
     34 import android.support.annotation.ColorRes;
     35 import android.support.annotation.DrawableRes;
     36 import android.util.AttributeSet;
     37 import android.widget.ImageView;
     38 
     39 public class CircleImageView extends ImageView {
     40 
     41     private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;//这里限制了只要一种模式:CENTER_CROP
     42 
     43     private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
     44     private static final int COLORDRAWABLE_DIMENSION = 2;
     45 
     46     private static final int DEFAULT_BORDER_WIDTH = 0;
     47     private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
     48     private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT;
     49     private static final boolean DEFAULT_BORDER_OVERLAY = false;
     50 
     51     private final RectF mDrawableRect = new RectF();
     52     private final RectF mBorderRect = new RectF();
     53 
     54     //用来变换 mBitmapShader,从而影响 mBitmapPaint的显示效果
     55     private final Matrix mShaderMatrix = new Matrix();
     56     private final Paint mBitmapPaint = new Paint();
     57     private final Paint mBorderPaint = new Paint();
     58     private final Paint mFillPaint = new Paint();
     59 
     60     private int mBorderColor = DEFAULT_BORDER_COLOR;
     61     private int mBorderWidth = DEFAULT_BORDER_WIDTH;
     62     private int mFillColor = DEFAULT_FILL_COLOR;
     63 
     64     private Bitmap mBitmap;
     65     private BitmapShader mBitmapShader;
     66     private int mBitmapWidth;
     67     private int mBitmapHeight;
     68 
     69     private float mDrawableRadius;
     70     private float mBorderRadius;
     71 
     72     private ColorFilter mColorFilter;//滤镜效果,用在中间的bitmap上
     73 
     74     private boolean mReady;
     75     private boolean mSetupPending;
     76     private boolean mBorderOverlay;
     77 
     78     public CircleImageView(Context context) {
     79         super(context);
     80         init();
     81     }
     82 
     83     public CircleImageView(Context context, AttributeSet attrs) {
     84         this(context, attrs, 0);
     85     }
     86 
     87     //构造方法,获取属性文件中的定义,不必细说
     88     public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
     89         super(context, attrs, defStyle);
     90 
     91         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
     92 
     93         mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH);
     94         mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR);
     95         mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY);
     96         mFillColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_FILL_COLOR);
     97 
     98         a.recycle();
     99 
    100         init();
    101     }
    102 
    103     //初始化方法,主要是设置ScaleType,ScaleType被限定为center_crop模式
    104     private void init() {
    105         super.setScaleType(SCALE_TYPE);
    106         mReady = true;
    107 
    108         if (mSetupPending) {
    109             setup();
    110             mSetupPending = false;
    111         }
    112     }
    113 
    114     @Override
    115     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    116         super.onSizeChanged(w, h, oldw, oldh);
    117         setup();//实现了refresh功能,当属性改变时,调用此方法,完成刷新界面的功能
    118     }
    119 
    120     @Override
    121     protected void onDraw(Canvas canvas) {
    122         if (mBitmap == null) {
    123             return;
    124         }
    125 
    126         //底色 mFillColor --> 画笔 mFillPaint
    127         if (mFillColor != Color.TRANSPARENT) {
    128             canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mFillPaint);
    129         }
    130 
    131         canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mDrawableRadius, mBitmapPaint);
    132 
    133         //边色 mBorderColor --> 画笔 mBorderPaint
    134         if (mBorderWidth != 0) {
    135             canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, mBorderRadius, mBorderPaint);
    136         }
    137     }
    138 
    139     private void setup() {
    140         if (!mReady) {
    141             mSetupPending = true;
    142             return;
    143         }
    144 
    145         if (getWidth() == 0 && getHeight() == 0) {
    146             return;
    147         }
    148 
    149         if (mBitmap == null) {
    150             invalidate();
    151             return;
    152         }
    153 
    154         mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
    155 
    156         mBitmapPaint.setAntiAlias(true);
    157         mBitmapPaint.setShader(mBitmapShader);
    158 
    159         mBorderPaint.setStyle(Paint.Style.STROKE);
    160         mBorderPaint.setAntiAlias(true);
    161         mBorderPaint.setColor(mBorderColor);
    162         mBorderPaint.setStrokeWidth(mBorderWidth);
    163 
    164         mFillPaint.setStyle(Paint.Style.FILL);
    165         mFillPaint.setAntiAlias(true);
    166         mFillPaint.setColor(mFillColor);
    167 
    168         mBitmapHeight = mBitmap.getHeight();
    169         mBitmapWidth = mBitmap.getWidth();
    170 
    171         mBorderRect.set(0, 0, getWidth(), getHeight());
    172         mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f);
    173 
    174         mDrawableRect.set(mBorderRect);
    175         if (!mBorderOverlay) {
    176             mDrawableRect.inset(mBorderWidth, mBorderWidth);
    177         }
    178         mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f);
    179 
    180         updateShaderMatrix();
    181         invalidate();
    182     }
    183 
    184     private void updateShaderMatrix() {
    185         float scale;
    186         float dx = 0;
    187         float dy = 0;
    188 
    189         mShaderMatrix.set(null);
    190         //这里判断长宽比例,即图片的实际长宽比例与view的长宽比例
    191         //如果图片更"扁",则缩放的尺寸按照两者的高度来定
    192         //如果图片更"瘦",则缩放的尺寸按照两者的宽度来定
    193         if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
    194             scale = mDrawableRect.height() / (float) mBitmapHeight;
    195             dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
    196         } else {
    197             scale = mDrawableRect.width() / (float) mBitmapWidth;
    198             dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
    199         }
    200 
    201         mShaderMatrix.setScale(scale, scale);
    202         mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
    203         //可以简单的将BitmapShader类用来给Paint设置"填充颜色",这种说法其实并不准确,shader"填充"效果针对的范围是整个canvas,
    204         //而paint显示的是这个paint实时画出来的部分。
    205         //shader可以设置matrix,用来缩放或位移
    206         mBitmapShader.setLocalMatrix(mShaderMatrix);
    207     }
    208 
    209     @Override
    210     public ScaleType getScaleType() {
    211         return SCALE_TYPE;
    212     }
    213 
    214     @Override
    215     public void setScaleType(ScaleType scaleType) {
    216         if (scaleType != SCALE_TYPE) {
    217             throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
    218         }
    219     }
    220 
    221     @Override
    222     public void setAdjustViewBounds(boolean adjustViewBounds) {
    223         if (adjustViewBounds) {
    224             throw new IllegalArgumentException("adjustViewBounds not supported.");
    225         }
    226     }
    227 
    228     public int getBorderColor() {
    229         return mBorderColor;
    230     }
    231 
    232     public void setBorderColor(@ColorInt int borderColor) {
    233         if (borderColor == mBorderColor) {
    234             return;
    235         }
    236 
    237         mBorderColor = borderColor;
    238         mBorderPaint.setColor(mBorderColor);
    239         invalidate();
    240     }
    241 
    242     public void setBorderColorResource(@ColorRes int borderColorRes) {
    243         setBorderColor(getContext().getResources().getColor(borderColorRes));
    244     }
    245 
    246     public int getFillColor() {
    247         return mFillColor;
    248     }
    249 
    250     public void setFillColor(@ColorInt int fillColor) {
    251         if (fillColor == mFillColor) {
    252             return;
    253         }
    254 
    255         mFillColor = fillColor;
    256         mFillPaint.setColor(fillColor);
    257         invalidate();
    258     }
    259 
    260     public void setFillColorResource(@ColorRes int fillColorRes) {
    261         setFillColor(getContext().getResources().getColor(fillColorRes));
    262     }
    263 
    264     public int getBorderWidth() {
    265         return mBorderWidth;
    266     }
    267 
    268     public void setBorderWidth(int borderWidth) {
    269         if (borderWidth == mBorderWidth) {
    270             return;
    271         }
    272 
    273         mBorderWidth = borderWidth;
    274         setup();
    275     }
    276 
    277     public boolean isBorderOverlay() {
    278         return mBorderOverlay;
    279     }
    280 
    281     public void setBorderOverlay(boolean borderOverlay) {
    282         if (borderOverlay == mBorderOverlay) {
    283             return;
    284         }
    285 
    286         mBorderOverlay = borderOverlay;
    287         setup();
    288     }
    289 
    290     @Override
    291     public void setImageBitmap(Bitmap bm) {
    292         super.setImageBitmap(bm);
    293         mBitmap = bm;
    294         setup();
    295     }
    296 
    297     @Override
    298     public void setImageDrawable(Drawable drawable) {
    299         super.setImageDrawable(drawable);
    300         mBitmap = getBitmapFromDrawable(drawable);
    301         setup();
    302     }
    303 
    304     @Override
    305     public void setImageResource(@DrawableRes int resId) {
    306         super.setImageResource(resId);
    307         mBitmap = getBitmapFromDrawable(getDrawable());
    308         setup();
    309     }
    310 
    311     @Override
    312     public void setImageURI(Uri uri) {
    313         super.setImageURI(uri);
    314         mBitmap = uri != null ? getBitmapFromDrawable(getDrawable()) : null;
    315         setup();
    316     }
    317 
    318     @Override
    319     public void setColorFilter(ColorFilter cf) {
    320         if (cf == mColorFilter) {
    321             return;
    322         }
    323 
    324         mColorFilter = cf;
    325         mBitmapPaint.setColorFilter(mColorFilter);
    326         invalidate();
    327     }
    328 
    329     private Bitmap getBitmapFromDrawable(Drawable drawable) {
    330         if (drawable == null) {
    331             return null;
    332         }
    333 
    334         if (drawable instanceof BitmapDrawable) {
    335             return ((BitmapDrawable) drawable).getBitmap();
    336         }
    337 
    338         try {
    339             Bitmap bitmap;
    340 
    341             if (drawable instanceof ColorDrawable) {
    342                 //COLORDRAWABLE_DIMENSION == 2,如果是ColorDrawable类型的,就取2x2大小
    343                 bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
    344             } else {
    345                 bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
    346             }
    347 
    348             Canvas canvas = new Canvas(bitmap);
    349             drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    350             drawable.draw(canvas);
    351             return bitmap;
    352         } catch (Exception e) {
    353             e.printStackTrace();
    354             return null;
    355         }
    356     }
    357 
    358 
    359 
    360 }

     

  • 相关阅读:
    dwz 嵌套网页的搜索刷新问题
    dwz 解决remote验证唯一时缓存问题。
    dwz div 局部刷新
    Oracle 递归查询子节点和父节点 函数方法
    关于未能加载文件或程序集“System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”或它的某一个依赖项的解决办法
    CentOS7搭建vsftp服务器
    Linux下 cmatrix的安装和使用(黑客屏保)
    配置动态web服务(wsgi)
    centos7 搭建discuz 全
    Centos7 更换为阿里源
  • 原文地址:https://www.cnblogs.com/carbs/p/5280749.html
Copyright © 2020-2023  润新知