🔥 Android 12 高斯模糊
新功能:更易用的模糊、彩色濾鏡等特效 ,
新的 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 提供了四個選項恕我沒看出來,,
這里還有一堆方法等你玩,

注意:注意如此完美的畫面只能在 Android 12(SDK31)及以上的設備上使用,其他版本的設備使用會導致崩潰,謹記謹記, 效果有了,下面咱們一起看看原始碼,
💥 原始碼
🌀 View.setRenderEffect()
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<SkImageFilter*>(inputFilterHandle);
sk_sp<SkImageFilter> blurFilter =
SkImageFilters::Blur(
Blur::convertRadiusToSigma(radiusX),
Blur::convertRadiusToSigma(radiusY),
static_cast<SkTileMode>(edgeTreatment),
sk_ref_sp(inputImageFilter),
nullptr);
return reinterpret_cast<jlong>(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
/*
* 回傳包裝提供的 ptr 的 sk_sp 并對其呼叫 ref (如果不為空)
*/
template <typename T> sk_sp<T> sk_ref_sp(T* obj) {
//sk_sp<SkImageFilter> :
return sk_sp<T>(SkSafeRef(obj));
}
//SkSafeRef:檢查引數是否為非空,如果是,則呼叫 obj->ref() 并回傳 obj,
template <typename T> static inline T* SkSafeRef(T* obj) {
if (obj) {
obj->ref();
}
return obj;
}
🌀 SkImageFilters::Blur()
#define SK_Scalar1 1.0f
#define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12))
sk_sp<SkImageFilter> SkImageFilters::Blur(
SkScalar sigmaX, SkScalar sigmaY, SkTileMode tileMode, sk_sp<SkImageFilter> input,
const CropRect& cropRect) {
if (sigmaX < SK_ScalarNearlyZero && sigmaY < SK_ScalarNearlyZero && !cropRect) {
return input;
}
return sk_sp<SkImageFilter>(
new SkBlurImageFilter(sigmaX, sigmaY, tileMode, input, cropRect));
}
附上最后的倔強
constexpr sk_sp() : fPtr(nullptr) {}
constexpr sk_sp(std::nullptr_t) : fPtr(nullptr) {}
/**
* Shares the underlying object by calling ref(), so that both the argument and the newly
* created sk_sp both have a reference to it.
*/
sk_sp(const sk_sp<T>& that) : fPtr(SkSafeRef(that.get())) {}
template <typename U,
typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type>
sk_sp(const sk_sp<U>& that) : fPtr(SkSafeRef(that.get())) {}
/**
* Move the underlying object from the argument to the newly created sk_sp. Afterwards only
* the new sk_sp will have a reference to the object, and the argument will point to null.
* No call to ref() or unref() will be made.
*/
sk_sp(sk_sp<T>&& that) : fPtr(that.release()) {}
template <typename U,
typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type>
sk_sp(sk_sp<U>&& that) : fPtr(that.release()) {}
/**
* Adopt the bare pointer into the newly created sk_sp.
* No call to ref() or unref() will be made.
*/
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);
}
繼續
/**
* @param classLoader ClassLoader 類加載器,
* @param freeFunction 型別為 nativePtr 的本機函式的地址,用于釋放這種本機分配
* @return 由系統記憶體分配器分配的本機記憶體的 NativeAllocationRegistry,此版本更適合較小的物件(通常小于幾百 KB),
*/
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 /* probably OutOfMemoryError */) {
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()
/** @hide */
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動態分配類的地址還是有點懵,讓我緩緩~以后補充,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/330369.html
標籤:其他
