ImageView
是 Android 中用于显示图片的一个基本视图组件。它继承自 View
类,并且可以用来展示静态的图像资源,如位图、动画 GIF、矢量图形等。下面我们将结合源码分析 ImageView
的实现原理。
1. 构造方法与初始化
ImageView
的构造方法和其他 View
子类类似,通常接受一个 Context
对象,可能还包含 AttributeSet
和 int
类型的默认样式。在构造方法中,ImageView
初始化其样式属性,设置默认的缩放类型等。
1public ImageView(Context context) {
2 super(context);
3 init(null, null, 0, 0);
4}
5
6public ImageView(Context context, AttributeSet attrs) {
7 this(context, attrs, 0);
8}
9
10public ImageView(Context context, AttributeSet attrs, int defStyleAttr) {
11 super(context, attrs, defStyleAttr);
12 init(attrs, null, defStyleAttr, 0);
13}
14
15private void init(AttributeSet attrs, AttributeSet defStyleAttrRes, int defStyleAttr, int defStyleRes) {
16 // 初始化ImageView的属性
17}
2. 设置图片资源
ImageView
支持多种方式来设置图片资源,包括从资源文件、Drawable 对象、位图或者 URL 加载图片。
从资源文件加载:
Java深色版本
1public void setImageResource(@DrawableRes int resId) { 2 Drawable drawable = null; 3 if (resId != 0) { 4 drawable = ContextCompat.getDrawable(getContext(), resId); 5 } 6 setImageDrawable(drawable); 7}
从 Drawable 设置:
1public void setImageDrawable(Drawable drawable) { 2 if (mImage != drawable) { 3 if (drawable != null) { 4 drawable.setCallback(this); 5 if (mAdjustViewBounds && drawable instanceof ScaleDrawable) { 6 ((ScaleDrawable) drawable).setTargetDensity(getDrawableDensity()); 7 } 8 } 9 if (mImage != null) { 10 mImage.setCallback(null); 11 } 12 mImage = drawable; 13 requestLayout(); 14 invalidate(); 15 } 16}
从位图设置:
1public void setImageBitmap(Bitmap bm) { 2 setImageDrawable(new BitmapDrawable(getResources(), bm)); 3}
3. 缩放类型
ImageView
支持不同的缩放类型,如 FIT_XY
, CENTER_CROP
, CENTER_INSIDE
等。缩放类型决定了如何在 ImageView
内部调整图片的大小和位置。
1public void setScaleType(ScaleType scaleType) {
2 if (scaleType != mScaleType) {
3 mScaleType = scaleType;
4 requestLayout(); // 请求重新布局
5 }
6}
4. 测量与布局
ImageView
需要根据图片的大小和缩放类型来确定自己的大小。onMeasure
方法负责计算 ImageView
的大小。
1@Override
2protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
3 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
4 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
5 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
6
7 final int width = getMeasuredWidth();
8 final int height = getMeasuredHeight();
9 if (getDrawable() != null) {
10 // 根据图片和缩放类型计算ImageView的大小
11 final int childWidth = getDrawable().getIntrinsicWidth();
12 final int childHeight = getDrawable().getIntrinsicHeight();
13 final ScaleType scaleType = getScaleType();
14
15 int widthSize = width;
16 int heightSize = height;
17
18 if (scaleType == ScaleType.FIT_XY) {
19 // FIT_XY 会拉伸图片以填满ImageView
20 widthSize = childWidth;
21 heightSize = childHeight;
22 } else if (scaleType == ScaleType.CENTER_CROP) {
23 // CENTER_CROP 会裁剪图片以适应ImageView
24 // 计算新的宽度和高度
25 }
26
27 setMeasuredDimension(resolveSizeAndState(widthSize, widthMeasureSpec, 0),
28 resolveSizeAndState(heightSize, heightMeasureSpec, 0));
29 }
30}
5. 绘制图片
在 onDraw
方法中,ImageView
负责将图片绘制到屏幕上。
1@Override
2protected void onDraw(Canvas canvas) {
3 super.onDraw(canvas);
4 final Drawable drawable = getDrawable();
5 if (drawable != null) {
6 final Rect bounds = drawable.getBounds();
7 if (!bounds.isEmpty()) {
8 final int saveCount = canvas.save();
9 final int w = bounds.width();
10 final int h = bounds.height();
11 final int tw = getWidth() - getPaddingLeft() - getPaddingRight();
12 final int th = getHeight() - getPaddingTop() - getPaddingBottom();
13 final int scaleType = getScaleType();
14 if (scaleType != null) {
15 switch (scaleType) {
16 case FIT_XY:
17 canvas.scale((float) tw / w, (float) th / h);
18 break;
19 case CENTER_CROP:
20 // ... 其他缩放类型 ...
21 default:
22 break;
23 }
24 }
25 canvas.translate(getPaddingLeft(), getPaddingTop());
26 drawable.draw(canvas);
27 canvas.restoreToCount(saveCount);
28 }
29 }
30}
总结
ImageView
的实现涉及到构造、图片资源的加载和管理、缩放类型的设置、测量与布局逻辑以及图片的绘制。这些功能的实现确保了 ImageView
可以灵活地显示不同类型的图片资源,并能适应不同的布局需求。