-
Notifications
You must be signed in to change notification settings - Fork 6k
Allow FlutterViewController to specify whether its FlutterView is opaque #6570
Changes from 5 commits
5b57c55
a8a67dd
e751691
04d80e0
5c4eab2
d0c3cf7
f62db18
4e585be
3b16036
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,10 +9,25 @@ | |
|
|
||
| #include <memory> | ||
|
|
||
| #include "flutter/fml/memory/weak_ptr.h" | ||
| #include "flutter/shell/common/shell.h" | ||
| #include "flutter/shell/platform/darwin/ios/ios_surface.h" | ||
|
|
||
| @protocol FlutterScreenshotDelegate <NSObject> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you plan to use this elsewhere? If not, it's clear to me what advantage this provides over passing the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, but it feels pretty wrong to pass a view controller directly into a view. I was looking at passing in just the shell, and after discussion with @chinmaygarde decided to go with a delegate - this way we avoid trying to share a pointer to the shell, and we avoid tying the ViewController implementation details to the View. |
||
|
|
||
| - (shell::Rasterizer::Screenshot)takeScreenshot:(shell::Rasterizer::ScreenshotType)type | ||
| asBase64Encoded:(BOOL)base64Encode; | ||
|
|
||
| @end | ||
|
|
||
| @interface FlutterView : UIView | ||
|
|
||
| - (instancetype)init NS_UNAVAILABLE; | ||
| - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; | ||
| - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; | ||
|
|
||
| - (instancetype)initWithDelegate:(id<FlutterScreenshotDelegate>)delegate | ||
| opaque:(BOOL)opaque NS_DESIGNATED_INITIALIZER; | ||
| - (std::unique_ptr<shell::IOSSurface>)createSurface; | ||
|
|
||
| @end | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,8 +12,6 @@ | |
| #include "flutter/fml/trace_event.h" | ||
| #include "flutter/shell/common/platform_view.h" | ||
| #include "flutter/shell/common/rasterizer.h" | ||
| #include "flutter/shell/common/shell.h" | ||
| #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h" | ||
| #include "flutter/shell/platform/darwin/ios/ios_surface_gl.h" | ||
| #include "flutter/shell/platform/darwin/ios/ios_surface_software.h" | ||
| #include "third_party/skia/include/utils/mac/SkCGUtils.h" | ||
|
|
@@ -24,28 +22,36 @@ @interface FlutterView () <UIInputViewAudioFeedback> | |
|
|
||
| @implementation FlutterView | ||
|
|
||
| - (FlutterViewController*)flutterViewController { | ||
| // Find the first view controller in the responder chain and see if it is a FlutterViewController. | ||
| for (UIResponder* responder = self.nextResponder; responder != nil; | ||
| responder = responder.nextResponder) { | ||
| if ([responder isKindOfClass:[UIViewController class]]) { | ||
| if ([responder isKindOfClass:[FlutterViewController class]]) { | ||
| return reinterpret_cast<FlutterViewController*>(responder); | ||
| } else { | ||
| // Should only happen if a non-FlutterViewController tries to somehow (via dynamic class | ||
| // resolution or reparenting) set a FlutterView as its view. | ||
| return nil; | ||
| } | ||
| } | ||
| id<FlutterScreenshotDelegate> _delegate; | ||
|
|
||
| - (instancetype)init { | ||
| @throw([NSException exceptionWithName:@"FlutterView must initWithShell" reason:nil userInfo:nil]); | ||
|
||
| } | ||
|
|
||
| - (instancetype)initWithFrame:(CGRect)frame { | ||
| @throw([NSException exceptionWithName:@"FlutterView must initWithShell" reason:nil userInfo:nil]); | ||
| } | ||
|
|
||
| - (instancetype)initWithCoder:(NSCoder*)aDecoder { | ||
| @throw([NSException exceptionWithName:@"FlutterView must initWithShell" reason:nil userInfo:nil]); | ||
| } | ||
|
|
||
| - (instancetype)initWithDelegate:(id<FlutterScreenshotDelegate>)delegate opaque:(BOOL)opaque { | ||
| FML_DCHECK(delegate) << "Delegate must not be nil."; | ||
| self = [super initWithFrame:CGRectNull]; | ||
|
|
||
| if (self) { | ||
| _delegate = delegate; | ||
| self.layer.opaque = opaque; | ||
| } | ||
| return nil; | ||
|
|
||
| return self; | ||
| } | ||
|
|
||
| - (void)layoutSubviews { | ||
| if ([self.layer isKindOfClass:[CAEAGLLayer class]]) { | ||
| CAEAGLLayer* layer = reinterpret_cast<CAEAGLLayer*>(self.layer); | ||
| layer.allowsGroupOpacity = YES; | ||
| layer.opaque = YES; | ||
| CGFloat screenScale = [UIScreen mainScreen].scale; | ||
| layer.contentsScale = screenScale; | ||
| layer.rasterizationScale = screenScale; | ||
|
|
@@ -84,16 +90,8 @@ - (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context { | |
| return; | ||
| } | ||
|
|
||
| FlutterViewController* controller = [self flutterViewController]; | ||
|
|
||
| if (controller == nil) { | ||
| return; | ||
| } | ||
|
|
||
| auto& shell = [controller shell]; | ||
|
|
||
| auto screenshot = shell.Screenshot(shell::Rasterizer::ScreenshotType::UncompressedImage, | ||
| false /* base64 encode */); | ||
| auto screenshot = [_delegate takeScreenshot:shell::Rasterizer::ScreenshotType::UncompressedImage | ||
| asBase64Encoded:NO]; | ||
|
|
||
| if (!screenshot.data || screenshot.data->isEmpty() || screenshot.frame_size.isEmpty()) { | ||
| return; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit:
@property(nonatomic, getter=isViewOpaque) BOOL viewOpaque;with the setter being inferred assetIsOpaqueis more idiomatic. See-[UIView opaque]for another such use.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done