t简介
扩展ImageView。扩展ScaleType属性,和增加srcGravity属性,可设置src显示位置
扩展功能一:扩展ScaleType属性
ScaleType 增加 leftCrop 、 topCrop、rightCrop、bottomCrop
leftCrop : 垂直方向充满,均匀缩放,显示在控件左侧,超出控件部分进行裁剪,优先显示图片左侧内容
topCrop : 水平方向充满,均匀缩放,显示在控件顶部,超出控件部分进行裁剪,优先显示图片顶部内容
rightCrop : 垂直方向充满,均匀缩放,显示在控件右侧,超出控件部分进行裁剪,优先显示图片右侧内容
bottomCrop : 水平方向充满,均匀缩放,显示在控件底部,超出控件部分进行裁剪,优先显示图片底部内容
使用:xml app:scaleType="topCrop" code imageView.setScaleType(ExtendScaleImageView.ExtendScalType.TOP_CROP);
扩展功能二:增加 setGravity()方法,设置src 的显示位置(可以设置上下左右、水平和垂直居中,前提是scaleType设置为 matrix)
使用:xml app:srcGravity="center_horizontal|right" code imageView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
代码实现
package com.ttkx.extendscale;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.Map;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
/**
* 扩展ImageView
*
*/
public class ExtendScaleImageView extends AppCompatImageView {
private ExtendScalType mScalType;
private int mGravity = -1;
public ExtendScaleImageView(@NonNull Context context) {
this(context, null);
}
public ExtendScaleImageView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ExtendScaleImageView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ExtendScaleType);
final int index = a.getInt(R.styleable.ExtendScaleType_scaleType, -1);
if (index >= 0) {
ExtendScalType scalType = null;
for (Map.Entry<ExtendScalType, ScaleType> entry : ExtendScalType.map.entrySet()) {
if (entry.getKey().nativeInt == index) {
scalType = entry.getKey();
break;
}
}
if (scalType != null) {
setScaleType(scalType);
}
}
final int srcGravity = a.getInt(R.styleable.ExtendScaleType_srcGravity, -1);
setGravity(srcGravity);
a.recycle();
}
@IntDef(flag = true, value = {Gravity.LEFT, Gravity.RIGHT, Gravity.TOP, Gravity.BOTTOM, Gravity.CENTER, Gravity.CENTER_VERTICAL, Gravity.CENTER_HORIZONTAL})
@Retention(RetentionPolicy.SOURCE)
public @interface GravityMode {
}
/**
* 设置src 的显示位置(可以设置上下左右、水平和垂直居中,前提是scaleType设置为 matrix)
*
* @param gravity
*/
public void setGravity(@GravityMode int gravity) {
if (gravity != mGravity) {
invalidate();
}
mGravity = gravity;
}
public void setScaleType(ExtendScalType scaleType) {
mScalType = scaleType;
if (mScalType != null) {
ScaleType type = scaleType.getScaleType();
if (type != null) {
setScaleType(type);
}
}
}
public final void setScaleType(ScaleType scaleType) {
super.setScaleType(scaleType);
}
@Override
protected boolean setFrame(int l, int t, int r, int b) {
boolean change = super.setFrame(l, t, r, b);
Matrix matrix = getImageMatrix();
Drawable drawable = getDrawable();
final int dwidth = drawable.getIntrinsicWidth();
final int dheight = drawable.getIntrinsicHeight();
final int vwidth = getWidth() - getPaddingLeft() - getPaddingRight();
final int vheight = getHeight() - getPaddingTop() - getPaddingBottom();
if (hasExtendScaleType()) {
if (mScalType == ExtendScalType.LEFT_CROP) {
float scale = (float) vheight / (float) dheight;
matrix.setScale(scale, scale);
} else if (mScalType == ExtendScalType.TOP_CROP) {
float scale = (float) vwidth / (float) dwidth;
matrix.setScale(scale, scale);
} else if (mScalType == ExtendScalType.RIGHT_ROP) {
float scale = (float) vheight / (float) dheight;
matrix.setScale(scale, scale);
float dx = vwidth - dwidth * scale;
matrix.postTranslate(dx, 0);
} else if (mScalType == ExtendScalType.BOTTOM_CROP) {
float scale = (float) vwidth / (float) dwidth;
matrix.setScale(scale, scale);
float dy = vheight - dheight * scale;
matrix.postTranslate(0, dy);
}
setImageMatrix(matrix);
} else if (mGravity != -1 && ((mScalType == null && getScaleType() == ScaleType.MATRIX) || mScalType == ExtendScalType.MATRIX)) {//gravity有值,且scaleType=matrix
int dx = 0;
int dy = 0;
final int gravityV = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
if (gravityV != 0) {
if (gravityV == Gravity.CENTER_VERTICAL) {
dy = (vheight - dheight) / 2;
} else if (gravityV == Gravity.BOTTOM) {
dy = vheight - dheight;
} else { // (gravity == Gravity.TOP)
}
}
final int gravityH = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
if (gravityH != 0) {
if (gravityH == Gravity.RIGHT) {
dx = vwidth - dwidth;
} else if (gravityH == Gravity.CENTER_HORIZONTAL) { // (gravity == Gravity.CENTER_VERTICAL)
dx = (vwidth - dwidth) / 2;
} else {// (gravity == Gravity.LEFT)
}
}
matrix.postTranslate(dx, dy);
setImageMatrix(matrix);
}
return change;
}
/**
* 是否有扩展的scale属性
* @return
*/
private boolean hasExtendScaleType() {
return getDrawable() != null && mScalType != null && mScalType.isExtendScaleType();
}
public static enum ExtendScalType {
MATRIX(0),
FIT_XY(1),
FIT_START(2),
FIT_CENTER(3),
FIT_END(4),
CENTER(5),
CENTER_CROP(6),
CENTER_INSIDE(7),
LEFT_CROP(8),
TOP_CROP(9),
RIGHT_ROP(10),
BOTTOM_CROP(11);
static Map<ExtendScalType, ScaleType> map = new HashMap<>();
final int nativeInt;
static {
map.put(MATRIX, ScaleType.MATRIX);
map.put(FIT_XY, ScaleType.FIT_XY);
map.put(FIT_START, ScaleType.FIT_START);
map.put(FIT_CENTER, ScaleType.FIT_CENTER);
map.put(FIT_END, ScaleType.FIT_END);
map.put(CENTER, ScaleType.CENTER);
map.put(CENTER_CROP, ScaleType.CENTER_CROP);
map.put(CENTER_INSIDE, ScaleType.CENTER_INSIDE);
map.put(LEFT_CROP, ScaleType.MATRIX);
map.put(TOP_CROP, ScaleType.MATRIX);
map.put(RIGHT_ROP, ScaleType.MATRIX);
map.put(BOTTOM_CROP, ScaleType.MATRIX);
}
ExtendScalType(int ni) {
nativeInt = ni;
}
public ScaleType getScaleType() {
return map.get(this);
}
public boolean isExtendScaleType() {
return this.nativeInt >= 8;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ExtendScaleType">
<attr name="scaleType" format="enum">
<!-- 扩展scaleType - leftCrop
垂直方向充满,均匀缩放,显示在控件顶部,超出控件部分进行裁剪,优化显示图片左侧 -->
<enum name="leftCrop" value="8" />
<!--水平方向充满,均匀缩放,显示在控件顶部,超出控件部分进行裁剪,优先显示图片顶部-->
<enum name="topCrop" value="9" />
<!--垂直方向充满,均匀缩放,显示在控件顶部,超出控件部分进行裁剪,优先显示图片右侧-->
<enum name="rightCrop" value="10" />
<!--水平方向充满,均匀缩放,显示在控件顶部,超出控件部分进行裁剪,优先显示图片底部-->
<enum name="bottomCrop" value="11" />
<enum name="matrix" value="0" />
<enum name="fitXY" value="1" />
<enum name="fitStart" value="2" />
<enum name="fitCenter" value="3" />
<enum name="fitEnd" value="4" />
<enum name="center" value="5" />
<enum name="centerCrop" value="6" />
<enum name="centerInside" value="7" />
</attr>
<attr name="srcGravity" format="reference">
<flag name="top" value="48" />
<flag name="bottom" value="80" />
<flag name="left" value="3" />
<flag name="right" value="5" />
<flag name="center_vertical" value="16" />
<flag name="center_horizontal" value="1" />
<flag name="center" value="17" />
</attr>
</declare-styleable>
</resources>
示例:
扩展ScaleType属性示例
<com.ttkx.extendscale.ExtendScaleImageView
app:scaleType="leftCrop"
style="@style/crop_style" />
<com.ttkx.extendscale.ExtendScaleImageView
app:scaleType="rightCrop"
style="@style/crop_style" />
总结:图片均匀缩放,根据扩展的scaleType控制图片显示位置和裁剪区域, 是相对系统android:scaleType="centerCorp"的扩展。
srcGravity属性示例
xml布局 引用
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:showDividers="middle|beginning|end"
android:divider="@drawable/shape_divider"
tools:context=".MainActivity">
<LinearLayout style="@style/line_parent_style">
<com.ttkx.extendscale.ExtendScaleImageView
app:srcGravity="left"
style="@style/sv_style" />
<com.ttkx.extendscale.ExtendScaleImageView
app:srcGravity="center_horizontal"
style="@style/sv_style" />
<com.ttkx.extendscale.ExtendScaleImageView
app:srcGravity="right"
style="@style/sv_style" />
</LinearLayout>
<LinearLayout style="@style/line_parent_style">
<com.ttkx.extendscale.ExtendScaleImageView
app:srcGravity="top"
style="@style/sv_style" />
<com.ttkx.extendscale.ExtendScaleImageView
app:srcGravity="center_vertical"
style="@style/sv_style" />
<com.ttkx.extendscale.ExtendScaleImageView
app:srcGravity="bottom"
style="@style/sv_style" />
</LinearLayout>
<LinearLayout style="@style/line_parent_style">
<com.ttkx.extendscale.ExtendScaleImageView
app:srcGravity="center_vertical|bottom"
style="@style/sv_style" />
<com.ttkx.extendscale.ExtendScaleImageView
app:srcGravity="center_vertical|right"
style="@style/sv_style" />
<com.ttkx.extendscale.ExtendScaleImageView
app:srcGravity="center_horizontal|bottom"
style="@style/sv_style" />
<com.ttkx.extendscale.ExtendScaleImageView
app:srcGravity="right|bottom"
style="@style/sv_style" />
</LinearLayout>
</LinearLayout>
style引用(公共属性抽取)
<style name="sv_style">
<item name="android:layout_width">90dp</item>
<item name="android:layout_height">90dp</item>
<item name="android:background">#999</item>
<item name="android:src">@drawable/icon_scale_type_small</item>
<item name="scaleType">matrix</item>
</style>
<style name="crop_style">
<item name="android:layout_width">120dp</item>
<item name="android:layout_height">120dp</item>
<item name="android:background">#999</item>
<item name="android:src">@drawable/icon_scale_type_small</item>
</style>
<style name="line_parent_style">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:divider">@drawable/shape_divider</item>
<item name="android:orientation">horizontal</item>
<item name="android:showDividers">middle|beginning|end</item>
</style>
样式如下:
备注:图片尺寸是200px * 163px, 存放在xxhdpi目录, 控件尺寸为120dp*120dp。图片scaleType= matrix, 图片正常显示不会超出控件。如果示例图片尺寸较大,超出控件尺寸会被裁剪。