From 16d9df79fd3d273a798852ec80e4d4fa068dad4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nishan=20=28o=5E=E2=96=BD=5Eo=29?= Date: Sun, 15 Jun 2025 19:24:52 +0530 Subject: [PATCH 1/2] ios blur filter --- .../ComponentViews/View/RCTViewComponentView.mm | 13 +++++++++++++ .../rn-tester/js/examples/Filter/FilterExample.js | 1 - 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index c9c2520451aada..6898d37e77a294 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -986,6 +986,7 @@ - (void)invalidateLayer // filter [_filterLayer removeFromSuperlayer]; _filterLayer = nil; + self.layer.filters = nil; self.layer.opacity = (float)_props->opacity; if (!_props->filter.empty()) { float multiplicativeBrightness = 1; @@ -995,6 +996,18 @@ - (void)invalidateLayer multiplicativeBrightness *= std::get(primitive.parameters); } else if (primitive.type == FilterType::Opacity) { self.layer.opacity *= std::get(primitive.parameters); + } else if (primitive.type == FilterType::Blur) { + float amount = std::get(primitive.parameters); + if (amount > 0) { + Class clz = NSClassFromString(@"CAFilter"); + if (clz) { + id filter = [clz performSelector:@selector(filterWithName:) withObject:@"gaussianBlur"]; + if (filter) { + [filter setValue:[NSNumber numberWithFloat: amount] forKey:@"inputRadius"]; + self.layer.filters = @[filter]; + } + } + } } } } diff --git a/packages/rn-tester/js/examples/Filter/FilterExample.js b/packages/rn-tester/js/examples/Filter/FilterExample.js index 987e1da56232be..72a5550cff6d2f 100644 --- a/packages/rn-tester/js/examples/Filter/FilterExample.js +++ b/packages/rn-tester/js/examples/Filter/FilterExample.js @@ -189,7 +189,6 @@ exports.examples = [ title: 'Blur', description: 'blur(10)', name: 'blur', - platform: 'android', render(): React.Node { return ( Date: Fri, 27 Jun 2025 14:22:57 +0530 Subject: [PATCH 2/2] get filter class from UIVisualEffectView --- .../View/RCTViewComponentView.mm | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index 40cac4f26c4c56..3ac8bfc5dbf276 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -997,17 +997,35 @@ - (void)invalidateLayer } else if (primitive.type == FilterType::Opacity) { self.layer.opacity *= std::get(primitive.parameters); } else if (primitive.type == FilterType::Blur) { - float amount = std::get(primitive.parameters); - if (amount > 0) { - Class clz = NSClassFromString(@"CAFilter"); - if (clz) { - id filter = [clz performSelector:@selector(filterWithName:) withObject:@"gaussianBlur"]; - if (filter) { - [filter setValue:[NSNumber numberWithFloat: amount] forKey:@"inputRadius"]; - self.layer.filters = @[filter]; + NSMutableArray *layerFilters = [NSMutableArray new]; + static Class FilterClass = nil; + if (FilterClass == nil) { + UIVisualEffectView *tempBlurView = + [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleRegular]]; + // We search for the backdrop subview from UIVisualEffectView + // to access the underlying filter class + for (UIView *subview in tempBlurView.subviews) { + if ([NSStringFromClass(subview.class).lowercaseString containsString:@"backdrop"]) { + if (subview.layer.filters.firstObject) { + FilterClass = [subview.layer.filters.firstObject class]; + break; + } } } } + if (FilterClass) { + SEL selector = NSSelectorFromString(@"filterWithType:"); + if ([FilterClass respondsToSelector:selector]) { + IMP methodIMP = [FilterClass methodForSelector:selector]; + id (*filterWithType)(Class, SEL, NSString *) = (id (*)(Class, SEL, NSString *))methodIMP; + id gaussianBlurFilter = filterWithType(FilterClass, selector, @"gaussianBlur"); + + CGFloat blurRadius = std::get(primitive.parameters); + [gaussianBlurFilter setValue:@(blurRadius) forKey:@"inputRadius"]; + [layerFilters addObject:gaussianBlurFilter]; + } + } + self.layer.filters = layerFilters.count > 0 ? layerFilters : nil; } } } @@ -1016,10 +1034,10 @@ - (void)invalidateLayer [self shapeLayerToMatchView:_filterLayer borderMetrics:borderMetrics]; _filterLayer.compositingFilter = @"multiplyBlendMode"; _filterLayer.backgroundColor = [UIColor colorWithRed:multiplicativeBrightness - green:multiplicativeBrightness + green:multiplicativeBrightness blue:multiplicativeBrightness - alpha:self.layer.opacity] - .CGColor; + alpha:self.layer.opacity] + .CGColor; // So that this layer is always above any potential sublayers this view may // add _filterLayer.zPosition = CGFLOAT_MAX;