123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- //
- // FLEXKeyboardToolbar.m
- // FLEX
- //
- // Created by Tanner on 6/11/17.
- // Copyright © 2017 Tanner Bennett. All rights reserved.
- //
- #import "FLEXKeyboardToolbar.h"
- #import "FLEXUtility.h"
- #define kToolbarHeight 44
- #define kButtonSpacing 6
- #define kScrollViewHorizontalMargins 3
- @interface FLEXKeyboardToolbar ()
- /// The fake top border to replicate the toolbar.
- @property (nonatomic) CALayer *topBorder;
- @property (nonatomic) UIView *toolbarView;
- @property (nonatomic) UIScrollView *scrollView;
- @property (nonatomic) UIVisualEffectView *blurView;
- /// YES if appearance is set to `default`
- @property (nonatomic, readonly) BOOL useSystemAppearance;
- /// YES if the current trait collection is set to dark mode and \c useSystemAppearance is YES
- @property (nonatomic, readonly) BOOL usingDarkMode;
- @end
- @implementation FLEXKeyboardToolbar
- + (instancetype)toolbarWithButtons:(NSArray *)buttons {
- return [[self alloc] initWithButtons:buttons];
- }
- - (id)initWithButtons:(NSArray *)buttons {
- self = [super initWithFrame:CGRectMake(0, 0, self.window.rootViewController.view.bounds.size.width, kToolbarHeight)];
- if (self) {
- _buttons = [buttons copy];
-
- self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-
- if (@available(iOS 13, *)) {
- self.appearance = UIKeyboardTypeDefault;
- } else {
- self.appearance = UIKeyboardAppearanceLight;
- }
- }
-
- return self;
- }
- - (void)setAppearance:(UIKeyboardAppearance)appearance {
- _appearance = appearance;
-
- // Remove toolbar if it exits because it will be recreated below
- if (self.toolbarView) {
- [self.toolbarView removeFromSuperview];
- }
-
- [self addSubview:self.inputAccessoryView];
- }
- - (void)layoutSubviews {
- [super layoutSubviews];
-
- // Layout top border
- CGRect frame = _toolbarView.bounds;
- frame.size.height = 0.5;
- _topBorder.frame = frame;
-
- // Scroll view //
-
- frame = CGRectMake(0, 0, self.bounds.size.width, kToolbarHeight);
- CGSize contentSize = self.scrollView.contentSize;
- CGFloat scrollViewWidth = frame.size.width;
-
- // If our content size is smaller than the scroll view,
- // we want to right-align all the content
- if (contentSize.width < scrollViewWidth) {
- // Compute the content size to scroll view size difference
- UIEdgeInsets insets = self.scrollView.contentInset;
- CGFloat margin = insets.left + insets.right;
- CGFloat difference = scrollViewWidth - contentSize.width - margin;
- // Update the content size to be the full width of the scroll view
- contentSize.width += difference;
- self.scrollView.contentSize = contentSize;
-
- // Offset every button by the difference above
- // so that every button appears right-aligned
- for (UIView *button in self.scrollView.subviews) {
- CGRect f = button.frame;
- f.origin.x += difference;
- button.frame = f;
- }
- }
- }
- - (UIView *)inputAccessoryView {
- _topBorder = [CALayer new];
- _topBorder.frame = CGRectMake(0.0, 0.0, self.bounds.size.width, 0.5);
- [self makeScrollView];
-
- UIColor *borderColor = nil, *backgroundColor = nil;
- UIColor *lightColor = [UIColor colorWithHue:216.0/360.0 saturation:0.05 brightness:0.85 alpha:1];
- UIColor *darkColor = [UIColor colorWithHue:220.0/360.0 saturation:0.07 brightness:0.16 alpha:1];
-
- switch (_appearance) {
- case UIKeyboardAppearanceDefault:
- #if FLEX_AT_LEAST_IOS13_SDK
- if (@available(iOS 13, *)) {
- #if !TARGET_OS_TV
- borderColor = UIColor.systemBackgroundColor;
- #endif
- if (self.usingDarkMode) {
- // style = UIBlurEffectStyleSystemThickMaterial;
- backgroundColor = darkColor;
- } else {
- // style = UIBlurEffectStyleSystemUltraThinMaterialLight;
- backgroundColor = lightColor;
- }
- break;
- }
- #endif
- case UIKeyboardAppearanceLight: {
- borderColor = UIColor.clearColor;
- backgroundColor = lightColor;
- break;
- }
- case UIKeyboardAppearanceDark: {
- borderColor = [UIColor colorWithWhite:0.100 alpha:1.000];
- backgroundColor = darkColor;
- break;
- }
- }
-
- self.toolbarView = [UIView new];
- [self.toolbarView addSubview:self.scrollView];
- [self.toolbarView.layer addSublayer:self.topBorder];
- self.toolbarView.frame = CGRectMake(0, 0, self.bounds.size.width, kToolbarHeight);
- self.toolbarView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-
- self.backgroundColor = backgroundColor;
- self.topBorder.backgroundColor = borderColor.CGColor;
-
- return self.toolbarView;
- }
- - (UIScrollView *)makeScrollView {
- UIScrollView *scrollView = [UIScrollView new];
- scrollView.backgroundColor = UIColor.clearColor;
- scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- scrollView.contentInset = UIEdgeInsetsMake(
- 8.f, kScrollViewHorizontalMargins, 4.f, kScrollViewHorizontalMargins
- );
- scrollView.showsHorizontalScrollIndicator = NO;
-
- self.scrollView = scrollView;
- [self addButtons];
-
- return scrollView;
- }
- - (void)addButtons {
- NSUInteger originX = 0.f;
-
- CGRect originFrame;
- CGFloat top = self.scrollView.contentInset.top;
- CGFloat bottom = self.scrollView.contentInset.bottom;
-
- for (FLEXKBToolbarButton *button in self.buttons) {
- button.appearance = self.appearance;
-
- originFrame = button.frame;
- originFrame.origin.x = originX;
- originFrame.origin.y = 0.f;
- originFrame.size.height = kToolbarHeight - (top + bottom);
- button.frame = originFrame;
-
- [self.scrollView addSubview:button];
-
- // originX tracks the origin of the next button to be added,
- // so at the end of each iteration of this loop we increment
- // it by the size of the last button with some padding
- originX += button.bounds.size.width + kButtonSpacing;
- }
-
- // Update contentSize,
- // set to the max x value of the last button added
- CGSize contentSize = self.scrollView.contentSize;
- contentSize.width = originX - kButtonSpacing;
- self.scrollView.contentSize = contentSize;
-
- // Needed to potentially right-align buttons
- [self setNeedsLayout];
- }
- - (void)setButtons:(NSArray<FLEXKBToolbarButton *> *)buttons {
- [_buttons makeObjectsPerformSelector:@selector(removeFromSuperview)];
- _buttons = buttons.copy;
-
- [self addButtons];
- }
- - (BOOL)useSystemAppearance {
- return self.appearance == UIKeyboardAppearanceDefault;
- }
- - (BOOL)usingDarkMode {
- if (@available(iOS 12, *)) {
- return self.useSystemAppearance && self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark;
- }
-
- return self.appearance == UIKeyboardAppearanceDark;
- }
- - (void)traitCollectionDidChange:(UITraitCollection *)previous {
- if (@available(iOS 12, *)) {
- // Was darkmode toggled?
- if (previous.userInterfaceStyle != self.traitCollection.userInterfaceStyle) {
- if (self.useSystemAppearance) {
- // Recreate the background view with the proper colors
- self.appearance = self.appearance;
- }
- }
- }
- }
- @end
|