Skip to content

Now with physics! #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 97 additions & 53 deletions CSNotificationView/CSNotificationView.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@

static NSInteger const kCSNotificationViewEmptySymbolViewTag = 666;

@interface CSNotificationView ()
@interface CSNotificationView (){
UIView *_messageView;
UIDynamicAnimator *_animator;
}

#pragma mark - blur effect
@property (nonatomic, strong) UIToolbar *toolbar;
Expand Down Expand Up @@ -93,22 +96,26 @@ - (instancetype)initWithParentViewController:(UIViewController*)viewController
self = [super initWithFrame:CGRectZero];
if (self) {

_messageView = [[UIView alloc] initWithFrame:CGRectZero];
[self addSubview:_messageView];

//Blur | thanks to https://github.com/JagCesar/iOS-blur for providing this under the WTFPL-license!
{
[self setToolbar:[[UIToolbar alloc] initWithFrame:[self bounds]]];
[self setToolbar:[[UIToolbar alloc] initWithFrame:[_messageView bounds]]];
[self setBlurLayer:[[self toolbar] layer]];

UIView *blurView = [UIView new];
[blurView setUserInteractionEnabled:NO];
[blurView.layer addSublayer:[self blurLayer]];
[blurView setTranslatesAutoresizingMaskIntoConstraints:NO];
[blurView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
[self insertSubview:blurView atIndex:0];
[_messageView insertSubview:blurView atIndex:0];

[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[blurView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(blurView)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(-1)-[blurView]-(-1)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(blurView)]];
[_messageView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[blurView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(blurView)]];
[_messageView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(-1)-[blurView]-(-1)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(blurView)]];

[self setBackgroundColor:[UIColor clearColor]];
[_messageView setBackgroundColor:[UIColor clearColor]];
}

//Parent view
Expand Down Expand Up @@ -141,7 +148,7 @@ - (instancetype)initWithParentViewController:(UIViewController*)viewController
_textLabel.numberOfLines = 2;
_textLabel.textColor = [UIColor whiteColor];
_textLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_textLabel];
[_messageView addSubview:_textLabel];
}
//symbolView
{
Expand All @@ -150,7 +157,7 @@ - (instancetype)initWithParentViewController:(UIViewController*)viewController
}

self.autoresizingMask = UIViewAutoresizingNone;

_messageView.autoresizingMask = UIViewAutoresizingNone;
}
return self;
}
Expand All @@ -159,7 +166,7 @@ - (instancetype)initWithParentViewController:(UIViewController*)viewController

- (void)updateConstraints
{
[self removeConstraints:self.constraints];
[_messageView removeConstraints:_messageView.constraints];

CGFloat symbolViewWidth = self.symbolView.tag != kCSNotificationViewEmptySymbolViewTag ?
kCSNotificationViewSymbolViewSidelength : 0.0f;
Expand All @@ -169,29 +176,29 @@ - (void)updateConstraints
@{@"symbolViewWidth": [NSNumber numberWithFloat:symbolViewWidth],
@"symbolViewHeight":[NSNumber numberWithFloat:symbolViewHeight]};

[self addConstraints:[NSLayoutConstraint
[_messageView addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"H:|-(4)-[_symbolView(symbolViewWidth)]-(5)-[_textLabel]-(10)-|"
options:0
metrics:metrics
views:NSDictionaryOfVariableBindings(_textLabel, _symbolView)]];

[self addConstraints:[NSLayoutConstraint
[_messageView addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:[_symbolView(symbolViewHeight)]"
options:0
metrics:metrics
views:NSDictionaryOfVariableBindings(_symbolView)]];

CGFloat topInset = CGRectGetHeight(self.frame) - 4;
CGFloat topInset = CGRectGetHeight(_messageView.frame) - 4;

[self addConstraint:[NSLayoutConstraint
[_messageView addConstraint:[NSLayoutConstraint
constraintWithItem:_symbolView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self
toItem:_messageView
attribute:NSLayoutAttributeBottom
multiplier:0.0f constant:topInset]];

[self addConstraint:[NSLayoutConstraint
[_messageView addConstraint:[NSLayoutConstraint
constraintWithItem:_textLabel
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
Expand All @@ -205,7 +212,8 @@ - (void)updateConstraints
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
self.blurLayer.frame = self.bounds;
_messageView.frame = [self hiddenFrame];
self.blurLayer.frame = _messageView.bounds;
}

#pragma mark - tint color
Expand All @@ -224,33 +232,55 @@ - (void)setVisible:(BOOL)visible animated:(BOOL)animated completion:(void (^)())
{
if (_visible != visible) {

NSTimeInterval animationDuration = animated ? 0.4 : 0.0;
CGRect startFrame = visible ? [self hiddenFrame]:[self visibleFrame];
CGRect endFrame = visible ? [self visibleFrame] : [self hiddenFrame];
self.frame = [self bigFrame];

if (!self.superview) {
self.frame = startFrame;

if (self.parentNavigationController) {
[self.parentNavigationController.view insertSubview:self belowSubview:self.parentNavigationController.navigationBar];
} else {
[self.parentViewController.view addSubview:self];
}

if (self.parentNavigationController) {
[self.parentNavigationController.view insertSubview:self belowSubview:self.parentNavigationController.navigationBar];
} else {
[self.parentViewController.view addSubview:self];
}

__block typeof(self) weakself = self;
[UIView animateWithDuration:animationDuration animations:^{
[weakself setFrame:endFrame];
} completion:^(BOOL finished) {
if (!visible) {
[weakself removeFromSuperview];
}
if (visible) {
_messageView.frame = [self hiddenFrame];

UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self];

UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[_messageView]];

UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[_messageView]];
collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;

UIDynamicItemBehavior *dynamicItem = [[UIDynamicItemBehavior alloc] initWithItems:@[_messageView]];
dynamicItem.elasticity = 0.4;
dynamicItem.allowsRotation = NO;

[animator addBehavior:dynamicItem];
[animator addBehavior:collisionBehavior];
[animator addBehavior:gravityBehavior];

_animator = animator;

if (completion) {
completion();
double delayInSeconds = 0.5;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
completion();
});
}
}];

}else{
CGRect frame = [self hiddenFrame];
frame.origin.y = self.bounds.size.height - frame.size.height;
_messageView.frame = frame;
[UIView animateWithDuration:0.4 animations:^{
_messageView.frame = [self hiddenFrame];
}completion:^(BOOL finished) {
[self removeFromSuperview];
if (completion) {
completion();
}
}];
}

_visible = visible;
} else if (completion) {
completion();
Expand Down Expand Up @@ -283,7 +313,13 @@ - (void)dismissWithStyle:(CSNotificationViewStyle)style message:(NSString *)mess
//Workaround as there is a bug: sometimes, when accessing topLayoutGuide, it will render contentSize of UITableViewControllers to be {0, 0}
- (CGFloat)topLayoutGuideLengthCalculation
{
CGFloat top = CGRectGetHeight([[UIApplication sharedApplication] statusBarFrame]);
CGFloat top = 0;

if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
top = CGRectGetWidth([[UIApplication sharedApplication] statusBarFrame]);
}else{
top = CGRectGetHeight([[UIApplication sharedApplication] statusBarFrame]);
}

if (self.parentNavigationController) {

Expand All @@ -293,35 +329,43 @@ - (CGFloat)topLayoutGuideLengthCalculation
return top;
}

- (CGRect)visibleFrame
- (CGFloat)widthLayoutGuideLengthCalculation
{
UIViewController* viewController = self.parentNavigationController ?: self.parentViewController;
CGFloat width = 0;

if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
width = CGRectGetHeight([[UIApplication sharedApplication] statusBarFrame]);
}else{
width = CGRectGetWidth([[UIApplication sharedApplication] statusBarFrame]);
}

return width;
}

- (CGRect)bigFrame
{
CGFloat topLayoutGuideLength = [self topLayoutGuideLengthCalculation];

CGFloat totalWidth = [self widthLayoutGuideLengthCalculation];

CGRect displayFrame = CGRectMake(0, 0, CGRectGetWidth(viewController.view.frame),
kCSNotificationViewHeight + topLayoutGuideLength);
CGRect displayFrame = CGRectMake(0, -(topLayoutGuideLength + kCSNotificationViewHeight),
totalWidth, 2*(kCSNotificationViewHeight + topLayoutGuideLength));

return displayFrame;
}

- (CGRect)hiddenFrame
{
UIViewController* viewController = self.parentNavigationController ?: self.parentViewController;

CGFloat topLayoutGuideLength = [self topLayoutGuideLengthCalculation];

CGRect offscreenFrame = CGRectMake(0, -kCSNotificationViewHeight - topLayoutGuideLength,
CGRectGetWidth(viewController.view.frame),
kCSNotificationViewHeight + topLayoutGuideLength);

CGRect offscreenFrame = self.bounds;
offscreenFrame.size.height /= 2;
return offscreenFrame;
}

- (CGSize)intrinsicContentSize
{
CGRect currentRect = self.visible ? [self visibleFrame] : [self hiddenFrame];
return currentRect.size;
UIViewController* viewController = self.parentNavigationController ?: self.parentViewController;
return CGSizeMake(CGRectGetWidth(viewController.view.frame),
kCSNotificationViewHeight);
}

#pragma mark - symbol view
Expand Down Expand Up @@ -349,7 +393,7 @@ - (void)updateSymbolView
_symbolView.tag = kCSNotificationViewEmptySymbolViewTag;
}
_symbolView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_symbolView];
[_messageView addSubview:_symbolView];
[self setNeedsUpdateConstraints];

}
Expand Down