https://github.com/hdodenhof/CircleImageView
主要的类:
1. package de.hdodenhof.circleimageview;
2. import edu.njupt.zhb.main.R;
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.Matrix;
10. import android.graphics.Paint;
11. import android.graphics.RectF;
12. import android.graphics.Shader;
13. import android.graphics.drawable.BitmapDrawable;
14. import android.graphics.drawable.ColorDrawable;
15. import android.graphics.drawable.Drawable;
16. import android.util.AttributeSet;
17. import android.widget.ImageView;
18.
19. public class CircleImageView extends ImageView {
20.
21. private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
22.
23. private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
24. private static final int COLORDRAWABLE_DIMENSION = 1;
25.
26. private static final int DEFAULT_BORDER_WIDTH = 0;
27. private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
28.
29. private final RectF mDrawableRect = new RectF();
30. private final RectF mBorderRect = new RectF();
31.
32. private final Matrix mShaderMatrix = new Matrix();
33. private final Paint mBitmapPaint = new Paint();
34. private final Paint mBorderPaint = new Paint();
35.
36. private int mBorderColor = DEFAULT_BORDER_COLOR;
37. private int mBorderWidth = DEFAULT_BORDER_WIDTH;
38.
39. private Bitmap mBitmap;
40. private BitmapShader mBitmapShader;
41. private int mBitmapWidth;
42. private int mBitmapHeight;
43.
44. private float mDrawableRadius;
45. private float mBorderRadius;
46.
47. private boolean mReady;
48. private boolean mSetupPending;
49.
50. public CircleImageView(Context context) {
51. super(context);
52. }
53.
54. public CircleImageView(Context context, AttributeSet attrs) {
55. this(context, attrs, 0);
56. }
57.
58. public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
59. super(context, attrs, defStyle);
60. super.setScaleType(SCALE_TYPE);
61.
62. 0);
63.
64. mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, DEFAULT_BORDER_WIDTH);
65. mBorderColor = a.getColor(R.styleable.CircleImageView_border_color, DEFAULT_BORDER_COLOR);
66.
67. a.recycle();
68.
69. true;
70.
71. if (mSetupPending) {
72. setup();
73. false;
74. }
75. }
76.
77. @Override
78. public ScaleType getScaleType() {
79. return SCALE_TYPE;
80. }
81.
82. @Override
83. public void setScaleType(ScaleType scaleType) {
84. if (scaleType != SCALE_TYPE) {
85. throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
86. }
87. }
88.
89. @Override
90. protected void onDraw(Canvas canvas) {
91. if (getDrawable() == null) {
92. return;
93. }
94.
95. 2, getHeight() / 2, mDrawableRadius, mBitmapPaint);
96. 2, getHeight() / 2, mBorderRadius, mBorderPaint);
97. }
98.
99. @Override
100. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
101. super.onSizeChanged(w, h, oldw, oldh);
102. setup();
103. }
104.
105. public int getBorderColor() {
106. return mBorderColor;
107. }
108.
109. public void setBorderColor(int borderColor) {
110. if (borderColor == mBorderColor) {
111. return;
112. }
113.
114. mBorderColor = borderColor;
115. mBorderPaint.setColor(mBorderColor);
116. invalidate();
117. }
118.
119. public int getBorderWidth() {
120. return mBorderWidth;
121. }
122.
123. public void setBorderWidth(int borderWidth) {
124. if (borderWidth == mBorderWidth) {
125. return;
126. }
127.
128. mBorderWidth = borderWidth;
129. setup();
130. }
131.
132. @Override
133. public void setImageBitmap(Bitmap bm) {
134. super.setImageBitmap(bm);
135. mBitmap = bm;
136. setup();
137. }
138.
139. @Override
140. public void setImageDrawable(Drawable drawable) {
141. super.setImageDrawable(drawable);
142. mBitmap = getBitmapFromDrawable(drawable);
143. setup();
144. }
145.
146. @Override
147. public void setImageResource(int resId) {
148. super.setImageResource(resId);
149. mBitmap = getBitmapFromDrawable(getDrawable());
150. setup();
151. }
152.
153. private Bitmap getBitmapFromDrawable(Drawable drawable) {
154. if (drawable == null) {
155. return null;
156. }
157.
158. if (drawable instanceof BitmapDrawable) {
159. return ((BitmapDrawable) drawable).getBitmap();
160. }
161.
162. try {
163. Bitmap bitmap;
164.
165. if (drawable instanceof ColorDrawable) {
166. bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
167. else {
168. bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
169. }
170.
171. new Canvas(bitmap);
172. 0, 0, canvas.getWidth(), canvas.getHeight());
173. drawable.draw(canvas);
174. return bitmap;
175. catch (OutOfMemoryError e) {
176. return null;
177. }
178. }
179.
180. private void setup() {
181. if (!mReady) {
182. true;
183. return;
184. }
185.
186. if (mBitmap == null) {
187. return;
188. }
189.
190. new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
191.
192. true);
193. mBitmapPaint.setShader(mBitmapShader);
194.
195. mBorderPaint.setStyle(Paint.Style.STROKE);
196. true);
197. mBorderPaint.setColor(mBorderColor);
198. mBorderPaint.setStrokeWidth(mBorderWidth);
199.
200. mBitmapHeight = mBitmap.getHeight();
201. mBitmapWidth = mBitmap.getWidth();
202.
203. 0, 0, getWidth(), getHeight());
204. 2, (mBorderRect.width() - mBorderWidth) / 2);
205.
206. mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth);
207. 2, mDrawableRect.width() / 2);
208.
209. updateShaderMatrix();
210. invalidate();
211. }
212.
213. private void updateShaderMatrix() {
214. float scale;
215. float dx = 0;
216. float dy = 0;
217.
218. null);
219.
220. if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
221. float) mBitmapHeight;
222. 0.5f;
223. else {
224. float) mBitmapWidth;
225. 0.5f;
226. }
227.
228. mShaderMatrix.setScale(scale, scale);
229. int) (dx + 0.5f) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth);
230.
231. mBitmapShader.setLocalMatrix(mShaderMatrix);
232. }
233.
234. }
自定义的属性:res/values/attrs.xml
1. <?xml version="1.0" encoding="utf-8"?>
2. <resources>
3. <declare-styleable name="CircleImageView">
4. <attr name="border_width" format="dimension" />
5. <attr name="border_color" format="color" />
6. </declare-styleable>
7. </resources>
使用时的布局文件:
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. xmlns:app="http://schemas.android.com/apk/res-auto"
4. android:layout_width="match_parent"
5. android:layout_height="match_parent"
6. android:orientation="vertical" >
7. <RelativeLayout
8. android:layout_width="match_parent"
9. android:layout_height="0dp"
10. android:layout_weight="1"
11. android:padding="@dimen/base_padding"
12. android:background="@color/light">
13.
14. <de.hdodenhof.circleimageview.CircleImageView
15. android:layout_width="160dp"
16. android:layout_height="160dp"
17. android:layout_centerInParent="true"
18. android:src="@drawable/demo"
19. app:border_width="2dp"
20. app:border_color="@color/dark" />
21.
22. </RelativeLayout>
23.
24. <RelativeLayout
25. android:layout_width="match_parent"
26. android:layout_height="0dp"
27. android:layout_weight="1"
28. android:padding="@dimen/base_padding"
29. android:background="@color/dark">
30.
31. <de.hdodenhof.circleimageview.CircleImageView
32. android:layout_width="160dp"
33. android:layout_height="160dp"
34. android:layout_centerInParent="true"
35. android:src="@drawable/lena"
36. app:border_width="2dp"
37. app:border_color="@color/light" />
38.
39. </RelativeLayout>
40.
41. </LinearLayout>
效果:
注意:有些开发者可能也发现了,如果我们需要一个圆形的ImageButton的话,其实,我们没有必要自己写。如果ImageButton的图标是固定不变的,我们完全可以让设计师给我设计一个圆形的图片,然后直接设置再ImageButton上就可以了。但是,请注意,我们这里的圆形ImageView是自定义控件,也即是:无论你设置的图片是什么样的,显示出来的就是圆的。比如:易信中用户头像的设置,无论用户拍什么的照片,显示出来都是一个圆的。
拓展阅读:
还有一个更加强大的RoundedImageView,还支持圆角,椭圆等等。
https://github.com/vinc3m1/RoundedImageView