Skip to content

Commit

Permalink
add customView sizingController & use in presentSwiftView:
Browse files Browse the repository at this point in the history
  • Loading branch information
calimarkus committed Oct 25, 2023
1 parent eaf37b7 commit 667acf3
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
7E1C2838285226F5004315CC /* EnumPickerOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E1C2836285226F5004315CC /* EnumPickerOptionView.swift */; };
7E1C2839285226F5004315CC /* EnumPickerOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E1C2836285226F5004315CC /* EnumPickerOptionView.swift */; };
7E2A4E852AE70A4B001F0DB0 /* JDStatusBarNotificationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EB914CF2ADC11F4004B3435 /* JDStatusBarNotificationPresenter.swift */; };
7E2A4E8D2AE99D70001F0DB0 /* JDStatusBarNotificationPresenterCustomViewSizingController.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E2A4E8C2AE99D70001F0DB0 /* JDStatusBarNotificationPresenterCustomViewSizingController.h */; settings = {ATTRIBUTES = (Public, ); }; };
7E2F3BBB284F6144002B2181 /* ObservableCustomStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E2F3BBA284F6144002B2181 /* ObservableCustomStyle.swift */; };
7E2F3BBC284F6144002B2181 /* ObservableCustomStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E2F3BBA284F6144002B2181 /* ObservableCustomStyle.swift */; };
7E2F3BBD284F6144002B2181 /* ObservableCustomStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E2F3BBA284F6144002B2181 /* ObservableCustomStyle.swift */; };
Expand Down Expand Up @@ -110,6 +111,7 @@
7E1C283128520F56004315CC /* JDSBNotificationAnimator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JDSBNotificationAnimator.h; sourceTree = "<group>"; };
7E1C283228520F56004315CC /* JDSBNotificationAnimator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JDSBNotificationAnimator.m; sourceTree = "<group>"; };
7E1C2836285226F5004315CC /* EnumPickerOptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnumPickerOptionView.swift; sourceTree = "<group>"; };
7E2A4E8C2AE99D70001F0DB0 /* JDStatusBarNotificationPresenterCustomViewSizingController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JDStatusBarNotificationPresenterCustomViewSizingController.h; sourceTree = "<group>"; };
7E2F3BBA284F6144002B2181 /* ObservableCustomStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservableCustomStyle.swift; sourceTree = "<group>"; };
7E5402C2286708840079C579 /* JDStatusBarNotification.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JDStatusBarNotification.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7E5402C5286708850079C579 /* JDStatusBarNotification.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = JDStatusBarNotification.docc; sourceTree = "<group>"; };
Expand Down Expand Up @@ -234,6 +236,7 @@
7E8C519628585BE400C7C003 /* JDStatusBarNotificationPresenterPrepareStyleBlock.h */,
7E8C519328585BE400C7C003 /* JDStatusBarNotificationStyle.h */,
7E8C519728585BE400C7C003 /* JDStatusBarNotificationStyle.m */,
7E2A4E8C2AE99D70001F0DB0 /* JDStatusBarNotificationPresenterCustomViewSizingController.h */,
);
path = Public;
sourceTree = "<group>";
Expand Down Expand Up @@ -337,6 +340,7 @@
7E5402E5286709560079C579 /* JDStatusBarNotificationPresenter.h in Headers */,
7E5402E72867095C0079C579 /* JDStatusBarNotificationPresenterPrepareStyleBlock.h in Headers */,
7E5402E6286709590079C579 /* JDStatusBarNotificationStyle.h in Headers */,
7E2A4E8D2AE99D70001F0DB0 /* JDStatusBarNotificationPresenterCustomViewSizingController.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ struct ExamplesScreen: View {
}
.padding(6.0)
.padding([.leading, .trailing], 10.0)
.fixedSize()
}

NotificationPresenter.shared().dismiss(afterDelay: 2.5)
Expand Down
3 changes: 3 additions & 0 deletions JDStatusBarNotification/Private/JDSBNotificationView.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#import <UIKit/UIKit.h>

#import <JDStatusBarNotification/JDStatusBarNotificationPresenterCustomViewSizingController.h>

NS_ASSUME_NONNULL_BEGIN

@class JDStatusBarNotificationStyle;
Expand Down Expand Up @@ -35,6 +37,7 @@ NS_SWIFT_NAME(_SBNotificationView)
/// state like rotation, status bar visibility, etc..) It never overlaps the statusbar. The height & width is defined
/// by the selected style. In the pill style the view will match the pill size.
@property (nonatomic, strong, nullable) UIView *customSubview;
@property (nonatomic, strong, nullable) id<JDStatusBarNotificationPresenterCustomViewSizingController> customSubviewSizingController;

/// A left view will be displayed left of the text. The layout can be adjusted using the leftViewStyle.
@property (nonatomic, strong, nullable) UIView *leftView;
Expand Down
12 changes: 12 additions & 0 deletions JDStatusBarNotification/Private/JDSBNotificationView.m
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ - (void)resetSubviews {

// reset custom subview
_customSubview = nil;
_customSubviewSizingController = nil;
if (_leftView != _activityIndicatorView) {
_leftView = nil;
}
Expand Down Expand Up @@ -278,6 +279,11 @@ - (void)setCustomSubview:(UIView *)customSubview {
[self setNeedsLayout];
}

- (void)setCustomSubviewSizingController:(id<JDStatusBarNotificationPresenterCustomViewSizingController>)customSubviewSizingController {
_customSubviewSizingController = customSubviewSizingController;
[self setNeedsLayout];
}

#pragma mark - Style

- (void)setStyle:(JDStatusBarNotificationStyle *)style {
Expand Down Expand Up @@ -386,6 +392,12 @@ - (CGRect)pillContentRectForContentRect:(CGRect)contentRect {

// layout pill
CGFloat maxTextWidth = MAX(realTextSizeForLabel(_titleLabel).width, realTextSizeForLabel(_subtitleLabel).width);
if (_customSubview) {
const CGSize sizeThatFits = (_customSubviewSizingController
? [_customSubviewSizingController sizeThatFits:contentRect.size]
: [_customSubview sizeThatFits:contentRect.size]);
maxTextWidth = MAX(maxTextWidth, sizeThatFits.width);
}
CGFloat pillWidth = round(MAX(minimumPillWidth, MIN(maximumPillWidth, maxTextWidth + paddingX * 2)));
CGFloat pillX = round(MAX(minimumPillInset, (CGRectGetWidth(self.bounds) - pillWidth)/2.0));
CGFloat pillY = round(contentRect.origin.y + contentRect.size.height - pillHeight);
Expand Down
22 changes: 22 additions & 0 deletions JDStatusBarNotification/Public/JDStatusBarNotificationPresenter.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#import <JDStatusBarNotification/JDStatusBarNotificationPresenterPrepareStyleBlock.h>
#import <JDStatusBarNotification/JDStatusBarNotificationStyle.h>
#import <JDStatusBarNotification/JDStatusBarNotificationPresenterCustomViewSizingController.h>

@class JDStatusBarNotificationPresenter;

Expand Down Expand Up @@ -242,6 +243,27 @@ NS_SWIFT_NAME(NotificationPresenter)
styleName:(NSString * _Nullable)styleName
completion:(JDStatusBarNotificationPresenterCompletionBlock)completion NS_SWIFT_NAME(present(customView:style:completion:));

/// Present a notification using a custom subview.
///
/// The `customView` will be layouted correctly according to the selected style & the current device
/// state (rotation, status bar visibility, etc.). The background will still be styled & layouted
/// according to the provided style. If your custom view requires custom touch handling,
/// make sure to set `style.canTapToHold` to `false`. Otherwise the `customView` won't
/// receive any touches, as the internal `gestureRecognizer` would receive them.
///
/// - Parameters:
/// - customView: A custom UIView to display as notification content.
/// - styleName: The name of the style. You can use styles previously added using e.g. ``addStyleNamed:prepare:``.
/// If no style can be found for the given `styleName` or it is `nil`, the default style will be used.
/// - completion: A ``JDStatusBarNotificationPresenterCompletionBlock``, which gets called once the presentation animation finishes.
///
/// - Returns: The presented UIView for further customization
///
- (UIView *)presentWithCustomView:(UIView *)customView
sizingController:(id<JDStatusBarNotificationPresenterCustomViewSizingController> _Nullable)sizingController
styleName:(NSString * _Nullable)styleName
completion:(JDStatusBarNotificationPresenterCompletionBlock)completion NS_SWIFT_NAME(present(customView:sizingController:style:completion:));

#pragma mark - Dismissal

/// Dismisses any currently displayed notification immediately using an animation.
Expand Down
11 changes: 11 additions & 0 deletions JDStatusBarNotification/Public/JDStatusBarNotificationPresenter.m
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,20 @@ - (UIView *)presentWithTitle:(NSString *)title
- (UIView *)presentWithCustomView:(UIView *)customView
styleName:(NSString * _Nullable)styleName
completion:(JDStatusBarNotificationPresenterCompletionBlock)completion {
return [self presentWithCustomView:customView
sizingController:nil
styleName:styleName
completion:completion];
}

- (UIView *)presentWithCustomView:(UIView *)customView
sizingController:(id<JDStatusBarNotificationPresenterCustomViewSizingController> _Nullable)sizingController
styleName:(NSString * _Nullable)styleName
completion:(JDStatusBarNotificationPresenterCompletionBlock)completion {
JDStatusBarNotificationStyle *style = [_styleCache styleForName:styleName];
JDSBNotificationView *view = [self presentWithTitle:nil subtitle:nil style:style completion:completion];
view.customSubview = customView;
view.customSubviewSizingController = sizingController;
return view;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,29 @@

import SwiftUI

class NotificationPresenterSizingController<Content>: NotificationPresenterCustomViewSizingController where Content: View {
let hostingController: UIHostingController<Content>

init(hostingController: UIHostingController<Content>) {
self.hostingController = hostingController
}

func sizeThatFits(in size: CGSize) -> CGSize {
return hostingController.sizeThatFits(in: size)
}
}

extension NotificationPresenter {

public func presentSwiftView(style: String? = nil,
@ViewBuilder viewBuilder: () -> some View,
completion: NotificationPresenterCompletion? = nil) {
let controller = UIHostingController(rootView: viewBuilder())
controller.view.backgroundColor = .clear
self.present(customView: controller.view, style: style, completion: completion)
self.present(customView: controller.view,
sizingController: NotificationPresenterSizingController(hostingController: controller),
style: style,
completion: completion)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// JDStatusBarNotificationPresenterCustomViewSizingController.h
//
// Created by Markus Emrich on 10/25/23.
// Copyright 2023 Markus Emrich. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

NS_SWIFT_NAME(NotificationPresenterCustomViewSizingController)
@protocol JDStatusBarNotificationPresenterCustomViewSizingController
- (CGSize)sizeThatFits:(CGSize)size NS_SWIFT_NAME(sizeThatFits(in:));
@end

NS_ASSUME_NONNULL_END

0 comments on commit 667acf3

Please sign in to comment.