新功能:更易用的模糊、彩色滤镜等特效 。
新的 API 让你能更轻松地将常见图形效果应用到视图和渲染结构上。
-
使用 RenderEffect 将模糊、色彩滤镜等效果应用于 RenderNode 或 View。
-
使用新的 Window.setBackgroundBlurRadius() API 为窗口背景创建雾面玻璃效果,
-
使用 blurBehindRadius 来模糊窗口后面的所有内容。
咱们一个一个玩。
RenderEffect 实现效果 private void setBlur(){
View.setRenderEffect(RenderEffect.createBlurEffect(3, 3, Shader.TileMode.REPEAT));
...
}
使用特别简单,走你。
X 轴的模糊效果图咱再看看代码
private void setBlur(){
agb.iv1.setRenderEffect(RenderEffect.createBlurEffect(3, 0, Shader.TileMode.CLAMP));
agb.iv2.setRenderEffect(RenderEffect.createBlurEffect(8, 0, Shader.TileMode.REPEAT));
agb.iv3.setRenderEffect(RenderEffect.createBlurEffect(18, 0 ,Shader.TileMode.MIRROR));
agb.iv4.setRenderEffect(RenderEffect.createBlurEffect(36, 0,Shader.TileMode.DECAL));
}
RenderEffect.createBlurEffect()的四个参数:
-
radiusX 沿 X 轴的模糊半径
-
radiusY 沿 Y 轴的模糊半径
-
inputEffect 模糊一次(传入 RenderEffect)
-
edgeTreatment 用于如何模糊模糊内核边缘附近的内容
下面两种仅看效果图。就不做代码设置了。
Y 轴的模糊效果图 XY同时模糊效果图第四个参数对边缘模糊,效果图如下:
Shader.TileMode 提供了四个选项恕我没看出来。。
这里还有一堆方法等你玩。
源码 View.setRenderEffect()注意:注意如此完美的画面只能在 Android 12(SDK31)及以上的设备上使用,其他版本的设备使用会导致崩溃,谨记谨记。 效果有了,下面咱们一起看看源码。
public void setRenderEffect(@Nullable RenderEffect renderEffect) {
...
}
这个方法就是:renderEffect 应用于 View。 传入 null清除之前配置的RenderEffect 。这里咱们先看传入的 RenderEffect。
RenderEffect.createBlurEffect() public static RenderEffect createBlurEffect(
float radiusX,
float radiusY,
@NonNull RenderEffect inputEffect,
@NonNull TileMode edgeTreatment
) {
long nativeInputEffect = inputEffect != null ? inputEffect.mNativeRenderEffect : 0;
return new RenderEffect(
nativeCreateBlurEffect(
radiusX,
radiusY,
nativeInputEffect,
edgeTreatment.nativeInt
)
);
}
两个 createBlurEffect() 方法,分别为三参(模糊一次)和四参(模糊两次)。inputEffect 先进行了一次模糊。
看效果图:
模糊程度一样,但是实现方式不同:
private void setBlur() {
RenderEffect radiusXRenderEffect = RenderEffect.createBlurEffect(10, 0, Shader.TileMode.MIRROR);
RenderEffect radiusYRenderEffect = RenderEffect.createBlurEffect(0, 10, Shader.TileMode.MIRROR);
agb.iv1.setRenderEffect(RenderEffect.createBlurEffect(10, 10, Shader.TileMode.CLAMP));
agb.iv2.setRenderEffect(RenderEffect.createBlurEffect(10, 10, Shader.TileMode.REPEAT));
//自身radiusY 为 0 ,传入的radiusYRenderEffect设置的radiusY为10;
agb.iv3.setRenderEffect(RenderEffect.createBlurEffect(10, 0, radiusYRenderEffect, Shader.TileMode.MIRROR));
//自身radiusX 为 0 ,传入的radiusXRenderEffect设置的radiusX为10;
agb.iv4.setRenderEffect(RenderEffect.createBlurEffect(0, 10, radiusXRenderEffect, Shader.TileMode.DECAL));
}
这个方法返回一个 new RenderEffect(nativeCreateBlurEffect(...)。
那咱们去看看 nativeCreateBlurEffect()
nativeCreateBlurEffect()frameworks/base/libs/hwui/jni/RenderEffect.cpp
static const JNINativeMethod gRenderEffectMethods[] = {
...
{"nativeCreateBlurEffect", "(FFJI)J", (void*)createBlurEffect},
...
};
static jlong createBlurEffect(JNIEnv* env , jobject, jfloat radiusX,
jfloat radiusY, jlong inputFilterHandle, jint edgeTreatment) {
auto* inputImageFilter = reinterpret_cast(inputFilterHandle);
sk_sp blurFilter =
SkImageFilters::Blur(
Blur::convertRadiusToSigma(radiusX),
Blur::convertRadiusToSigma(radiusY),
static_cast(edgeTreatment),
sk_ref_sp(inputImageFilter),
nullptr);
return reinterpret_cast(blurFilter.release());
}
这里有两个函数来处理我们传过来的模糊的值,咱进去看看。
convertRadiusToSigma(convertSigmaToRadius)//该常数近似于在SkBlurMask::Blur()(1/sqrt(3)中,在软件路径的"高质量"模式下进行的缩放。
static const float BLUR_SIGMA_SCALE = 0.57735f;
float Blur::convertRadiusToSigma(float radius) {
return radius > 0 ? BLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
}
float Blur::convertSigmaToRadius(float sigma) {
return sigma > 0.5f ? (sigma - 0.5f) / BLUR_SIGMA_SCALE : 0.0f;
}
sk_ref_sp(inputImageFilter)
external/skia/include/core/SkRefCnt.h
template SkImageFilters::Blur()sk_sp sk_ref_sp(T* obj) { //sk_sp : return sk_sp (SkSafeRef(obj)); } //SkSafeRef:检查参数是否为非空,如果是,则调用 obj->ref() 并返回 obj。 template static inline T* SkSafeRef(T* obj) { if (obj) { obj->ref(); } return obj; }
#define SK_Scalar1 1.0f #define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12)) sk_spSkImageFilters::Blur( SkScalar sigmaX, SkScalar sigmaY, SkTileMode tileMode, sk_sp input, const CropRect& cropRect) { if (sigmaX < SK_ScalarNearlyZero && sigmaY < SK_ScalarNearlyZero && !cropRect) { return input; } return sk_sp ( new SkBlurImageFilter(sigmaX, sigmaY, tileMode, input, cropRect)); }
附上最后的倔强
constexpr sk_sp() : fPtr(nullptr) {}
constexpr sk_sp(std::nullptr_t) : fPtr(nullptr) {}
sk_sp(const sk_sp& that) : fPtr(SkSafeRef(that.get())) {}
template ::value>::type>
sk_sp(const sk_sp& that) : fPtr(SkSafeRef(that.get())) {}
sk_sp(sk_sp&& that) : fPtr(that.release()) {}
template ::value>::type>
sk_sp(sk_sp&& that) : fPtr(that.release()) {}
explicit sk_sp(T* obj) : fPtr(obj) {}
createBlurEffect() 得到 long 类型的 native 分配的的非零地址, 传入 new RenderEffect()
new RenderEffect()
private RenderEffect(long nativeRenderEffect) {
mNativeRenderEffect = nativeRenderEffect;
RenderEffectHolder.RENDER_EFFECT_REGISTRY.registerNativeAllocation(
this, mNativeRenderEffect);
}
继续
private static class RenderEffectHolder {
public static final NativeAllocationRegistry RENDER_EFFECT_REGISTRY =
NativeAllocationRegistry.createMalloced(
RenderEffect.class.getClassLoader(), nativeGetFinalizer());
}
NativeAllocationRegistry.createMalloced()
libcore/luni/src/main/java/libcore/util/NativeAllocationRegistry.java
@SystemApi(client = MODULE_LIBRARIES)
public static NativeAllocationRegistry createMalloced(
@NonNull ClassLoader classLoader, long freeFunction, long size) {
return new NativeAllocationRegistry(classLoader, freeFunction, size, true);
}
NativeAllocationRegistry()
libcore/luni/src/main/java/libcore/util/NativeAllocationRegistry.java
private NativeAllocationRegistry(ClassLoader classLoader, long freeFunction, long size,
boolean mallocAllocation) {
if (size < 0) {
throw new IllegalArgumentException("Invalid native allocation size: " + size);
}
this.classLoader = classLoader;
this.freeFunction = freeFunction;
this.size = mallocAllocation ? (size | IS_MALLOCED) : (size & ~IS_MALLOCED);
}
既然拿到 NativeAllocationRegistry 那就继续调用其 registerNativeAllocation() 方法。
registerNativeAllocation () @SystemApi(client = MODULE_LIBRARIES)
@libcore.api.IntraCoreApi
public @NonNull Runnable registerNativeAllocation(@NonNull Object referent, long nativePtr) {
//当 referent 或nativePtr 为空
...
CleanerThunk thunk;
CleanerRunner result;
try {
thunk = new CleanerThunk();
Cleaner cleaner = Cleaner.create(referent, thunk);
result = new CleanerRunner(cleaner);
registerNativeAllocation(this.size);
} catch (VirtualMachineError vme ) {
applyFreeFunction(freeFunction, nativePtr);
throw vme;
}
// Enable the cleaner only after we can no longer throw anything, including OOME.
thunk.setNativePtr(nativePtr);
// Ensure that cleaner doesn't get invoked before we enable it.
Reference.reachabilityFence(referent);
return result;
}
向 ART 注册新的 NativePtr 和关联的 Java 对象(也就是咱们设置的模糊类)。
返回的 Runnable 可用于在引用变得无法访问之前释放本机分配。如果运行时或使用 runnable 已经释放了本机分配,则 runnable 将不起作用。
RenderEffect 算是搞完了,咱们回到View.setRenderEffect()
View.setRenderEffect() public void setRenderEffect(@Nullable RenderEffect renderEffect) {
if (mRenderNode.setRenderEffect(renderEffect)) {
//视图属性更改(alpha、translationXY 等)的快速失效。
invalidateViewProperty(true, true);
}
}
这里有个 mRenderNode.setRenderEffect(renderEffect)。咱们近距离观望一番。
mRenderNode 的创建咱们先找找他是在什么地方创建的。
public View(Context context) {
...
//在View的构造方法中创建
mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this));
...
}
RenderNode.create()
public static RenderNode create(String name, @Nullable AnimationHost animationHost) {
return new RenderNode(name, animationHost);
}
private RenderNode(String name, AnimationHost animationHost) {
mNativeRenderNode = nCreate(name);
//注册 Native Allocation。
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode);
mAnimationHost = animationHost;
}
再往下感觉也看不到啥了 跟上面类似,看.cpp动态分配类的地址还是有点懵。让我缓缓~以后补充。



