leonatan / lnpopupcontroller Goto Github PK
View Code? Open in Web Editor NEWA framework for presenting view controllers as popups of other view controllers, much like the Apple Music and Podcasts apps.
License: MIT License
A framework for presenting view controllers as popups of other view controllers, much like the Apple Music and Podcasts apps.
License: MIT License
Hi Leo,
I'm having an issue with the popup bar and the bottom layout guide. You mention in the docs that your "framework will attempt to correct the bottom layout guide of the container controller and its child controllers as the popup bar is presented and dismissed." I'm wondering where exactly these calls are being made so that I can trace where it's going wrong in my app.
I attach your framework to my root view controller (a UITabBarController) whose child views are all UINavigationControllers, which in turn contain UITableViewControllers. Here's an example of the issue I'm having:
Once your bar is presented, it overlaps the table view, as you'd expect.
However, when I try to scroll to make the bottommost row visible, the app springs it back below the popup bar. I'm presuming this is because the table view controller doesn't know about the bottom layout guide.
I'm wondering how I can go about debugging this. I'd like to assume it's a potential problem with my code before blaming your framework, so I'm wondering where your framework attempts to set the bottomLayoutGuide so that I can trace the call down my view hierarchy and hopefully identify the issue.
Thanks!
My content view controller's primary view is a UIScrollView
subclass, specifically: UITableVIew
. Any advice on what the correct solution is for getting the popupInteractionGestureRecognizer
to work simultaneously with its installed panGestureRecognizer
so that if the scroll view's contentOffset
is zero, dragging down will dismiss the content view controller?
I have a crude initial attempt, which looks in the tableView
's gesture recognizer array for popupInteractionGestureRecognizer
. When the contentOffset
is just right (TM), it will stop the panGestureRecognizer
from beginning.
It works...but not great.
private override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
// Capture '_popupGesture', if necessary...
if (gestureRecognizers?.contains(gestureRecognizer) ?? false) == false
&& gestureRecognizer is UIPanGestureRecognizer
&& _popupGesture == nil {
_popupGesture = gestureRecognizer as? UIPanGestureRecognizer
} else if gestureRecognizer == panGestureRecognizer {
if let _ = _popupGesture {
switch (contentOffset.y + 44.0, panGestureRecognizer.velocityInView(self).y) {
case (-CGFloat.max...0, 1...CGFloat.max):
return false
default:
return true
}
}
}
return true
}
Is this feature deprecated in iOS 9 according to this documentation: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIPopoverController_class/index.html
I would like to press a button in the player view and then put the player into minified state. Exactly the same what the dismiss chevron button in the upper left of the example does. How can I call this from my own code?
Hi Leo!
In my app I have scrollable content inside a popup so the built in UIPanGestureRecognizer doesn't work in my situation. I want to have a UIPanGestureRecognizer on the top bar of my view controller only, not on the whole screen.
Would it be possible add API to pass a UIPanGestureRecognizer to LNPopupController or to pass a UIView to which I want the recogniser to be added?
This one was introduced very recently. One of the symptoms is that UIPopoverPresentationController's adaptivity behaviour has stopped working when presented inside the popup controller.
Steps to reproduce:
Inside DemoPopupContentViewController add
- (IBAction)presentVC:(UIButton *)sender {
UIViewController *testVC = [UIViewController new];
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:testVC];
nc.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *popoverController = nc.popoverPresentationController;
if (popoverController != nil) {
popoverController.sourceView = sender;
popoverController.sourceRect = sender.bounds;
popoverController.permittedArrowDirections = UIPopoverArrowDirectionAny;
}
[self presentViewController:nc animated:YES completion:nil];
}
On iPad Air 2 simulator present the test view controller and change the multitasking mode to 50/50 so that the horizontal size class becomes Regular.
Expected: the presented popover transforms to fullscreen (the screenshot was taken from an older version of the library)
Actual: the popover style remains (the recent version)
This seems to happen when openPopup is set to YES.
In _presentBar: of FirstViewController.m of the example project , I tried changing
[targetVC openPopupAnimated:demoVC completion:nil];
to
[targetVC presentPopupBarWithContentViewController:demoVC openPopup:YES animated:YES completion:^{ NSLog(@"Completion"); }];
And get two logs of "Completion".
This happens because the completion block is called in presentPopupBarAnimated both in the animations:^ and completion^: blocks when open == YES.
Hey, I followed the Github instructions for importing the framework. It's in embedded libraries and linked frameworks but I'm getting "error: /Users/me/Documents/testApp/TestApp/LNPopupController/build/Debug-iphoneos/LNPopupController.framework: No such file or directory"
Not sure what I'm doing wrong. When I downloaded and dragged in just the .xcodeproj it linked from my downloads directory so undid all that and copied the folder into my directory and then dragged it in again. Hitting the + on the Embedded Libraries didn't bring it in so I went to Link Binary With Libraries and added it there first. Now it appears in all the correct places but it isn't being found.
dyld: Library not loaded: @rpath/LNPopupController.framework/LNPopupController
Referenced from: /var/mobile/Containers/Bundle/Application/....
Reason: image not found
If I open a navigation controller instead a single view controller, then the bar doesn't show any button or information.
let nav = UINavigationController(rootViewController: popupContentController) tabBarController?.presentPopupBarWithContentViewController(nav, animated: true, completion: nil)
I downloaded the framework as a git submodule and built my app. Then I tried uploading to iTC. I received an error about missing version keys in the info.plist. It turns out that the framework target doesn't have the required version numbers in its info.plist. I've fixed this and submitted a PR #28.
In 0c98357 you have removed the default centered text alignment. Now I tried to set the alignment with paragraphStyle, but it does not work.
NSMutableParagraphStyle *paragraph= [[NSMutableParagraphStyle alloc] init];
[paragraph setAlignment:NSTextAlignmentCenter];
[[LNPopupBar appearanceWhenContainedInInstancesOfClasses:@[[UINavigationController class]]] setTitleTextAttributes:@{NSFontAttributeName: [UIFont fontWithName:@"Chalkduster" size:14], NSForegroundColorAttributeName: [UIColor yellowColor],NSParagraphStyleAttributeName : paragraph}];
How can I set myself as the popupBarLongPressGestureRecognizerDelegate
?
How do I achieve changing the progress bar color?
It's a major one - when used with UITabBarController that has more than 4 tabs the LNPopupController gets embedded into the UITabBarController as an additional tab. This happens not on the initial presentation but when the screen size changes (iOS9 multitasking on iPad Air2 and newer).
Steps:
Result:
The LNPopupController ends up being an additional tab of the tab bar controller
I'm implementing this framework in my app, but somehow, when I slide it open, the view is placed behind the UINavigationBar
. What am I doing wrong?
I present it like this: [self presentPopupBarWithContentViewController:self.demoVC animated:YES completion:nil];
I present a UIViewController as a popup. I want to change the status bar color dynamically.
I have implemented preferredStatusBarStyle()
and an updateStatusBarStyle(style: UIStatusBarStyle)
method to set a new style.
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return statusBarStyle
}
func updateStatusBarStyle(style: UIStatusBarStyle) {
statusBarStyle = style
self.setNeedsStatusBarAppearanceUpdate()
}
self.setNeedsStatusBarAppearanceUpdate()
is called as I can see by debugging. However the status bar color does not change.
The status bar only updates its style correctly, if I minify the popup and max again.
Any help would be greatly appreciated - I have a view controller that has a table view of audio tracks that plays them via AVPlayer. When I call dismissPopupBar the audio keeps playing and makes me believe that the view controller and it's objects are still in memory.
I would like to have a small coverart image of the current playing song in the minified version of the player.
I tried to set the coverart image instead of the play/pause button, however it messed up the whole layout. Maybe because it is a large image? I expected it to be scaled...
Any tips on how to do that?
Currently there is presentPopupBarWithContentViewController and upon completion we can call openPopupAnimated. It works OK but it'd be nice to have API to present popup view controller in one step.
Hi, LNPopupController dosent allow to click on keyboard, i have made a test project so u can test it, when u touch UISearchBar, keyboard shows up but its not clickable, it happens even when u don't present the popup bar!
here u can check the test project
love the project btw!! awesome
Hi All,
I would like to use LNPopupController with content controller which is embeded in UINavigationController (or have own UINavigationBar at least).
I am trying to do something similar as Instagram do with their Tabbar middle Button, but in my case I want to create Popup Bar with Dashboard View Controller as it's content view. So I used the Tabbarcontroller delegate method to basically ignore that middle tab bar button tap and instead of that I instantiate Dashboard VC from storyboard like this:
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
if ([viewController isKindOfClass:[GRAVDashBoardPlaceholderController class]]) {
UIStoryboard *dashboardStoryboard = [UIStoryboard storyboardWithName:@"Dashboard" bundle:nil];
UIViewController *dashboardVC = (GRAVDashboardViewController *)[dashboardStoryboard instantiateInitialViewController];
dashboardVC.popupItem.title = @"Recording test";
dashboardVC.popupItem.subtitle = @"00:00:00";
dashboardVC.popupItem.progress = 0;
self.tabBarController.popupContentView.popupCloseButton.hidden = YES;
[self.tabBarController presentPopupBarWithContentViewController:dashboardVC openPopup:YES animated:YES completion:nil];
return NO;
}
return YES;
}
And this is what I want to achieve:
I tried to:
1) embed Dashboard view in Navigation Controller (translucent set to NO) directly in Storyboard
2) add Navigation Bar with autolayout constraints
But Navigation bar looks always like this when I use presentPopupBarWithContentViewController:openPopup:animated:completion:
This is well known behaviour since iOS7 [http://blog.jaredsinclair.com/post/61507315630/wrestling-with-status-bars-and-navigation-bars-on]
I checked tons of stackoverflow discussions about this topic. The only way I was able to solve that navigation bar layout (as seen on gif above) after initial openPopup: was that I add NavigationBar with 20pts constraint to Top Layout Guide of DashboardVC and use positionForBar:
delegate method to return UIBarPositionTopAttached
:
- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar {
return UIBarPositionTopAttached;
}
But here is the issue. On both solutions stated above (correct and incorrect initial navbar height) with another UI update on the Dashboard i.e. when "start recording" button is pressed NavigationBar height change as well:
I am not sure it this behaviour has something to do with the Dashboard autolayout constraints setup or anything else... Any idea how to solve this? Or advice, what should I be focused on during troubleshooting? Thanks in advance ✌️
When popup view controller is being presented for the first time it's view hierarchy animates (expands from the bottom left corner) inline with the popup presentation animation. It can be reproduced in the sample app "Apple Music". Expected behaviour would be to see the view coming from the bottom.
I just discovered a problem: If you use a timer in the PopupViewController to call a method on it regularly the PlayerViewController will be kept in memory and active even if the tabBarController instantiated a new PopupViewController.
I discovered this because right at the moment I added a timer, my AVPlayer of each PopupViewController(containing the player) kept playing in the background even when I started playing another song and a new PopupViewController was created.
I fixed this by invalidating the timer each time a new PopupViewController object was created.
// invalidate the timer of the old controller, because this keeps the old controller in the memory
if let oldController = popupContentController {
oldController.timer?.invalidate()
oldController.player?.pause()
}
popupContentController = storyboard?.instantiateViewControllerWithIdentifier("DemoMusicPlayerController") as? PlayerViewController
tabBarController?.presentPopupBarWithContentViewController(popupContentController!, animated: true, completion: nil)
Is this issue covered in the demo projects?
Hi @LeoNatan ,great work on LNPopupController!
I tried to uncomment the code in your example project
+ (void)load
{
[[LNPopupBar appearanceWhenContainedInInstancesOfClasses:@[[UINavigationController class]]] setTitleTextAttributes:@{NSFontAttributeName: [UIFont fontWithName:@"Chalkduster" size:14], NSForegroundColorAttributeName: [UIColor yellowColor]}];
[[LNPopupBar appearanceWhenContainedInInstancesOfClasses:@[[UINavigationController class]]] setSubtitleTextAttributes:@{NSFontAttributeName: [UIFont fontWithName:@"Chalkduster" size:12], NSForegroundColorAttributeName: [UIColor greenColor]}];
[[LNPopupBar appearanceWhenContainedInInstancesOfClasses:@[[UINavigationController class]]] setBarStyle:UIBarStyleBlack];
[[LNPopupBar appearanceWhenContainedInInstancesOfClasses:@[[UINavigationController class]]] setTintColor:[UIColor yellowColor]];
}
to see customised appearance of LNPopupBar, it was crashed with unrecognized selector sent to class
, am I missing anything?
Hi!
I cannot find LNNotificationsUI.framework. I only found LNPopupController.
Currently it's two steps: close popup and dismiss bar. Would be nice to be able to dismiss popup in one step.
I want to customize the looks of my popup bar:
LNPopupBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName : UIColor.whiteColor()]
LNPopupBar.appearance().subtitleTextAttributes = [NSForegroundColorAttributeName : UIColor.whiteColor()]
LNPopupBar.appearance().barStyle = UIBarStyle.Black
LNPopupBar.appearance().tintColor = UIColor.whiteColor()
All settings work except the background color aka barStyle. My popupbar is still red like the tabBar underneath it. I want it to be black.
Why is deinit
of my contentViewController which I present as popupBar not called when I call dismissPopupBarAnimated(true, completion: nil)
to dismiss the popupbar?
When my lnpopup view is fullscreen, I set the status bar color according to the coverart image (so the status bar is visible).
However if the player is minified I need to update the status bar color again, so it matches the color of my navigation bar of the rest of the app.
This kinda works if I use this method to set my status bar color:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
However this does not play nice with controllers inside UINavigationController
s. So I use this method now:
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
However this does not change the status bar color when the popup is minified. Therefore I need a delegate to be called whenever the popup is minified, so I can force an update of the status bar color.
I have a UINavigationController with a UIVC as its content controller. I call:
[self presentPopupBarWithContentViewController:self.mapNavigationController animated:YES completion:nil];
and it all works great. I get my viewDidLayoutSubviews - I alter the table content insets and all is good!
However when I open the content controller either by tapping on the button or swiping up, the content is under the navigation controller's navbar.
Now in your sample, you present the popupbar on the self.navigationController if there is no tab bar - and true, if I set it to navigationBar…it overlays the navigation Bar correctly…but then I don't get any changes to my bottom layout guide to offset the tableview content offsets.
There has to be a way to make both work…
Hello, I've dragged and dropped LNPopupController.xcoderoj into my project then I added the Framework to binary. Finally, in .m file I've added @import LNPopupController;
.
Now when I run my project I get this error :
dyld: Library not loaded: @rpath/LNPopupController.framework/LNPopupController
Referenced from: /private/var/mobile/Containers/Bundle/Application/811B7095-DA53-4F0E-B48D-D22765AAFD7E/flimee.app/flimee
Reason: image not found
Did I missed something here ?
please update when you can !
It would be great if this component could be integrated into a project using cocoapods. This would mean only one line in a project's Podfile to install it.
Information about adding a new project to cocoapods is here: https://guides.cocoapods.org/making/making-a-cocoapod.html
Cheers
Hi,
Unfortunately, I can't use anymore swipe gesture recognizer in the popup window. It seems the popup event to reduce the View Controller is overwriting all swipe events.
Thanks.
I'm trying to add a popupBar
with a custom bottomDockingView
(essentially, my player controls view).
However, I'm seeing some odd behavior: the popupBar
isn't initially respecting the location of the bottomDockingView
. It's only after I open contentViewController
(calling presentPopupBarWithContentViewController
) and then closing it, does the popupBar
appear connected to the bottomDockingView
correctly.
If it helps any: the initial state of the view hierarchy (i.e, simply launching the app) indicates the bottomDockingView
is sitting where it should, but above all other views (including the popupBar
). Thus, until I figure out what I'm doing wrong, I'm moving the z-position of the bottomDockingView
to be below the popupBar
, so at least I can open (then close) its contentViewController
.
Any insight into what I'm doing wrong? Thanks.
Need API to customise the close button. At least to be able to hide the default one.
When I initialise and open the LNPopupController
instance in my app, I get a a window that's complete see-through on top of the presenting UIViewController
.
self.restVC = [RestaurantsViewController new];
self.restVC.restaurants = [Restaurants fetchAll];
UIBarButtonItem *title = [[UIBarButtonItem alloc] initWithCustomView:self.restLabel];
self.restVC.popupItem.rightBarButtonItems = @[title];
[self.navigationController presentPopupBarWithContentViewController:self.restVC openPopup:YES animated:NO completion:nil];
When I look in the logs I can see that RestaurantsViewController
is indeed loaded. If I then collaps the view and reopen it, it's fine. Any ideas as to what's causing this?
I've got a crash when the title or subtitle property is nil on presentation.
The crash is in the LNPopupBar : _layputTitles method, at line 281:
_titleLabel.attributedText = [[NSAttributedString alloc] initWithString:_title attributes:defaultTitleAttribures];
of course the error is the following:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'NSConcreteAttributedString initWithString:: nil value'
For the subtitle, I did not check, but based on the code, it is the same :)
I'm unable to duplicate the dismiss chevron like you have in the example...I thought it was included by default. I am using cocoapods.
Need a way to interface the gesture recogniser since it's not always needed, especially when the popup content is scrollable.
The Apple Music app doesn't use a UINavigationController here, so perhaps this wasn't an anticipated edge case, but whenever I pass a UINavigationController as the popup view controller, the navigation bar doesn't adjust for the status bar.
Please help on this one - so weird..been at it for hours now.
Hi,
UITabBar can be hidden with .hidden
property, but in this case bottomBarFrame
still will be calculated with default UITabBar height (including frame.origin
). You can see it here:
- (CGRect)defaultFrameForBottomDockingView
{
CGRect bottomBarFrame = self.tabBar.frame;
bottomBarFrame.origin = CGPointMake(0, self.view.bounds.size.height - bottomBarFrame.size.height);
return bottomBarFrame;
}
I think .origin
should be calculated with additional check for visibility, something like this:
- (CGRect)defaultFrameForBottomDockingView
{
CGRect bottomBarFrame = self.tabBar.frame;
bottomBarFrame.origin = CGPointMake(0, self.view.bounds.size.height - (self.tabBar.isHidden ? 0 : bottomBarFrame.size.height));
return bottomBarFrame;
}
Regards,
Artem
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.