ImageView
,比如,作为AbsListView
的一个Item的图标。Android
系统提供的ImageView
控件,通过设置属性:android:scaleType="fitXY"
就可以让图片铺满控件显示了。但是,在我们实际开发中,应该很少有人会去使用这个属性,因为这样做就让图片变形了。Android
系统没有给我提供这样方便的显示方式,那么,我们就去自定义一个ImageView
以满足我们的需求。ImageView
的代码:
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ImageView;
/**
* 自动让图片铺满控件显示的ImageView
* 何谓铺满控件:就是图片等比缩放。然后占满控件。多余的部分会加载在控件之外,也就是看不见的地方
*/
public class FullImage extends ImageView implements OnGlobalLayoutListener {
private static final boolean DEBUG = true;
private boolean once;
private Matrix matrix;
public FullImage(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FullImage(Context context) {
this(context, null);
}
public FullImage(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// init
init();
}
private void init() {
once = true;
matrix = new Matrix();
// setScaleType(ScaleType.MATRIX);// 这一步不加,以上全是白费
}
@Override
protected void onAttachedToWindow() {
// 注册 OnGlobalLayoutListener 的监听
ViewTreeObserver observer = getViewTreeObserver();
observer.addOnGlobalLayoutListener(this);
super.onAttachedToWindow();
}
@SuppressLint("NewApi")
@Override
protected void onDetachedFromWindow() {
// 反注册 OnGlobalLayoutListener 的监听
getViewTreeObserver().removeOnGlobalLayoutListener(this);
super.onDetachedFromWindow();
}
@Override
public void onGlobalLayout() {
if (once) {// 初始化操作,只需要搞一次即可。但是onGlobalLayout 会被多次调用
// 1. 获取当前控件,加载之后的(this)的宽高
int width = this.getWidth();
int height = this.getHeight();
// 2. 获取显示的图片,以及宽高
Drawable drawable = this.getDrawable();// 获取显示的图片
if (drawable == null)
return;
if (DEBUG) {
System.out.println("drawable: " + drawable);
}
int dw = drawable.getIntrinsicWidth();// 获取图片的宽高
int dh = drawable.getIntrinsicHeight();// 获取图片的宽高
if (DEBUG) {
System.out.println("dw: " + dw);
System.out.println("dh: " + dh);
System.out.println("width: " + width);
System.out.println("height: " + height);
}
// 5.不仅要缩放,还要让图片居中(图片中心点和控件中心点重合),也就是平移
int dx = Math.round(width * 1.0f / 2 - dw * 1.0f / 2);// x方向:向右移动:控件宽度的一半-图片宽度的一般
int dy = Math.round(height * 1.0f / 2 - dh * 1.0f / 2);// y方法:向下移动:控件高度的一半-图片高度的一半
// ___TODO:一定要先平移再进行缩放拆走
matrix.postTranslate(dx, dy);// 这个OK
// 3. 根据控件宽高一级图片宽高,设置缩放比例
float scale = 1.0f;
// case 1:图片宽度>控件宽度,高度<控件高度
if (dw > width && dh < height) {// 如果要铺满控件,且等比缩放,则
/** // scale = width * 1.0f / dw;// <1,缩小的*/
scale = height * 1.0f / dh;// >1,放大
System.out.println("case 1:" + scale);
}
// case 2:图片宽度<控件宽度,高度>控件高度
if (dw < width && dh > height) {// 如果要完全显示图片,且等比缩放,则
/** // scale = height / dh;// <1,缩小的*/
scale = width * 1.0f / dw;// >1,放大
System.out.println("case 2:" + scale);
}
// case 3:图片宽度>控件宽度,高度>控件高度
if (dw > width && dh > height) {// 如果要铺满控件,且等比缩放,则
scale = Math.max(width * 1.0f / dw, height* 1.0f / dh);// <1,缩小的
System.out.println("case 3:" + scale);
}
// case 4:图片宽度<控件宽度,高度<控件高度
if (dw < width && dh < height) {// 如果要完全显示图片,且等比缩放,则
scale = Math.max(width * 1.0f / dw, height* 1.0f / dh);// >1,放大的
System.out.println("case 4:" + scale);
}
// ------图片与控件的尺寸比较,只有以上4种情况
// 4. 根据缩放比例进行缩放
if (DEBUG) {
System.out.println("scale: " + scale);
}
matrix.postScale(scale, scale, width / 2, height / 2);
this.setImageMatrix(matrix);
once = false;
}
}
}
需要注意的是:我在代码中是先进行平移,再进行缩放的。是因为,如果先缩放,再平移,可能会出现一些不正常的效果。
使用该控件的代码:
<com.xxx.yyyy.FullImage
android:id="@+id/imageView1"
android:layout_width="240dp"
android:layout_height="240dp"
android:background="@android:color/darker_gray"
android:padding="2dp"
android:src="@drawable/install" />
只要,在我们需要使用这种显示方式的地方,将xnl中ImageView
改成我们自定义的FullImage
即可。不需要做任何的自定义属性,自定义命名空间等等。