简介
我们以往显示圆角图形,一般使用三方库或者自己写一个控件来实现。在constraintlayout 2.0出来后,提供了一个圆角控件ImageFilterView,使用更加方便,并且自带滤镜功能。可以显示本地图片(R.drawable引用)和网络图片(比如Glide加载)。
属性
- 圆角大小:取值0-size/2之间,超过就没什么意义了,默认0,就是方形;对于正方形来说,取值size/2就是圆形, 圆角是针对View的, 将View绘制成圆角.
- 圆角比例:取值0-1之间,超过1就没什么意义了,默认0就是方形,1是圆形图片。和app:round意思一样,只不过一个是具体的大小,一个是百分比。
- 缩放:放大或缩小图片大小,比如:2表示图片放大到原来的2倍,0.5表示图片缩小到原来的一半。View的大小不变,只是显示的图片缩放了。
- 旋转:旋转图片的角度,比如90,表示图片旋转90度。View的角度和大小是不变的。
- 交叉图:需要跟app:crossfade共同使用,app:crossfade取值0-1,默认0为交叉图完全透明,不展示。取值1交叉图完全展示,覆盖到src上。
- 饱和度:float型,默认1,取值0为灰阶样式,大于1的数值都是超饱和状态,色彩非常艳丽,有点辣眼睛。
- 亮度:float型,默认1,值越大亮度越高。
- 色温:float型,默认值1,小于1是冷色调,大于1是暖色调。
- 对比度:float型,默认1,取值0相当于图片变全黑,大于1都是高对比度状态。
- ,官方释义:定义alt图像是在原始图像的顶部淡入,还是与其交叉淡入。默认值为true。对于半透明对象设置为false。
使用
1. 滤镜
一般应用都是显示图片的原始效果图,鲜少使用滤镜功能,除非是相册等专门处理图片的应用。所以,这里不会专门介绍,只略提一笔。
//继承ImageView,本质上就是一个ImageView
public class ImageFilterView extends androidx.appcompat.widget.AppCompatImageView {
//这个类就是用来处理滤镜功能的
static class ImageMatrix {
float[] m = new float[4 * 5];
//颜色矩阵,用来实现各种滤镜效果
ColorMatrix mColorMatrix = new ColorMatrix();
ColorMatrix mTmpColorMatrix = new ColorMatrix();
float mBrightness = 1;
float mSaturation = 1;
float mContrast = 1;
float mWarmth = 1;
void updateMatrix(ImageView view) {
mColorMatrix.reset();
boolean filter = false;
//设置饱和度效果
if (mSaturation != 1.0f) {
saturation(mSaturation);
mColorMatrix.set(m);
filter = true;
}
//设置对比度效果
if (mContrast != 1.0f) {
mTmpColorMatrix.setScale(mContrast, mContrast, mContrast, 1);
mColorMatrix.postConcat(mTmpColorMatrix);
filter = true;
}
//设置色温效果
if (mWarmth != 1.0f) {
warmth(mWarmth);
mTmpColorMatrix.set(m);
mColorMatrix.postConcat(mTmpColorMatrix);
filter = true;
}
//设置亮度效果
if (mBrightness != 1.0f) {
brightness(mBrightness);
mTmpColorMatrix.set(m);
mColorMatrix.postConcat(mTmpColorMatrix);
filter = true;
}
//其实就是通过setColorFilter实现颜色的滤镜效果
if (filter) {
view.setColorFilter(new ColorMatrixColorFilter(mColorMatrix));
} else {
view.clearColorFilter();
}
}
}
2. 缩放
以下将图片的大小放大到原来的1.5倍。
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:src="@drawable/setting_item_privacy_manager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="@id/origin"
app:layout_constraintTop_toTopOf="parent"
app:imageZoom="1.5"/>
效果图:屏幕背景绿色, View背景橙色. 左边是原图,右边是放大1.5倍图。可以看到,View大小是不变的,还是原图大小。
3. 旋转
以下将图片的角度顺时针旋转60度。
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:src="@drawable/setting_item_privacy_manager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="@id/origin"
app:layout_constraintTop_toTopOf="parent"
app:imageRotate="60"/>
效果图:屏幕背景绿色, View背景橙色. 左边是原图,右边是旋转60度的效果。可以看到,图片旋转后,超出View外是不会显示的。
3. 圆角
将圆角设置为size/2, 圆角比例设置为1. 如下88px是view的size/2.
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:background="@android:color/holo_orange_dark"
android:src="@drawable/setting_item_privacy_manager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/filter2"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="@id/origin"
app:layout_constraintTop_toTopOf="parent"
app:round="88px" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/filter2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:background="@android:color/holo_orange_dark"
android:src="@drawable/setting_item_privacy_manager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="@id/filter"
app:layout_constraintTop_toTopOf="parent"
app:roundPercent="1" />
效果图:屏幕背景绿色, View背景橙色. 左边是原图,中间是设置圆角size/2的效果, 右边是设置圆角比例为1的效果。可以看到,设置圆角或圆角比例后, View的视图显示区域变化了.
那么问题来了, 圆角的大小怎么体现, 从View来看的话, 是哪里的值呢?
如图, 红色部分即圆角大小.
原理
1. 缩放和旋转
其实就是通过Matrix, 设置Translate和Rotate值实现的.
private void setMatrix() {
......
float panX = (Float.isNaN(mPanX)) ? 0 : mPanX;
float panY = (Float.isNaN(mPanY)) ? 0 : mPanY;
float zoom = (Float.isNaN(mZoom)) ? 1 : mZoom;
float rota = (Float.isNaN(mRotate)) ? 0 : mRotate;
Matrix imageMatrix = new Matrix();
imageMatrix.reset();
float iw = getDrawable().getIntrinsicWidth();
float ih = getDrawable().getIntrinsicHeight();
float sw = getWidth();
float sh = getHeight();
float scale = zoom * ((iw * sh < ih * sw) ? sw / iw : sh / ih);
imageMatrix.postScale(scale, scale);
float tx = 0.5f * (panX * (sw - scale * iw) + sw - (scale * iw));
float ty = 0.5f * (panY * (sh - scale * ih) + sh - (scale * ih));
imageMatrix.postTranslate(tx, ty);
imageMatrix.postRotate(rota, sw / 2, sh / 2);
setImageMatrix(imageMatrix);
setScaleType(ScaleType.MATRIX);
}
2. 圆角
通过Path和Outline实现, 圆角比例类似.
public void setRound(float round) {
......
if (mPath == null) {
mPath = new Path();
}
if (mRect == null) {
mRect = new RectF();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (mViewOutlineProvider == null) {
mViewOutlineProvider = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
int w = getWidth();
int h = getHeight();
outline.setRoundRect(0, 0, w, h, mRound);
}
};
setOutlineProvider(mViewOutlineProvider);
}
setClipToOutline(true);
}
int w = getWidth();
int h = getHeight();
mRect.set(0, 0, w, h);
mPath.reset();
mPath.addRoundRect(mRect, mRound, mRound, Path.Direction.CW);
if (change) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
invalidateOutline();
}
}
}
总结
ImageFilterView提供了非常方便的显示圆角的方式, 另外, ImageFilterButton也具有同样的功能, 实现也几乎一样, 唯一不同的是, ImageFilterView继承ImageView, 而ImageFilterButton继承ImageButton. 还有一个控件MotionButton, 继承Button, 也可以实现圆角功能, 但是没有滤镜功能.