Code Monkey home page Code Monkey logo

lnpopupcontroller's Introduction

LNPopupController

LNPopupController is a framework for presenting view controllers as popups of other view controllers, much like the Apple Music and Podcasts apps.

For SwiftUI, check out the LNPopupUI library.

GitHub release GitHub stars GitHub license PayPal Donation Button

GitHub issues GitHub contributors Swift Package Manager compatible Carthage compatible

Once a popup bar is presented with a content view controller, the user can swipe or tap the popup bar at any point to present the popup. After finishing, the user dismisses the popup by either swiping or tapping the popup close button.

The framework is intended to be very generic and work in most situations, so it is implemented as a category over UIViewController. Each view controller can present a popup bar, docked to a bottom view. For UITabBarController subclasses, the default docking view is the tab bar. For UINavigationController subclasses, the default docking view is the toolbar. For other classes, the popup bar is presented at the bottom of the screen. View controller subclasses can provide their own docking views.

The framework correctly maintains the safe area insets of the container controller’s view and its child controllers, as the popup bar is presented and dismissed.

The information displayed on the popup bar is provided dynamically with popup item objects (instances of the LNPopupItem class) associated with the popup content view controllers. To change this information, update the popup item of the view controller.

Generally, it is recommended to present the popup bar on the outermost container controller. So if you have a view controller contained in a navigation controller, which is in turn contained in a tab bar controller, it is recommended to present the popup bar on the tab bar controller.

Check the demo project for many common use cases of the framework in various scenarios. It contains examples in Swift and Objective C.

Features

  • Available for iOS 13 and above, as an Xcode framework or an SPM package
  • Good citizen in modern UIKit world
  • Modern Objective C syntax and great Swift interoperability
  • For SwiftUI, check out the LNPopupUI library.

Adding to Your Project

Swift Package Manager

Swift Package Manager is the recommended way to integrate LNPopupController in your project.

LNPopupController supports SPM versions 5.5 and above. To use SPM, you should use Xcode 13 to open your project. Click File -> Swift Packages -> Add Package Dependency, enter https://github.com/LeoNatan/LNPopupController. Select the version you’d like to use.

You can also manually add the package to your Package.swift file:

.package(url: "https://github.com/LeoNatan/LNPopupController.git", from: "2.15.0")

And the dependency in your target:

.target(name: "MyExampleApp", dependencies: ["LNPopupController"]),

Carthage

Add the following to your Cartfile:

github "LeoNatan/LNPopupController"

Make sure you follow the Carthage integration instructions here.

Manual

Drag the LNPopupController.xcodeproj project to your project, and add LNPopupController.framework to Embedded Binaries in your project target's General tab. Xcode should sort everything else on its own.

CocoaPods

CocoaPods is not supported. There are many reasons for this. Instead of CocoaPods, use Swift Package Manager from within Xcode. You can continue using CocoaPods for for your other dependencies and Swift Package Manager for LNPopupController.

Using the Framework

Swift

While the framework is written in Objective C, it uses modern Objective C syntax, so using the framework in Swift is very easy and intuitive.

Project Integration

Import the module in your project:

import LNPopupController

Popup Items

A popup item should always reflect the popup information about the view controller with which it is associated. The popup item should provide a title and subtitles to display in the popup bar, when the view controller is presented as a popup content controller. In addition, the item may contain additional buttons to display on the leading and/or trailing edges of the popup bar using leadingBarButtonItems and trailingBarButtonItems.

Managing the Popup Bar

To present the popup bar, create a content controller, update its popup item and present the popup bar.

let demoVC = DemoPopupContentViewController()
demoVC.view.backgroundColor = .red
demoVC.popupItem.title = "Hello World"
demoVC.popupItem.subtitle = "And a subtitle!"
demoVC.popupItem.progress = 0.34
	
tabBarController?.presentPopupBar(withContentViewController: demoVC, animated: true, completion: nil)

You can present a new content controller while the popup bar is presented and when the popup itself is open.

To open and close the popup programatically, use openPopup(animated:completion:) and closePopup(animated:completion:) respectively.

tabBarController?.openPopup(animated: true, completion: nil)

Alternatively, you can present the popup bar and open the popup in one animation, using presentPopupBar(withContentViewController:openPopup:animated:completion:).

tabBarController?.presentPopupBar(withContentViewController: demoVC, openPopup:true, animated: true, completion: nil)

To dismiss the popup bar, use dismissPopupBarAnimated:completion:.

tabBarController?.dismissPopupBar(animated: true, completion: nil)

If the popup is open when dismissing the popup bar, the popup content will also be dismissed.

Popup Container View Controllers

Any UIViewController subclasses can be popup container view controllers. The popup bar is attached to a bottom docking view. By default, UITabBarController and UINavigationController subclasses return their bottom bars as docking view, while other controllers return a hidden 0pt height view on the bottom of the view. In your subclass, override bottomDockingViewForPopupBar and defaultFrameForBottomDockingView and return your view and frame accordingly. The returned view must be attached to the bottom of the view controller's view, or results are undefined.

override var bottomDockingViewForPopupBar: UIView? {
  return myCoolBottomView
}

override var defaultFrameForBottomDockingView: CGRect {
  var bottomViewFrame = myCoolBottomView.frame
  
  if isMyCoolBottomViewHidden {
    bottomViewFrame.origin = CGPoint(x: bottomViewFrame.x, y: view.bounds.height)
  } else {
    bottomViewFrame.origin = CGPoint(x: bottomViewFrame.x, y: view.bounds.height - bottomViewFrame.height)
  }
  
  return bottomViewFrame
}

Appearance and Behavior

LNPopupController provides three distinct styles of popup look and feel, each based on Music app looks and feels, that Apple has introduced over the years. Popup bar styles are labeled "floating”, “prominent" and "compact", matching the appropriate Apple style. Popup interaction styles are labeled "snap" for modern style snapping popups and "drag" for iOS 9 interactive popup interaction. Popup close buttons styles are labeled "chevron" for modern style chevron close button and "round" for iOS 9-style close buttons. For each, there is a "default" style for choosing the most suitable one for the current platform and operating system version.

The defaults are:

  • iOS 17:

    • Floating bar style

    • Snap interaction style

    • Grabber close button style

    • No progress view style

  • iOS 16 and below:

    • Prominent bar style
    • Snap interaction style

    • Chevron close button style

    • No progress view style

You can also present completely custom popup bars. For more information, see Custom Popup Bars.

By default, for navigation and tab bar container controllers, the appearance of the popup bar is determined according to the bottom bar's appearance. For other container controllers, a default appearance is used, most suitable for the current environment.

To disable inheriting the bottom bar’s appearance, set the inheritsAppearanceFromDockingView property to false.

Bar Style

Customizing the popup bar style is achieved by setting the popup bar's barStyle property.

navigationController?.popupBar.barStyle = .compact

Interaction Style

Customizing the popup interaction style is achieved by setting the popup presentation containing controller's popupInteractionStyle property.

navigationController?.popupInteractionStyle = .drag

Progress View Style

Customizing the popup bar progress view style is achieved by setting the popup bar's progressViewStyle property.

navigationController?.popupBar.progressViewStyle = .top

To hide the progress view, set the progressViewStyle property to LNPopupBar.ProgressViewStyle.none.





Close Button Style

Customizing the popup close button style is achieved by setting the popup content view's popupCloseButtonStyle property.

navigationController.popupContentView.popupCloseButtonStyle = .round

To hide the popup close button, set the popupCloseButtonStyle property to LNPopupCloseButton.Style.none.





Text Marquee Scroll

Supplying long text for the title and/or subtitle will result in a scrolling text, if text marquee is enabled. Otherwise, the text will be truncated.

Popup Bar Customization

LNPopupBar exposes API to customize the default popup bar's appearance, either through UIAppearance API or directly on a specific popup bar object. Use LNPopupBarAppearance objects to define the standard appearance of the bar.

Remember to set the inheritsAppearanceFromDockingView property to false, or your customization is likely to be overridden by the bottom bar’s appearance.

let appearance = LNPopupBarAppearance()
appearance.titleTextAttributes = AttributeContainer()
				.font(UIFontMetrics(forTextStyle: .headline).scaledFont(for: UIFont(name: "Chalkduster", size: 14)!))
				.foregroundColor(UIColor.yellow)
appearance.subtitleTextAttributes = AttributeContainer()
				.font(UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: UIFont(name: "Chalkduster", size: 12)!))
				.foregroundColor(UIColor.green)
appearance.backgroundEffect = UIBlurEffect(style: .systemChromeMaterialDark)

navigationController?.popupBar.inheritsAppearanceFromDockingView = false
navigationController?.popupBar.standardAppearance = appearance
navigationController?.popupBar.tintColor = .yellow

System Interactions

The hidesBottomBarWhenPushed property is supported for navigation and tab bar controllers. When set to true, the popup bar will transition to the bottom of the pushed controller's view. Setting isToolbarHidden = true and calling setToolbarHidden(_:animated:) are also supported.

Status bar management of the popup content view controller is respected and applied when appropriate.

Home indicator visibility control is respected and applied when appropriate.

Context menus are supported. Add a UIContextMenuInteraction interaction object to the popup bar, and it will behave as expected.

Pointer interactions are supported, and a default implementation is provided for system bar styles.

For custom popup bar controllers, the LNPopupCustomBarViewController class implements the UIPointerInteractionDelegate protocol. Implement the protocol's methods inside your subclass to implement custom pointer interactions.

Starting with iOS 15, scroll edge appearance is automatically disabled for toolbars and tab bars when a popup bar is presented, regardless of the scroll position of the content. Once the popup bar is dismissed, the scroll edge appearance is restored.

Custom Popup Bars

The framework supports implementing custom popup bars.

To implement a custom popup bar, you subclass LNPopupCustomBarViewController.

In your LNPopupCustomBarViewController subclass, build your popup bar's view hierarchy and set the controller's preferredContentSize property with the preferred popup bar height. Override any of the wantsDefaultTapGestureRecognizer, wantsDefaultPanGestureRecognizer and/or wantsDefaultHighlightGestureRecognizer properties to disable the default gesture recognizers functionality in your custom popup bar.

In your subclass, implement the popupItemDidUpdate() method to be notified of updates to the popup content view controller's item, or when a new popup content view controller is presented (with a new popup item). You must call the super implementation of this method.

Finally, set the customBarViewController property of the popup bar object to an instance of your LNPopupCustomBarViewController subclass. This will automatically change the bar style to LNPopupBar.Style.custom.

The included demo project includes two example custom popup bar scenes.

Tip

Only implement a custom popup bar if you need a design that is significantly different than the provided standard popup bar styles. A lot of care and effort has been put into integrating these popup bar styles with the UIKit system, including look, feel, transitions and interactions. Custom bars provide a blank canvas for you to implement a bar of your own, but if you end up recreating a bar design that is similar to a standard bar style, you are more than likely losing subtleties that have been added and perfected over the years in the standard implementations. Instead, consider using the many customization APIs to tweak the standard bar styles to fit your app’s design.

ProMotion Support

LNPopupController fully supports ProMotion on iPhone and iPad.

For iPhone 13 Pro and above, you need to add the CADisableMinimumFrameDurationOnPhone key to your Info.plist and set it to true. See Optimizing ProMotion Refresh Rates for iPhone 13 Pro and iPad Pro for more information. LNPopupController will log a single warning message in the console if this key is missing, or is set to false.

Interaction Gesture Recognizer

LNPopupContentView exposes access to the popup interaction gesture recognizer in the way of the popupInteractionGestureRecognizer property. This gesture recognizer is shared between opening the popup content, by panning the popup bar up (when the popup bar is closed), and closing the popup content, by panning the popup content view (when the popup bar is open).

When opening the popup, the system queries the viewForPopupInteractionGestureRecognizer property of the popup content view controller to determine to which view to add the interaction gesture recognizer. By default, the property returns the controller's root view. Override the property's getter to change this behavior.

You can implement the delegate of the interaction gesture recognizer in order to influence its behavior, such as preventing popup interaction when the user is interacting with other controls or views inside the popup content.

Caution

If you disable the gesture recognizer after opening the popup, you must monitor the state of the popup and reenable the gesture recognizer once closed by the user or through code. Instead, consider implementing the gesture recognizer's delegate and providing custom logic to disable the interaction.

Full Right-to-Left Support

The framework has full right-to-left support.

By default, the popup bar will follow the system's user interface layout direction, but will preserve the bar button items' order. To customize this behavior, modify the popup bar's semanticContentAttribute and barItemsSemanticContentAttribute properties.

Accessibility

The framework supports accessibility and will honor accessibility labels, hints and values. By default, the accessibility label of the popup bar is the title and subtitle provided by the popup item.

To modify the accessibility label and hint of the popup bar, set the accessibilityLabel and accessibilityHint properties of the LNPopupItem object of the popup content view controller.

demoVC.popupItem.accessibilityLabel = NSLocalizedString("Custom popup bar accessibility label", comment: "")
demoVC.popupItem.accessibilityHint = NSLocalizedString("Custom popup bar accessibility hint", comment: "")

To add accessibility labels and hints to buttons, set the accessibilityLabel and accessibilityHint properties of the UIBarButtonItem objects.

let upNext = UIBarButtonItem(image: UIImage(named: "next"), style: .plain, target: self, action: #selector(nextItem))
upNext.accessibilityLabel = NSLocalizedString("Up Next", comment: "")
upNext.accessibilityHint = NSLocalizedString("Double tap to show up next list", comment: "")

To modify the accessibility label and hint of the popup close button, set the accessibilityLabel and accessibilityHint properties of the LNPopupCloseButton object of the popup container view controller.

tabBarController?.popupContentView.popupCloseButton.accessibilityLabel = NSLocalizedString("Custom popup close button accessibility label", comment: "")
tabBarController?.popupContentView.popupCloseButton.accessibilityHint = NSLocalizedString("Custom popup close button accessibility hint", comment: "")

To modify the accessibility label and value of the popup bar progress view, set the accessibilityProgressLabel and accessibilityProgressValue properties of the LNPopupItem object of the popup content view controller.

demoVC.popupItem.accessibilityImageLabel = NSLocalizedString("Custom image label", comment: "")
demoVC.popupItem.accessibilityProgressLabel = NSLocalizedString("Custom accessibility progress label", comment: "")
demoVC.popupItem.accessibilityProgressValue = "\(accessibilityDateComponentsFormatter.stringFromTimeInterval(NSTimeInterval(popupItem.progress) * totalTime)!) \(NSLocalizedString("of", comment: "")) \(accessibilityDateComponentsFormatter.stringFromTimeInterval(totalTime)!)"

Notes

  • Legacy non-translucent tab bar and toolbars are not supported and can cause visual artifacts or layout glitches. Apple has many problem with such bars, and supporting those is not a priority for LNPopupController.
    • The correct way to achieve an opaque bar is to use the UIBarAppearance.configureWithOpaqueBackground() API, which is supported by LNPopupController.
  • Manually setting bottom bar properties, such as setting a tab bar’s or a toolbar’s isHidden = true is explicitly discouraged by Apple and not supported by the framework; it will lead to undefined behavior by the framework.

Acknowledgements

The framework uses:

Additionally, the demo project uses:

lnpopupcontroller's People

Contributors

aregler avatar cbpowell avatar codeeagle avatar colinmorelli avatar coolstar avatar fruitcoder avatar funkenstrahlen avatar idevelopper avatar joshluongo avatar juliensaad avatar leonatan avatar longhanks avatar louisdh avatar mosheberman avatar tomaszpieczykolan avatar wimbledon avatar zzzworm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lnpopupcontroller's Issues

UIPanGestureRecognizer from external view

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?

Completion block is called twice when calling presentPopupBarWithContentViewController:openPopup:animated:completion:

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.

setNeedsStatusBarAppearanceUpdate() has no effect

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.

o4wiaxrekp

Submitting to iTC without modifying info.plist causes an error

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.

Content controller is displaying under the navigation bar

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…

Opening LNPopupController programmatically gives me a "see through" window

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?

Issue with bottomLayoutGuide

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:

ezgif com-optimize 4
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!

Issues with UI adaptivity

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)

screen shot 2015-11-11 at 9 38 51 am

screen shot 2015-11-11 at 9 38 23 am

API to open popup view controller

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.

Technique for dismissing TableView `contentViewController` onDrag

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.

Current attempt

    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
    }

Bottom docking view should respect tabBar.isHidden property

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

Status Bar + UINavigationController doesn't play nicely.

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.

Info.plist is missing CFBundleShortVersionString

I can not submit an app using LNPopupController via Carthage as it is missing the CFBundleShortVersionString in Info.plist of LNPopupController.

screen shot 2016-01-09 at 11 53 03

How can I fix that? Is this an error on my side or can this be done via the Carthage package automatically so it is fixed for everyone using this?

Popup Content Controller with Navigation bar - UI issue

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:
1

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:

snappyapp snappyapp today at 3 59 35 pm

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:
2 3

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 ✌️

Error not Loaded

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 ?

Swipe Gesture Recognizer

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.

Changing background color does not work

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.

screen shot 2016-01-29 at 14 22 36

Add coverart image to minified player

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?

'popupBar' adjusting for 'bottomDockingView' only after presenting 'contentViewController'

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.


##### When presenting the `contentViewController` for the very first time

first_bar


##### After calling `presentPopupBarWithContentViewController` then closing it

second_bar


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.

Framework not found

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.

crash when trying to customise LNPopupBar appearance

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?

Crash when title or subtitle nil

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 :)

Change player to minified state via code

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?

I need an hasBeenMinified() delegate method

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 UINavigationControllers. 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.

LNPopupController goes behind UINavigationBar

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];

Title and subtitle doesn't appear in bar.

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)

You can reproduce in the example project.
simulator screen shot 2 feb 2016 15 34 49

Having big problems when using with UITabBarController that has more than 4 tabs

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:

  1. In the example app open Main.storyboard and add one more tab to the tab bar controller to make 5 tabs in total
  2. Compile and launch on iPad Air2 iOS9 simulator
  3. When the LNPopupController is docked change the screen size to 50/50

Result:
The LNPopupController ends up being an additional tab of the tab bar controller

Memory leak because of timer?

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?

Unwanted animation of popup controller's view hierarchy

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.

ParagraphStyle support

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}];

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.