Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 49acbfb

Browse files
author
Chris Yang
authored
Make iOS PlatformView to reuse VisualEffectView when possible. (#37263)
* reuse visual effect view is possible * fix double retain * review * rewview * remove unnecessary check
1 parent fb7cde6 commit 49acbfb

File tree

4 files changed

+182
-72
lines changed

4 files changed

+182
-72
lines changed

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree {
450450
break;
451451
case kBackdropFilter: {
452452
// Only support DlBlurImageFilter for BackdropFilter.
453-
if (!(*iter)->GetFilterMutation().GetFilter().asBlur() || !canApplyBlurBackdrop) {
453+
if (!canApplyBlurBackdrop || !(*iter)->GetFilterMutation().GetFilter().asBlur()) {
454454
break;
455455
}
456456
CGRect filterRect =

shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm

Lines changed: 115 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -508,19 +508,19 @@ - (void)testAddBackdropFilters {
508508
[mockFlutterView setNeedsLayout];
509509
[mockFlutterView layoutIfNeeded];
510510

511-
NSUInteger numberOfExpectedVisualEffectView = 0;
511+
NSMutableArray* originalVisualEffectViews = [[[NSMutableArray alloc] init] autorelease];
512512
for (UIView* subview in childClippingView.subviews) {
513513
if (![subview isKindOfClass:[UIVisualEffectView class]]) {
514514
continue;
515515
}
516-
XCTAssertLessThan(numberOfExpectedVisualEffectView, 1u);
516+
XCTAssertLessThan(originalVisualEffectViews.count, 1u);
517517
if ([self validateOneVisualEffectView:subview
518518
expectedFrame:CGRectMake(0, 0, 10, 10)
519519
inputRadius:(CGFloat)5]) {
520-
numberOfExpectedVisualEffectView++;
520+
[originalVisualEffectViews addObject:subview];
521521
}
522522
}
523-
XCTAssertEqual(numberOfExpectedVisualEffectView, 1u);
523+
XCTAssertEqual(originalVisualEffectViews.count, 1u);
524524

525525
//
526526
// Simulate adding 1 backdrop filter (create a new mutators stack)
@@ -541,20 +541,28 @@ - (void)testAddBackdropFilters {
541541
[mockFlutterView setNeedsLayout];
542542
[mockFlutterView layoutIfNeeded];
543543

544-
numberOfExpectedVisualEffectView = 0;
544+
NSMutableArray* newVisualEffectViews = [[[NSMutableArray alloc] init] autorelease];
545545
for (UIView* subview in childClippingView.subviews) {
546546
if (![subview isKindOfClass:[UIVisualEffectView class]]) {
547547
continue;
548548
}
549-
XCTAssertLessThan(numberOfExpectedVisualEffectView, 2u);
549+
XCTAssertLessThan(newVisualEffectViews.count, 2u);
550550

551551
if ([self validateOneVisualEffectView:subview
552552
expectedFrame:CGRectMake(0, 0, 10, 10)
553553
inputRadius:(CGFloat)5]) {
554-
numberOfExpectedVisualEffectView++;
554+
[newVisualEffectViews addObject:subview];
555555
}
556556
}
557-
XCTAssertEqual(numberOfExpectedVisualEffectView, 2u);
557+
XCTAssertEqual(newVisualEffectViews.count, 2u);
558+
for (NSUInteger i = 0; i < originalVisualEffectViews.count; i++) {
559+
UIView* originalView = originalVisualEffectViews[i];
560+
UIView* newView = newVisualEffectViews[i];
561+
// Compare reference.
562+
XCTAssertEqual(originalView, newView);
563+
id mockOrignalView = OCMPartialMock(originalView);
564+
OCMReject([mockOrignalView removeFromSuperview]);
565+
}
558566
}
559567

560568
- (void)testRemoveBackdropFilters {
@@ -613,6 +621,19 @@ - (void)testRemoveBackdropFilters {
613621
[mockFlutterView setNeedsLayout];
614622
[mockFlutterView layoutIfNeeded];
615623

624+
NSMutableArray* originalVisualEffectViews = [[[NSMutableArray alloc] init] autorelease];
625+
for (UIView* subview in childClippingView.subviews) {
626+
if (![subview isKindOfClass:[UIVisualEffectView class]]) {
627+
continue;
628+
}
629+
XCTAssertLessThan(originalVisualEffectViews.count, 5u);
630+
if ([self validateOneVisualEffectView:subview
631+
expectedFrame:CGRectMake(0, 0, 10, 10)
632+
inputRadius:(CGFloat)5]) {
633+
[originalVisualEffectViews addObject:subview];
634+
}
635+
}
636+
616637
// Simulate removing 1 backdrop filter (create a new mutators stack)
617638
// Create embedded view params
618639
flutter::MutatorsStack stack2;
@@ -631,19 +652,29 @@ - (void)testRemoveBackdropFilters {
631652
[mockFlutterView setNeedsLayout];
632653
[mockFlutterView layoutIfNeeded];
633654

634-
NSUInteger numberOfExpectedVisualEffectView = 0;
655+
NSMutableArray* newVisualEffectViews = [[[NSMutableArray alloc] init] autorelease];
635656
for (UIView* subview in childClippingView.subviews) {
636657
if (![subview isKindOfClass:[UIVisualEffectView class]]) {
637658
continue;
638659
}
639-
XCTAssertLessThan(numberOfExpectedVisualEffectView, 4u);
660+
XCTAssertLessThan(newVisualEffectViews.count, 4u);
640661
if ([self validateOneVisualEffectView:subview
641662
expectedFrame:CGRectMake(0, 0, 10, 10)
642663
inputRadius:(CGFloat)5]) {
643-
numberOfExpectedVisualEffectView++;
664+
[newVisualEffectViews addObject:subview];
644665
}
645666
}
646-
XCTAssertEqual(numberOfExpectedVisualEffectView, 4u);
667+
XCTAssertEqual(newVisualEffectViews.count, 4u);
668+
669+
for (NSUInteger i = 0; i < newVisualEffectViews.count; i++) {
670+
UIView* newView = newVisualEffectViews[i];
671+
id mockNewView = OCMPartialMock(newView);
672+
UIView* originalView = originalVisualEffectViews[i];
673+
// Compare reference.
674+
XCTAssertEqual(originalView, newView);
675+
OCMReject([mockNewView removeFromSuperview]);
676+
[mockNewView stopMocking];
677+
}
647678

648679
// Simulate removing all backdrop filters (replace the mutators stack)
649680
// Update embedded view params, delete except screenScaleMatrix
@@ -660,7 +691,7 @@ - (void)testRemoveBackdropFilters {
660691
[mockFlutterView setNeedsLayout];
661692
[mockFlutterView layoutIfNeeded];
662693

663-
numberOfExpectedVisualEffectView = 0;
694+
NSUInteger numberOfExpectedVisualEffectView = 0u;
664695
for (UIView* subview in childClippingView.subviews) {
665696
if ([subview isKindOfClass:[UIVisualEffectView class]]) {
666697
numberOfExpectedVisualEffectView++;
@@ -725,6 +756,19 @@ - (void)testEditBackdropFilters {
725756
[mockFlutterView setNeedsLayout];
726757
[mockFlutterView layoutIfNeeded];
727758

759+
NSMutableArray* originalVisualEffectViews = [[[NSMutableArray alloc] init] autorelease];
760+
for (UIView* subview in childClippingView.subviews) {
761+
if (![subview isKindOfClass:[UIVisualEffectView class]]) {
762+
continue;
763+
}
764+
XCTAssertLessThan(originalVisualEffectViews.count, 5u);
765+
if ([self validateOneVisualEffectView:subview
766+
expectedFrame:CGRectMake(0, 0, 10, 10)
767+
inputRadius:(CGFloat)5]) {
768+
[originalVisualEffectViews addObject:subview];
769+
}
770+
}
771+
728772
// Simulate editing 1 backdrop filter in the middle of the stack (create a new mutators stack)
729773
// Create embedded view params
730774
flutter::MutatorsStack stack2;
@@ -751,23 +795,33 @@ - (void)testEditBackdropFilters {
751795
[mockFlutterView setNeedsLayout];
752796
[mockFlutterView layoutIfNeeded];
753797

754-
NSUInteger numberOfExpectedVisualEffectView = 0;
798+
NSMutableArray* newVisualEffectViews = [[[NSMutableArray alloc] init] autorelease];
755799
for (UIView* subview in childClippingView.subviews) {
756800
if (![subview isKindOfClass:[UIVisualEffectView class]]) {
757801
continue;
758802
}
759-
XCTAssertLessThan(numberOfExpectedVisualEffectView, 5u);
803+
XCTAssertLessThan(newVisualEffectViews.count, 5u);
760804
CGFloat expectInputRadius = 5;
761-
if (numberOfExpectedVisualEffectView == 3) {
805+
if (newVisualEffectViews.count == 3) {
762806
expectInputRadius = 2;
763807
}
764808
if ([self validateOneVisualEffectView:subview
765809
expectedFrame:CGRectMake(0, 0, 10, 10)
766810
inputRadius:(CGFloat)expectInputRadius]) {
767-
numberOfExpectedVisualEffectView++;
811+
[newVisualEffectViews addObject:subview];
768812
}
769813
}
770-
XCTAssertEqual(numberOfExpectedVisualEffectView, 5u);
814+
XCTAssertEqual(newVisualEffectViews.count, 5u);
815+
for (NSUInteger i = 0; i < newVisualEffectViews.count; i++) {
816+
UIView* newView = newVisualEffectViews[i];
817+
id mockNewView = OCMPartialMock(newView);
818+
UIView* originalView = originalVisualEffectViews[i];
819+
// Compare reference.
820+
XCTAssertEqual(originalView, newView);
821+
OCMReject([mockNewView removeFromSuperview]);
822+
[mockNewView stopMocking];
823+
}
824+
[newVisualEffectViews removeAllObjects];
771825

772826
// Simulate editing 1 backdrop filter in the beginning of the stack (replace the mutators stack)
773827
// Update embedded view params, delete except screenScaleMatrix
@@ -794,23 +848,31 @@ - (void)testEditBackdropFilters {
794848
[mockFlutterView setNeedsLayout];
795849
[mockFlutterView layoutIfNeeded];
796850

797-
numberOfExpectedVisualEffectView = 0;
798851
for (UIView* subview in childClippingView.subviews) {
799852
if (![subview isKindOfClass:[UIVisualEffectView class]]) {
800853
continue;
801854
}
802-
XCTAssertLessThan(numberOfExpectedVisualEffectView, 5u);
855+
XCTAssertLessThan(newVisualEffectViews.count, 5u);
803856
CGFloat expectInputRadius = 5;
804-
if (numberOfExpectedVisualEffectView == 0) {
857+
if (newVisualEffectViews.count == 0) {
805858
expectInputRadius = 2;
806859
}
807860
if ([self validateOneVisualEffectView:subview
808861
expectedFrame:CGRectMake(0, 0, 10, 10)
809862
inputRadius:(CGFloat)expectInputRadius]) {
810-
numberOfExpectedVisualEffectView++;
863+
[newVisualEffectViews addObject:subview];
811864
}
812865
}
813-
XCTAssertEqual(numberOfExpectedVisualEffectView, 5u);
866+
for (NSUInteger i = 0; i < newVisualEffectViews.count; i++) {
867+
UIView* newView = newVisualEffectViews[i];
868+
id mockNewView = OCMPartialMock(newView);
869+
UIView* originalView = originalVisualEffectViews[i];
870+
// Compare reference.
871+
XCTAssertEqual(originalView, newView);
872+
OCMReject([mockNewView removeFromSuperview]);
873+
[mockNewView stopMocking];
874+
}
875+
[newVisualEffectViews removeAllObjects];
814876

815877
// Simulate editing 1 backdrop filter in the end of the stack (replace the mutators stack)
816878
// Update embedded view params, delete except screenScaleMatrix
@@ -837,23 +899,33 @@ - (void)testEditBackdropFilters {
837899
[mockFlutterView setNeedsLayout];
838900
[mockFlutterView layoutIfNeeded];
839901

840-
numberOfExpectedVisualEffectView = 0;
841902
for (UIView* subview in childClippingView.subviews) {
842903
if (![subview isKindOfClass:[UIVisualEffectView class]]) {
843904
continue;
844905
}
845-
XCTAssertLessThan(numberOfExpectedVisualEffectView, 5u);
906+
XCTAssertLessThan(newVisualEffectViews.count, 5u);
846907
CGFloat expectInputRadius = 5;
847-
if (numberOfExpectedVisualEffectView == 4) {
908+
if (newVisualEffectViews.count == 4) {
848909
expectInputRadius = 2;
849910
}
850911
if ([self validateOneVisualEffectView:subview
851912
expectedFrame:CGRectMake(0, 0, 10, 10)
852913
inputRadius:(CGFloat)expectInputRadius]) {
853-
numberOfExpectedVisualEffectView++;
914+
[newVisualEffectViews addObject:subview];
854915
}
855916
}
856-
XCTAssertEqual(numberOfExpectedVisualEffectView, 5u);
917+
XCTAssertEqual(newVisualEffectViews.count, 5u);
918+
919+
for (NSUInteger i = 0; i < newVisualEffectViews.count; i++) {
920+
UIView* newView = newVisualEffectViews[i];
921+
id mockNewView = OCMPartialMock(newView);
922+
UIView* originalView = originalVisualEffectViews[i];
923+
// Compare reference.
924+
XCTAssertEqual(originalView, newView);
925+
OCMReject([mockNewView removeFromSuperview]);
926+
[mockNewView stopMocking];
927+
}
928+
[newVisualEffectViews removeAllObjects];
857929

858930
// Simulate editing all backdrop filters in the stack (replace the mutators stack)
859931
// Update embedded view params, delete except screenScaleMatrix
@@ -875,19 +947,29 @@ - (void)testEditBackdropFilters {
875947
[mockFlutterView setNeedsLayout];
876948
[mockFlutterView layoutIfNeeded];
877949

878-
numberOfExpectedVisualEffectView = 0;
879950
for (UIView* subview in childClippingView.subviews) {
880951
if (![subview isKindOfClass:[UIVisualEffectView class]]) {
881952
continue;
882953
}
883-
XCTAssertLessThan(numberOfExpectedVisualEffectView, 5u);
954+
XCTAssertLessThan(newVisualEffectViews.count, 5u);
884955
if ([self validateOneVisualEffectView:subview
885956
expectedFrame:CGRectMake(0, 0, 10, 10)
886-
inputRadius:(CGFloat)numberOfExpectedVisualEffectView]) {
887-
numberOfExpectedVisualEffectView++;
957+
inputRadius:(CGFloat)newVisualEffectViews.count]) {
958+
[newVisualEffectViews addObject:subview];
888959
}
889960
}
890-
XCTAssertEqual(numberOfExpectedVisualEffectView, 5u);
961+
XCTAssertEqual(newVisualEffectViews.count, 5u);
962+
963+
for (NSUInteger i = 0; i < newVisualEffectViews.count; i++) {
964+
UIView* newView = newVisualEffectViews[i];
965+
id mockNewView = OCMPartialMock(newView);
966+
UIView* originalView = originalVisualEffectViews[i];
967+
// Compare reference.
968+
XCTAssertEqual(originalView, newView);
969+
OCMReject([mockNewView removeFromSuperview]);
970+
[mockNewView stopMocking];
971+
}
972+
[newVisualEffectViews removeAllObjects];
891973
}
892974

893975
- (void)testApplyBackdropFilterNotDlBlurImageFilter {

shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292

9393
// Applies blur backdrop filters to the ChildClippingView with blur values from
9494
// filters.
95-
- (void)applyBlurBackdropFilters:(NSMutableArray<PlatformViewFilter*>*)filters;
95+
- (void)applyBlurBackdropFilters:(NSArray<PlatformViewFilter*>*)filters;
9696

9797
@end
9898

0 commit comments

Comments
 (0)