├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── markdown-navigator.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── g7_user │ │ └── dingdingimage │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── g7_user │ │ │ └── dingdingimage │ │ │ ├── AvatarUtils.java │ │ │ ├── CircleImageView.java │ │ │ └── MainActivity.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ ├── four_pic.png │ │ ├── ic_launcher.png │ │ ├── three_pic.png │ │ └── two_pic.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── g7_user │ └── dingdingimage │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 36 | 37 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | Android API 21 Platform 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 高仿钉钉群头像 2 | ## 描述 3 | 由几张图片拼成一张圆形图片,有图有真相! 4 | 5 | ![](https://github.com/qiaoyhh/DingDingImage/blob/master/app/src/main/res/mipmap-xhdpi/two_pic.png) 6 | ![](https://github.com/qiaoyhh/DingDingImage/blob/master/app/src/main/res/mipmap-xhdpi/three_pic.png) 7 | ![](https://github.com/qiaoyhh/DingDingImage/blob/master/app/src/main/res/mipmap-xhdpi/four_pic.png) 8 | 9 | ## 特性 10 | * 代码只有一个类,确切来说 只有一个方法,传入头像集合,返回一个Bitmap对象,完美实现钉钉群头像效果! 11 | 12 | #### 如果大家有更好的实现方式,请不吝赐教! 13 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | buildToolsVersion "26.0.0" 6 | defaultConfig { 7 | applicationId "com.example.g7_user.dingdingimage" 8 | minSdkVersion 15 9 | targetSdkVersion 26 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:26.+' 28 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 29 | testCompile 'junit:junit:4.12' 30 | compile 'com.squareup.picasso:picasso:2.5.2' 31 | compile 'com.github.bumptech.glide:glide:3.7.0' 32 | } 33 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Android_Tools\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/g7_user/dingdingimage/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.example.g7_user.dingdingimage; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.example.g7_user.dingdingimage", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/g7_user/dingdingimage/AvatarUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.g7_user.dingdingimage; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Canvas; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Created by qyh on 2017/8/18. 10 | * Describe: 自动生成拼图工具类 11 | */ 12 | 13 | public class AvatarUtils { 14 | 15 | private static final int marginWhiteWidth = 6; // 中间白色宽度 16 | 17 | /** 18 | * 生成频道头像 19 | * @param bitmapList 20 | * @param width 21 | * @param height 22 | */ 23 | public static Bitmap getAvatar(List bitmapList, int width, int height){ 24 | final Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 25 | Canvas canvas = new Canvas(result); 26 | final int listSize = bitmapList.size(); 27 | switch (listSize) { 28 | case 1: 29 | Bitmap _p11 = Bitmap.createScaledBitmap(bitmapList.get(0), width, height, false); 30 | canvas.drawBitmap(_p11, 0, 0, null); 31 | break; 32 | case 2: 33 | // 比例缩放 34 | Bitmap _p21 = Bitmap.createScaledBitmap(bitmapList.get(0), width, height, false); 35 | Bitmap _p22 = Bitmap.createScaledBitmap(bitmapList.get(1), width, height, false); 36 | // 裁取中间部分(从x点裁取置顶距离) 37 | Bitmap __p21 = Bitmap.createBitmap(_p21, width / 4 + marginWhiteWidth / 2, 0, width / 2 - marginWhiteWidth / 2, height); // 中间留有1px白条 38 | Bitmap __p22 = Bitmap.createBitmap(_p22, width / 4 + marginWhiteWidth / 2, 0, width / 2 - marginWhiteWidth / 2, height); // 中间留有1px白条 39 | // 绘图 40 | canvas.drawBitmap(__p21, 0, 0, null); 41 | canvas.drawBitmap(__p22, width / 2 + marginWhiteWidth / 2, 0, null); 42 | break; 43 | case 3: 44 | // 1-图1 45 | Bitmap _p31 = Bitmap.createScaledBitmap(bitmapList.get(0), width, height, false); 46 | Bitmap __p31 = Bitmap.createBitmap(_p31, width / 4 + marginWhiteWidth / 2, 0, width / 2 - marginWhiteWidth / 2, height); 47 | // 2-图2,3 48 | Bitmap _p32 = Bitmap.createScaledBitmap(bitmapList.get(1), width / 2 - marginWhiteWidth / 2 , height / 2 - marginWhiteWidth / 2, false); 49 | Bitmap _p33 = Bitmap.createScaledBitmap(bitmapList.get(2), width / 2 - marginWhiteWidth / 2, height / 2 - marginWhiteWidth / 2, false); 50 | // 3-拼接 51 | canvas.drawBitmap(__p31, 0, 0, null); 52 | canvas.drawBitmap(_p32, width / 2 + marginWhiteWidth / 2, 0, null); 53 | canvas.drawBitmap(_p33, width / 2 + marginWhiteWidth / 2, height / 2 + marginWhiteWidth / 2, null); 54 | break; 55 | case 4: 56 | // 比例缩放 57 | Bitmap _p41 = Bitmap.createScaledBitmap(bitmapList.get(0), width / 2 - marginWhiteWidth / 2, height / 2 - marginWhiteWidth / 2, false); 58 | Bitmap _p42 = Bitmap.createScaledBitmap(bitmapList.get(1), width / 2 - marginWhiteWidth / 2, height / 2 - marginWhiteWidth / 2, false); 59 | Bitmap _p43 = Bitmap.createScaledBitmap(bitmapList.get(2), width / 2 - marginWhiteWidth / 2, height / 2 - marginWhiteWidth / 2, false); 60 | Bitmap _p44 = Bitmap.createScaledBitmap(bitmapList.get(3), width / 2 - marginWhiteWidth / 2, height / 2 - marginWhiteWidth / 2, false); 61 | // 多图拼接 62 | canvas.drawBitmap(_p41, 0, 0, null); 63 | canvas.drawBitmap(_p42, width / 2 + marginWhiteWidth / 2 , 0, null); 64 | canvas.drawBitmap(_p43, 0, height / 2 + marginWhiteWidth / 2, null); 65 | canvas.drawBitmap(_p44, width / 2 + marginWhiteWidth / 2, height / 2 + marginWhiteWidth / 2, null); 66 | break; 67 | default: 68 | break; 69 | } 70 | return result; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/g7_user/dingdingimage/CircleImageView.java: -------------------------------------------------------------------------------- 1 | package com.example.g7_user.dingdingimage; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapShader; 7 | import android.graphics.Canvas; 8 | import android.graphics.Color; 9 | import android.graphics.ColorFilter; 10 | import android.graphics.Matrix; 11 | import android.graphics.Paint; 12 | import android.graphics.RectF; 13 | import android.graphics.Shader; 14 | import android.graphics.drawable.BitmapDrawable; 15 | import android.graphics.drawable.ColorDrawable; 16 | import android.graphics.drawable.Drawable; 17 | import android.net.Uri; 18 | import android.support.annotation.ColorInt; 19 | import android.support.annotation.ColorRes; 20 | import android.support.annotation.DrawableRes; 21 | import android.util.AttributeSet; 22 | import android.widget.ImageView; 23 | 24 | import com.example.myapplication.R; 25 | 26 | 27 | /** 28 | * Created by qyh on 2016/4/22. 29 | * Describe:自定义圆形头像 30 | */ 31 | public class CircleImageView extends android.support.v7.widget.AppCompatImageView { 32 | 33 | private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; 34 | 35 | private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888; 36 | private static final int COLORDRAWABLE_DIMENSION = 2; 37 | 38 | private static final int DEFAULT_BORDER_WIDTH = 0; 39 | private static final int DEFAULT_BORDER_COLOR = Color.BLACK; 40 | private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT; 41 | private static final boolean DEFAULT_BORDER_OVERLAY = false; 42 | 43 | private final RectF mDrawableRect = new RectF(); 44 | private final RectF mBorderRect = new RectF(); 45 | 46 | private final Matrix mShaderMatrix = new Matrix(); 47 | private final Paint mBitmapPaint = new Paint(); 48 | private final Paint mBorderPaint = new Paint(); 49 | private final Paint mFillPaint = new Paint(); 50 | 51 | private int mBorderColor = DEFAULT_BORDER_COLOR; 52 | private int mBorderWidth = DEFAULT_BORDER_WIDTH; 53 | private int mFillColor = DEFAULT_FILL_COLOR; 54 | 55 | private Bitmap mBitmap; 56 | private BitmapShader mBitmapShader; 57 | private int mBitmapWidth; 58 | private int mBitmapHeight; 59 | 60 | private float mDrawableRadius; 61 | private float mBorderRadius; 62 | 63 | private ColorFilter mColorFilter; 64 | 65 | private boolean mReady; 66 | private boolean mSetupPending; 67 | private boolean mBorderOverlay; 68 | private boolean mDisableCircularTransformation; 69 | 70 | public CircleImageView(Context context) { 71 | super(context); 72 | 73 | init(); 74 | } 75 | 76 | public CircleImageView(Context context, AttributeSet attrs) { 77 | this(context, attrs, 0); 78 | } 79 | 80 | public CircleImageView(Context context, AttributeSet attrs, int defStyle) { 81 | super(context, attrs, defStyle); 82 | 83 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0); 84 | 85 | mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH); 86 | mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR); 87 | mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY); 88 | mFillColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_FILL_COLOR); 89 | 90 | a.recycle(); 91 | 92 | init(); 93 | } 94 | 95 | private void init() { 96 | super.setScaleType(SCALE_TYPE); 97 | mReady = true; 98 | if (mSetupPending) { 99 | setup(); 100 | mSetupPending = false; 101 | } 102 | } 103 | 104 | @Override 105 | public ScaleType getScaleType() { 106 | return SCALE_TYPE; 107 | } 108 | 109 | @Override 110 | public void setScaleType(ScaleType scaleType) { 111 | if (scaleType != SCALE_TYPE) { 112 | throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType)); 113 | } 114 | } 115 | 116 | @Override 117 | public void setAdjustViewBounds(boolean adjustViewBounds) { 118 | if (adjustViewBounds) { 119 | throw new IllegalArgumentException("adjustViewBounds not supported."); 120 | } 121 | } 122 | 123 | @Override 124 | protected void onDraw(Canvas canvas) { 125 | if (mDisableCircularTransformation) { 126 | super.onDraw(canvas); 127 | return; 128 | } 129 | 130 | if (mBitmap == null) { 131 | return; 132 | } 133 | 134 | if (mFillColor != Color.TRANSPARENT) { 135 | canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mFillPaint); 136 | } 137 | canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mBitmapPaint); 138 | if (mBorderWidth > 0) { 139 | canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint); 140 | } 141 | } 142 | 143 | @Override 144 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 145 | super.onSizeChanged(w, h, oldw, oldh); 146 | setup(); 147 | } 148 | 149 | @Override 150 | public void setPadding(int left, int top, int right, int bottom) { 151 | super.setPadding(left, top, right, bottom); 152 | setup(); 153 | } 154 | 155 | @Override 156 | public void setPaddingRelative(int start, int top, int end, int bottom) { 157 | super.setPaddingRelative(start, top, end, bottom); 158 | setup(); 159 | } 160 | 161 | public int getBorderColor() { 162 | return mBorderColor; 163 | } 164 | 165 | public void setBorderColor(@ColorInt int borderColor) { 166 | if (borderColor == mBorderColor) { 167 | return; 168 | } 169 | 170 | mBorderColor = borderColor; 171 | mBorderPaint.setColor(mBorderColor); 172 | invalidate(); 173 | } 174 | 175 | /** 176 | * @deprecated Use {@link #setBorderColor(int)} instead 177 | */ 178 | @Deprecated 179 | public void setBorderColorResource(@ColorRes int borderColorRes) { 180 | setBorderColor(getContext().getResources().getColor(borderColorRes)); 181 | } 182 | 183 | /** 184 | * Return the color drawn behind the circle-shaped drawable. 185 | * 186 | * @return The color drawn behind the drawable 187 | * 188 | * @deprecated Fill color support is going to be removed in the future 189 | */ 190 | @Deprecated 191 | public int getFillColor() { 192 | return mFillColor; 193 | } 194 | 195 | /** 196 | * Set a color to be drawn behind the circle-shaped drawable. Note that 197 | * this has no effect if the drawable is opaque or no drawable is set. 198 | * 199 | * @param fillColor The color to be drawn behind the drawable 200 | * 201 | * @deprecated Fill color support is going to be removed in the future 202 | */ 203 | @Deprecated 204 | public void setFillColor(@ColorInt int fillColor) { 205 | if (fillColor == mFillColor) { 206 | return; 207 | } 208 | 209 | mFillColor = fillColor; 210 | mFillPaint.setColor(fillColor); 211 | invalidate(); 212 | } 213 | 214 | /** 215 | * Set a color to be drawn behind the circle-shaped drawable. Note that 216 | * this has no effect if the drawable is opaque or no drawable is set. 217 | * 218 | * @param fillColorRes The color resource to be resolved to a color and 219 | * drawn behind the drawable 220 | * 221 | * @deprecated Fill color support is going to be removed in the future 222 | */ 223 | @Deprecated 224 | public void setFillColorResource(@ColorRes int fillColorRes) { 225 | setFillColor(getContext().getResources().getColor(fillColorRes)); 226 | } 227 | 228 | public int getBorderWidth() { 229 | return mBorderWidth; 230 | } 231 | 232 | public void setBorderWidth(int borderWidth) { 233 | if (borderWidth == mBorderWidth) { 234 | return; 235 | } 236 | 237 | mBorderWidth = borderWidth; 238 | setup(); 239 | } 240 | 241 | public boolean isBorderOverlay() { 242 | return mBorderOverlay; 243 | } 244 | 245 | public void setBorderOverlay(boolean borderOverlay) { 246 | if (borderOverlay == mBorderOverlay) { 247 | return; 248 | } 249 | 250 | mBorderOverlay = borderOverlay; 251 | setup(); 252 | } 253 | 254 | public boolean isDisableCircularTransformation() { 255 | return mDisableCircularTransformation; 256 | } 257 | 258 | public void setDisableCircularTransformation(boolean disableCircularTransformation) { 259 | if (mDisableCircularTransformation == disableCircularTransformation) { 260 | return; 261 | } 262 | 263 | mDisableCircularTransformation = disableCircularTransformation; 264 | initializeBitmap(); 265 | } 266 | 267 | @Override 268 | public void setImageBitmap(Bitmap bm) { 269 | super.setImageBitmap(bm); 270 | initializeBitmap(); 271 | } 272 | 273 | @Override 274 | public void setImageDrawable(Drawable drawable) { 275 | super.setImageDrawable(drawable); 276 | initializeBitmap(); 277 | } 278 | 279 | @Override 280 | public void setImageResource(@DrawableRes int resId) { 281 | super.setImageResource(resId); 282 | initializeBitmap(); 283 | } 284 | 285 | @Override 286 | public void setImageURI(Uri uri) { 287 | super.setImageURI(uri); 288 | initializeBitmap(); 289 | } 290 | 291 | @Override 292 | public void setColorFilter(ColorFilter cf) { 293 | if (cf == mColorFilter) { 294 | return; 295 | } 296 | 297 | mColorFilter = cf; 298 | applyColorFilter(); 299 | invalidate(); 300 | } 301 | 302 | @Override 303 | public ColorFilter getColorFilter() { 304 | return mColorFilter; 305 | } 306 | 307 | private void applyColorFilter() { 308 | if (mBitmapPaint != null) { 309 | mBitmapPaint.setColorFilter(mColorFilter); 310 | } 311 | } 312 | 313 | private Bitmap getBitmapFromDrawable(Drawable drawable) { 314 | if (drawable == null) { 315 | return null; 316 | } 317 | 318 | if (drawable instanceof BitmapDrawable) { 319 | return ((BitmapDrawable) drawable).getBitmap(); 320 | } 321 | 322 | try { 323 | Bitmap bitmap; 324 | 325 | if (drawable instanceof ColorDrawable) { 326 | bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG); 327 | } else { 328 | bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG); 329 | } 330 | 331 | Canvas canvas = new Canvas(bitmap); 332 | drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 333 | drawable.draw(canvas); 334 | return bitmap; 335 | } catch (Exception e) { 336 | e.printStackTrace(); 337 | return null; 338 | } 339 | } 340 | 341 | private void initializeBitmap() { 342 | if (mDisableCircularTransformation) { 343 | mBitmap = null; 344 | } else { 345 | mBitmap = getBitmapFromDrawable(getDrawable()); 346 | } 347 | setup(); 348 | } 349 | 350 | private void setup() { 351 | if (!mReady) { 352 | mSetupPending = true; 353 | return; 354 | } 355 | 356 | if (getWidth() == 0 && getHeight() == 0) { 357 | return; 358 | } 359 | 360 | if (mBitmap == null) { 361 | invalidate(); 362 | return; 363 | } 364 | 365 | mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 366 | 367 | mBitmapPaint.setAntiAlias(true); 368 | mBitmapPaint.setShader(mBitmapShader); 369 | 370 | mBorderPaint.setStyle(Paint.Style.STROKE); 371 | mBorderPaint.setAntiAlias(true); 372 | mBorderPaint.setColor(mBorderColor); 373 | mBorderPaint.setStrokeWidth(mBorderWidth); 374 | 375 | mFillPaint.setStyle(Paint.Style.FILL); 376 | mFillPaint.setAntiAlias(true); 377 | mFillPaint.setColor(mFillColor); 378 | 379 | mBitmapHeight = mBitmap.getHeight(); 380 | mBitmapWidth = mBitmap.getWidth(); 381 | 382 | mBorderRect.set(calculateBounds()); 383 | mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f); 384 | 385 | mDrawableRect.set(mBorderRect); 386 | if (!mBorderOverlay && mBorderWidth > 0) { 387 | mDrawableRect.inset(mBorderWidth - 1.0f, mBorderWidth - 1.0f); 388 | } 389 | mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f); 390 | 391 | applyColorFilter(); 392 | updateShaderMatrix(); 393 | invalidate(); 394 | } 395 | 396 | private RectF calculateBounds() { 397 | int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight(); 398 | int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom(); 399 | 400 | int sideLength = Math.min(availableWidth, availableHeight); 401 | 402 | float left = getPaddingLeft() + (availableWidth - sideLength) / 2f; 403 | float top = getPaddingTop() + (availableHeight - sideLength) / 2f; 404 | 405 | return new RectF(left, top, left + sideLength, top + sideLength); 406 | } 407 | 408 | private void updateShaderMatrix() { 409 | float scale; 410 | float dx = 0; 411 | float dy = 0; 412 | 413 | mShaderMatrix.set(null); 414 | 415 | if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) { 416 | scale = mDrawableRect.height() / (float) mBitmapHeight; 417 | dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f; 418 | } else { 419 | scale = mDrawableRect.width() / (float) mBitmapWidth; 420 | dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f; 421 | } 422 | 423 | mShaderMatrix.setScale(scale, scale); 424 | mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top); 425 | 426 | mBitmapShader.setLocalMatrix(mShaderMatrix); 427 | } 428 | 429 | } 430 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/g7_user/dingdingimage/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.g7_user.dingdingimage; 2 | 3 | import android.graphics.Bitmap; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | 8 | import com.example.myapplication.R; 9 | import com.squareup.picasso.Picasso; 10 | 11 | import java.io.IOException; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | /** 15 | * Created by qyh on 2017/8/18. 16 | * Describe: 17 | */ 18 | public class MainActivity extends AppCompatActivity { 19 | 20 | private CircleImageView iv_item_avatar; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_main); 26 | 27 | final ArrayList list = new ArrayList<>(); 28 | final ArrayList list2 = new ArrayList<>(); 29 | final ArrayList list3 = new ArrayList<>(); 30 | final ArrayList list4 = new ArrayList<>(); 31 | list.add("https://pic4.zhimg.com/02685b7a5f2d8cbf74e1fd1ae61d563b_xll.jpg"); 32 | 33 | list2.add("https://pic4.zhimg.com/02685b7a5f2d8cbf74e1fd1ae61d563b_xll.jpg"); 34 | list2.add("https://pic3.zhimg.com/33c6cf59163b3f17ca0c091a5c0d9272_xll.jpg"); 35 | 36 | list3.add("https://pic4.zhimg.com/02685b7a5f2d8cbf74e1fd1ae61d563b_xll.jpg"); 37 | list3.add("https://pic3.zhimg.com/33c6cf59163b3f17ca0c091a5c0d9272_xll.jpg"); 38 | list3.add("https://pic4.zhimg.com/52e093cbf96fd0d027136baf9b5cdcb3_xll.png"); 39 | 40 | list4.add("https://pic4.zhimg.com/02685b7a5f2d8cbf74e1fd1ae61d563b_xll.jpg"); 41 | list4.add("https://pic3.zhimg.com/33c6cf59163b3f17ca0c091a5c0d9272_xll.jpg"); 42 | list4.add("https://pic4.zhimg.com/52e093cbf96fd0d027136baf9b5cdcb3_xll.png"); 43 | list4.add("https://pic3.zhimg.com/0c149770fc2e16f4a89e6fc479272946_xll.jpg"); 44 | 45 | iv_item_avatar = (CircleImageView) findViewById(R.id.iv_item_avatar); 46 | getAvatarList(list); 47 | 48 | findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() { 49 | @Override 50 | public void onClick(View view) { 51 | getAvatarList(list2); 52 | } 53 | }); 54 | 55 | findViewById(R.id.btn3).setOnClickListener(new View.OnClickListener() { 56 | @Override 57 | public void onClick(View view) { 58 | getAvatarList(list3); 59 | } 60 | }); 61 | 62 | findViewById(R.id.btn4).setOnClickListener(new View.OnClickListener() { 63 | @Override 64 | public void onClick(View view) { 65 | getAvatarList(list4); 66 | } 67 | }); 68 | } 69 | 70 | private void getAvatarList(final List avatarList){ 71 | new Thread(new Runnable() { 72 | @Override 73 | public void run() { 74 | final List bitmapList = new ArrayList<>(); 75 | for (String decodePic : avatarList) { 76 | try { 77 | //生成bitmap对象 78 | Bitmap b = Picasso.with(MainActivity.this).load(decodePic).get(); 79 | if(b != null) { 80 | bitmapList.add(b); 81 | } 82 | } catch (IOException e) { 83 | e.printStackTrace(); 84 | } 85 | } 86 | final Bitmap result = AvatarUtils.getAvatar(bitmapList, 200, 200); 87 | MainActivity.this.runOnUiThread(new Runnable() { 88 | @Override 89 | public void run() { 90 | iv_item_avatar.setImageBitmap(bitmapList.size() == 1 ? bitmapList.get(0) : result); 91 | } 92 | }); 93 | } 94 | }).start(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 |