Explorar el Código

Add iPhone X safe area handling to layout the toolbar correctly

Chaoshuai Lu hace 8 años
padre
commit
009aa5e3f9

+ 48 - 21
Classes/ExplorerInterface/FLEXExplorerViewController.m

@@ -96,22 +96,14 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
 	
     // Toolbar
     self.explorerToolbar = [[FLEXExplorerToolbar alloc] init];
-    CGSize toolbarSize = [self.explorerToolbar sizeThatFits:self.view.bounds.size];
-    // Start the toolbar off below any bars that may be at the top of the view.
 
+    // Start the toolbar off below any bars that may be at the top of the view.
     id toolbarOriginYDefault = [[NSUserDefaults standardUserDefaults] objectForKey:kFLEXToolbarTopMarginDefaultsKey];
+    CGFloat toolbarOriginY = toolbarOriginYDefault ? [toolbarOriginYDefault doubleValue] : 100;
 
-    CGFloat toolbarOriginY;
-
-    if (toolbarOriginYDefault) {
-        toolbarOriginY = [toolbarOriginYDefault doubleValue];
-    } else {
-        toolbarOriginY = 100;
-
-        [[NSUserDefaults standardUserDefaults] setDouble:toolbarOriginY forKey:kFLEXToolbarTopMarginDefaultsKey];
-    }
-
-    self.explorerToolbar.frame = CGRectMake(0.0, toolbarOriginY, toolbarSize.width, toolbarSize.height);
+    CGRect safeArea = [self viewSafeArea];
+    CGSize toolbarSize = [self.explorerToolbar sizeThatFits:CGSizeMake(CGRectGetWidth(self.view.bounds), CGRectGetHeight(safeArea))];
+    [self updateToolbarPositionWithUnconstrainedFrame:CGRectMake(CGRectGetMinX(safeArea), toolbarOriginY, toolbarSize.width, toolbarSize.height)];
     self.explorerToolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin;
     [self.view addSubview:self.explorerToolbar];
     [self setupToolbarActions];
@@ -476,16 +468,24 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
     CGRect newToolbarFrame = self.toolbarFrameBeforeDragging;
     newToolbarFrame.origin.y += translation.y;
     
-    CGFloat maxY = CGRectGetMaxY(self.view.bounds) - newToolbarFrame.size.height;
-    if (newToolbarFrame.origin.y < 0.0) {
-        newToolbarFrame.origin.y = 0.0;
-    } else if (newToolbarFrame.origin.y > maxY) {
-        newToolbarFrame.origin.y = maxY;
+    [self updateToolbarPositionWithUnconstrainedFrame:newToolbarFrame];
+}
+
+- (void)updateToolbarPositionWithUnconstrainedFrame:(CGRect)unconstrainedFrame
+{
+    CGRect safeArea = [self viewSafeArea];
+    // We only constrain the Y-axis because We want the toolbar to handle the X-axis safeArea layout by itself
+    CGFloat minY = CGRectGetMinY(safeArea);
+    CGFloat maxY = CGRectGetMaxY(safeArea) - unconstrainedFrame.size.height;
+    if (unconstrainedFrame.origin.y < minY) {
+        unconstrainedFrame.origin.y = minY;
+    } else if (unconstrainedFrame.origin.y > maxY) {
+        unconstrainedFrame.origin.y = maxY;
     }
-    
-    self.explorerToolbar.frame = newToolbarFrame;
 
-    [[NSUserDefaults standardUserDefaults] setDouble:newToolbarFrame.origin.y forKey:kFLEXToolbarTopMarginDefaultsKey];
+    self.explorerToolbar.frame = unconstrainedFrame;
+
+    [[NSUserDefaults standardUserDefaults] setDouble:unconstrainedFrame.origin.y forKey:kFLEXToolbarTopMarginDefaultsKey];
 }
 
 - (void)handleToolbarHintTapGesture:(UITapGestureRecognizer *)tapGR
@@ -690,6 +690,33 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
 }
 
 
+#pragma mark - Safe Area Handling
+
+- (CGRect)viewSafeArea
+{
+    CGRect safeArea = self.view.bounds;
+#if FLEX_AT_LEAST_IOS11_SDK
+    if (@available(iOS 11, *)) {
+        safeArea = UIEdgeInsetsInsetRect(self.view.bounds, self.view.safeAreaInsets);
+    }
+#endif
+    return safeArea;
+}
+
+#if FLEX_AT_LEAST_IOS11_SDK
+- (void)viewSafeAreaInsetsDidChange
+{
+  if (@available(iOS 11, *)) {
+    [super viewSafeAreaInsetsDidChange];
+  }
+
+  CGRect safeArea = [self viewSafeArea];
+  CGSize toolbarSize = [self.explorerToolbar sizeThatFits:CGSizeMake(CGRectGetWidth(self.view.bounds), CGRectGetHeight(safeArea))];
+  [self updateToolbarPositionWithUnconstrainedFrame:CGRectMake(CGRectGetMinX(self.explorerToolbar.frame), CGRectGetMinY(self.explorerToolbar.frame), toolbarSize.width, toolbarSize.height)];
+}
+#endif
+
+
 #pragma mark - Touch Handling
 
 - (BOOL)shouldReceiveTouchAtWindowPoint:(CGPoint)pointInWindowCoordinates

+ 1 - 1
Classes/Toolbar/FLEXExplorerToolbar.h

@@ -14,7 +14,7 @@
 
 /// The items to be displayed in the toolbar. Defaults to:
 /// globalsItem, hierarchyItem, selectItem, moveItem, closeItem
-@property (nonatomic, copy) NSArray<UIView*> *toolbarItems;
+@property (nonatomic, copy) NSArray<UIView *> *toolbarItems;
 
 /// Toolbar item for selecting views.
 /// Users of the toolbar can configure the enabled/selected state and event targets/actions.

+ 45 - 13
Classes/Toolbar/FLEXExplorerToolbar.m

@@ -23,9 +23,12 @@
 @property (nonatomic, strong) UIImageView *dragHandleImageView;
 
 @property (nonatomic, strong) UIView *selectedViewDescriptionContainer;
+@property (nonatomic, strong) UIView *selectedViewDescriptionSafeAreaContainer;
 @property (nonatomic, strong) UIView *selectedViewColorIndicator;
 @property (nonatomic, strong) UILabel *selectedViewDescriptionLabel;
 
+@property (nonatomic, strong,readwrite) UIView *backgroundView;
+
 @end
 
 @implementation FLEXExplorerToolbar
@@ -34,8 +37,12 @@
 {
     self = [super initWithFrame:frame];
     if (self) {
+        self.backgroundView = [[UIView alloc] init];
+        self.backgroundView.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.95];
+        [self addSubview:self.backgroundView];
+
         self.dragHandle = [[UIView alloc] init];
-        self.dragHandle.backgroundColor = [FLEXToolbarItem defaultBackgroundColor];
+        self.dragHandle.backgroundColor = [UIColor clearColor];
         [self addSubview:self.dragHandle];
         
         UIImage *dragHandle = [FLEXResources dragHandle];
@@ -56,22 +63,24 @@
         
         UIImage *closeIcon = [FLEXResources closeIcon];
         self.closeItem = [FLEXToolbarItem toolbarItemWithTitle:@"close" image:closeIcon];
-        
-        self.backgroundColor = [UIColor clearColor];
-        
+
         self.selectedViewDescriptionContainer = [[UIView alloc] init];
         self.selectedViewDescriptionContainer.backgroundColor = [UIColor colorWithWhite:0.9 alpha:0.95];
         self.selectedViewDescriptionContainer.hidden = YES;
         [self addSubview:self.selectedViewDescriptionContainer];
+
+        self.selectedViewDescriptionSafeAreaContainer = [[UIView alloc] init];
+        self.selectedViewDescriptionSafeAreaContainer.backgroundColor = [UIColor clearColor];
+        [self.selectedViewDescriptionContainer addSubview:self.selectedViewDescriptionSafeAreaContainer];
         
         self.selectedViewColorIndicator = [[UIView alloc] init];
         self.selectedViewColorIndicator.backgroundColor = [UIColor redColor];
-        [self.selectedViewDescriptionContainer addSubview:self.selectedViewColorIndicator];
+        [self.selectedViewDescriptionSafeAreaContainer addSubview:self.selectedViewColorIndicator];
         
         self.selectedViewDescriptionLabel = [[UILabel alloc] init];
         self.selectedViewDescriptionLabel.backgroundColor = [UIColor clearColor];
         self.selectedViewDescriptionLabel.font = [[self class] descriptionLabelFont];
-        [self.selectedViewDescriptionContainer addSubview:self.selectedViewDescriptionLabel];
+        [self.selectedViewDescriptionSafeAreaContainer addSubview:self.selectedViewDescriptionLabel];
         
         self.toolbarItems = @[_globalsItem, _hierarchyItem, _selectItem, _moveItem, _closeItem];
     }
@@ -82,10 +91,12 @@
 - (void)layoutSubviews
 {
     [super layoutSubviews];
-    
+
+
+    CGRect safeArea = [self safeArea];
     // Drag Handle
     const CGFloat kToolbarItemHeight = [[self class] toolbarItemHeight];
-    self.dragHandle.frame = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, [[self class] dragHandleWidth], kToolbarItemHeight);
+    self.dragHandle.frame = CGRectMake(CGRectGetMinX(safeArea), CGRectGetMinY(safeArea), [[self class] dragHandleWidth], kToolbarItemHeight);
     CGRect dragHandleImageFrame = self.dragHandleImageView.frame;
     dragHandleImageFrame.origin.x = FLEXFloor((self.dragHandle.frame.size.width - dragHandleImageFrame.size.width) / 2.0);
     dragHandleImageFrame.origin.y = FLEXFloor((self.dragHandle.frame.size.height - dragHandleImageFrame.size.height) / 2.0);
@@ -94,9 +105,9 @@
     
     // Toolbar Items
     CGFloat originX = CGRectGetMaxX(self.dragHandle.frame);
-    CGFloat originY = self.bounds.origin.y;
+    CGFloat originY = CGRectGetMinY(safeArea);
     CGFloat height = kToolbarItemHeight;
-    CGFloat width = FLEXFloor((CGRectGetMaxX(self.bounds) - originX) / [self.toolbarItems count]);
+    CGFloat width = FLEXFloor((CGRectGetWidth(safeArea) - CGRectGetWidth(self.dragHandle.frame)) / [self.toolbarItems count]);
     for (UIView *toolbarItem in self.toolbarItems) {
         toolbarItem.frame = CGRectMake(originX, originY, width, height);
         originX = CGRectGetMaxX(toolbarItem.frame);
@@ -105,8 +116,10 @@
     // Make sure the last toolbar item goes to the edge to account for any accumulated rounding effects.
     UIView *lastToolbarItem = [self.toolbarItems lastObject];
     CGRect lastToolbarItemFrame = lastToolbarItem.frame;
-    lastToolbarItemFrame.size.width = CGRectGetMaxX(self.bounds) - lastToolbarItemFrame.origin.x;
+    lastToolbarItemFrame.size.width = CGRectGetMaxX(safeArea) - lastToolbarItemFrame.origin.x;
     lastToolbarItem.frame = lastToolbarItemFrame;
+
+    self.backgroundView.frame = CGRectMake(0, 0, CGRectGetWidth(self.bounds), kToolbarItemHeight);
     
     const CGFloat kSelectedViewColorDiameter = [[self class] selectedViewColorIndicatorDiameter];
     const CGFloat kDescriptionLabelHeight = [[self class] descriptionLabelHeight];
@@ -115,11 +128,19 @@
     const CGFloat kDescriptionContainerHeight = [[self class] descriptionContainerHeight];
     
     CGRect descriptionContainerFrame = CGRectZero;
+    descriptionContainerFrame.size.width = CGRectGetWidth(self.bounds);
     descriptionContainerFrame.size.height = kDescriptionContainerHeight;
+    descriptionContainerFrame.origin.x = CGRectGetMinX(self.bounds);
     descriptionContainerFrame.origin.y = CGRectGetMaxY(self.bounds) - kDescriptionContainerHeight;
-    descriptionContainerFrame.size.width = self.bounds.size.width;
     self.selectedViewDescriptionContainer.frame = descriptionContainerFrame;
-    
+
+    CGRect descriptionSafeAreaContainerFrame = CGRectZero;
+    descriptionSafeAreaContainerFrame.size.width = CGRectGetWidth(safeArea);
+    descriptionSafeAreaContainerFrame.size.height = kDescriptionContainerHeight;
+    descriptionSafeAreaContainerFrame.origin.x = CGRectGetMinX(safeArea);
+    descriptionSafeAreaContainerFrame.origin.y = CGRectGetMinY(safeArea);
+    self.selectedViewDescriptionSafeAreaContainer.frame = descriptionSafeAreaContainerFrame;
+
     // Selected View Color
     CGRect selectedViewColorFrame = CGRectZero;
     selectedViewColorFrame.size.width = kSelectedViewColorDiameter;
@@ -237,4 +258,15 @@
     return CGSizeMake(size.width, height);
 }
 
+- (CGRect)safeArea
+{
+  CGRect safeArea = self.bounds;
+#if FLEX_AT_LEAST_IOS11_SDK
+  if (@available(iOS 11, *)) {
+    safeArea = UIEdgeInsetsInsetRect(self.bounds, self.safeAreaInsets);
+  }
+#endif
+  return safeArea;
+}
+
 @end

+ 0 - 2
Classes/Toolbar/FLEXToolbarItem.h

@@ -12,6 +12,4 @@
 
 + (instancetype)toolbarItemWithTitle:(NSString *)title image:(UIImage *)image;
 
-+ (UIColor *)defaultBackgroundColor;
-
 @end

+ 1 - 1
Classes/Toolbar/FLEXToolbarItem.m

@@ -70,7 +70,7 @@
 
 + (UIColor *)defaultBackgroundColor
 {
-    return [UIColor colorWithWhite:1.0 alpha:0.95];
+    return [UIColor clearColor];
 }
 
 + (CGFloat)topMargin

+ 4 - 0
Classes/Utility/FLEXUtility.h

@@ -6,12 +6,16 @@
 //  Copyright (c) 2014 Flipboard. All rights reserved.
 //
 
+#import <Availability.h>
+#import <AvailabilityInternal.h>
 #import <Foundation/Foundation.h>
 #import <UIKit/UIKit.h>
 #import <objc/runtime.h>
 
 #define FLEXFloor(x) (floor([[UIScreen mainScreen] scale] * (x)) / [[UIScreen mainScreen] scale])
 
+#define FLEX_AT_LEAST_IOS11_SDK defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
+
 @interface FLEXUtility : NSObject
 
 + (UIColor *)consistentRandomColorForObject:(id)object;