Skip to content

Commit

Permalink
Allow FlutterViewController to specify whether its FlutterView is opa…
Browse files Browse the repository at this point in the history
…que (flutter#6570)

* Allow FlutterViewController to specify whether its FlutterView is opaque
  • Loading branch information
dnfield authored Oct 23, 2018
1 parent 20c805c commit 427915e
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ FLUTTER_EXPORT
*/
@property(strong, nonatomic) UIView* splashScreenView;

/**
* Controls whether the created view will be opaque or not.
*
* Default is `YES`. Note that setting this to `NO` may negatively impact performance
* when using hardware acceleration, and toggling this will trigger a re-layout of the
* view.
*/
@property(nonatomic, getter=isViewOpaque) BOOL viewOpaque;

@end

#endif // FLUTTER_FLUTTERVIEWCONTROLLER_H_
15 changes: 15 additions & 0 deletions shell/platform/darwin/ios/framework/Source/FlutterView.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>

- (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
Expand Down
58 changes: 31 additions & 27 deletions shell/platform/darwin/ios/framework/Source/FlutterView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -24,28 +22,42 @@ @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 initWithDelegate"
reason:nil
userInfo:nil]);
}

- (instancetype)initWithFrame:(CGRect)frame {
@throw([NSException exceptionWithName:@"FlutterView must initWithDelegate"
reason:nil
userInfo:nil]);
}

- (instancetype)initWithCoder:(NSCoder*)aDecoder {
@throw([NSException exceptionWithName:@"FlutterView must initWithDelegate"
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;
Expand Down Expand Up @@ -84,16 +96,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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h"
#include "flutter/shell/platform/darwin/ios/platform_view_ios.h"

@interface FlutterViewController () <FlutterTextInputDelegate>
@interface FlutterViewController () <FlutterTextInputDelegate, FlutterScreenshotDelegate>
@property(nonatomic, readonly) NSMutableDictionary* pluginPublications;
@end

Expand Down Expand Up @@ -58,6 +58,7 @@ @implementation FlutterViewController {
blink::ViewportMetrics _viewportMetrics;
int64_t _nextTextureId;
BOOL _initialized;
BOOL _viewOpaque;

fml::scoped_nsobject<FlutterObservatoryPublisher> _publisher;
}
Expand All @@ -75,6 +76,8 @@ - (instancetype)initWithProject:(FlutterDartProject*)projectOrNil
else
_dartProject.reset([projectOrNil retain]);

self.viewOpaque = YES;

[self performCommonViewControllerInitialization];
}

Expand Down Expand Up @@ -146,7 +149,7 @@ - (BOOL)setupShell {
_threadHost.io_thread->GetTaskRunner() // io
);

_flutterView.reset([[FlutterView alloc] init]);
_flutterView.reset([[FlutterView alloc] initWithDelegate:self opaque:self.isViewOpaque]);

// Lambda captures by pointers to ObjC objects are fine here because the create call is
// synchronous.
Expand Down Expand Up @@ -180,6 +183,18 @@ - (BOOL)setupShell {
return true;
}

- (BOOL)isViewOpaque {
return _viewOpaque;
}

- (void)viewOpaque:(BOOL)value {
_viewOpaque = value;
if (_flutterView.get().layer.opaque != value) {
_flutterView.get().layer.opaque = value;
[_flutterView.get().layer setNeedsLayout];
}
}

- (void)setupChannels {
_localizationChannel.reset([[FlutterMethodChannel alloc]
initWithName:@"flutter/localization"
Expand Down Expand Up @@ -840,6 +855,14 @@ - (void)performAction:(FlutterTextInputAction)action withClient:(int)client {
arguments:@[ @(client), actionString ]];
}

#pragma mark - Screenshot Delegate

- (shell::Rasterizer::Screenshot)takeScreenshot:(shell::Rasterizer::ScreenshotType)type
asBase64Encoded:(BOOL)base64Encode {
FML_DCHECK(_shell) << "Cannot takeScreenshot without a shell";
return _shell->Screenshot(type, base64Encode);
}

#pragma mark - Orientation updates

- (void)onOrientationPreferencesUpdated:(NSNotification*)notification {
Expand Down

0 comments on commit 427915e

Please sign in to comment.