简单分析
这个比较简单,就是重新计算ImageView的宽高。这里可以设置宽高的比例,所以多加一个自定义view中的自定义属性。假设我们的这个控件已经写好了,那么我们会在布局文件xml中使用,我们会在xml使用我们自定义的属性来设置宽高比,在控件的java类中拿到我们xml文件中自定义属性的值,然后计算出控件的宽高实例大小,最后保存。over。
实现步骤
- 自定义属性,目的是在xml中使用该属性赋值
- 得到在xml中自定义属性的值。
- 通过自定义属性的值计算出实际的宽高
- 保存计算得到的宽高
代码实现
- 1、自定义属性,在values下新建一个名为:attrs 的资源文件(鼠标右键→new→Values Resource file),然后写上你要自定的属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--自定义属性的名称,额。。可以理解成类名 如:class user-->
<declare-styleable name="ScaleImageView">
<!--name:属性名称 format:属性类型,额。。可以理解用类的成员 如:String name-->
<attr name="heightScale" format="float" />
<attr name="widthScale" format="float" />
</declare-styleable>
</resources>
2、3、4嗯。。。直接看代码
/**
* create by ts_xiaoa
* create Time 2018/9/11
* description: 可以设置宽高比的ImageView
*/
public class ScaleImageView extends android.support.v7.widget.AppCompatImageView {
//高度 : 宽度 = heightScale 0f不做处理
private float heightScale = 0f;
//宽度 : 高度 = widthScale 0f不做处理
private float widthScale = 0f;
public ScaleImageView(Context context) {
super(context);
}
/**
* 两个参数的构造方法,在xml文件中使用该控件的时候回调
* 我们这里就是在xml中直接使用所以把我们要做的初始化操作写这儿,比如初始化宽高比
*
* @param context
* @param attrs
*/
public ScaleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
//通过context.obtainStyledAttributes,得到TypedArray对象,该对象中可以得到自定义属性对应的值
//context.obtainStyledAttributes第一个参数就是构造方法的attrs
//context.obtainStyledAttributes第一个参数就是你自定义的属性
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScaleImageView);
//得到xml文件中widthScale属性的值
widthScale = typedArray.getFloat(R.styleable.ScaleImageView_widthScale, 0f);
//得到xml文件中heightScale属性的值
heightScale = typedArray.getFloat(R.styleable.ScaleImageView_heightScale, 0f);
//回收typedArray对象
typedArray.recycle();
}
public ScaleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScaleImageView);
widthScale = typedArray.getFloat(R.styleable.ScaleImageView_widthScale, 0f);
heightScale = typedArray.getFloat(R.styleable.ScaleImageView_heightScale, 0f);
typedArray.recycle();
}
/**
* 控件的测量方法,该方法实现控件的测量规则,
* 并在该方法最后调用setMeasuredDimension(widthSize,heightSize)
* 或者super.onMeasure(widthMeasureSpec, heightMeasureSpec)
* 保存最终测量的控件大小
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//默认测量规则
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//限制开发者只能设置了一个比例(比例得有一个实际大小的参照,比如宽200,heightScale=1f,那么高度的值=200)
if (widthScale != 0f && heightScale != 0f) {
throw new IllegalArgumentException("宽高比例只能设置一个");
}
//得到默认测量规则下测量到的宽度
int measuredWidth = getMeasuredWidth();
//得到默认测量规则下测量到的高度
int measuredHeight = getMeasuredHeight();
//判断开发者设置的宽高比
if (widthScale != 0) {
//开发者设置的是宽度比例,通过比例和实际高度计算实际的宽度
measuredWidth = (int) (widthScale * measuredHeight);
//保存测量的最终结果setMeasuredDimension()或者super.onMeasure()
setMeasuredDimension(measuredWidth, measuredHeight);
// super.onMeasure(MeasureSpec.makeMeasureSpec(measuredWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY));
} else if (heightScale != 0) {
//开发者设置的是高度比例,通过比例和实际宽度计算实际的高度
measuredHeight = (int) (heightScale * measuredWidth);
//保存测量的最终结果setMeasuredDimension()或者super.onMeasure()
setMeasuredDimension(measuredWidth, measuredHeight);
// super.onMeasure(MeasureSpec.makeMeasureSpec(measuredWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY));
}
}
}
注:三个参数的构造方法里面可以不用写我上面贴的代码,反正也没用到。。。。
使用
比如高占宽的一半:设置宽度=具体值,match_parent,wrap_centent都行,然后设置比例 heightScale=0.5就行了
<com.ts_xiaoa.tsxiaoa_lib.widget.ScaleImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff0000"
android:src="@mipmap/ic_launcher"
app:heightScale="0.5f" />
运行效果
懒得截图。。。。。