Code Monkey home page Code Monkey logo

xlactioncontroller's Introduction

XLActionController

Build status Platform iOS Swift 5 compatible Carthage compatible CocoaPods compatible License: MIT

By XMARTLABS.

XLActionController is an extensible library to quickly create any custom action sheet controller.

Examples

The action sheet controllers shown above were entirely created using XLActionController and are included in the Examples. To run the Example project: clone XLActionController repository, open XLActionController workspace and run the Example project.

The code snippet below shows how to present the Tweetbot action sheet controller:

let actionController = TweetbotActionController()

actionController.addAction(Action("View Details", style: .default, handler: { action in
  // do something useful
}))
actionController.addAction(Action("View Retweets", style: .default, handler: { action in
  // do something useful
}))
actionController.addAction(Action("View in Favstar", style: .default, handler: { action in
  // do something useful
}))
actionController.addAction(Action("Translate", style: .default, executeImmediatelyOnTouch: true, handler: { action in
  // do something useful
}))

actionController.addSection(Section())
actionController.addAction(Action("Cancel", style: .cancel, handler:nil))

present(actionController, animated: true, completion: nil)

As you may have noticed, the library usage looks pretty similar to UIAlertController.

Actions' handlers are executed after the alert controller is dismissed from screen. If you want, you can change this passing true to the action's constructor to the argument executeImmediatelyOnTouch.

Behind the scenes XLActionController uses a UICollectionView to display the action sheet.

Usage

First create a custom action sheet view controller by extending from the ActionController generic class. For details on how to create a custom action sheet controller look at the Extensibility section.

For instance, let's suppose we've already created TwitterActionController.

// Instantiate custom action sheet controller
let actionSheet = TwitterActionController()
// set up a header title
actionSheet.headerData = "Accounts"
// Add some actions, note that the first parameter of `Action` initializer is `ActionData`.
actionSheet.addAction(Action(ActionData(title: "Xmartlabs", subtitle: "@xmartlabs", image: UIImage(named: "tw-xmartlabs")!), style: .default, handler: { action in
   // do something useful
}))
actionSheet.addAction(Action(ActionData(title: "Miguel", subtitle: "@remer88", image: UIImage(named: "tw-remer")!), style: .default, handler: { action in
   // do something useful
}))
// present actionSheet like any other view controller
present(actionSheet, animated: true, completion: nil)

As the code above illustrates, there are no relevant differences compared to the UIAlertController API.

The main difference is that XLActionController works with any header data type and not only the standard UIAlertController title and message properties. Similarly XLActionController's Action works with any data Type and not only the title string.

// XLActionController:
xlActionController.headerData = SpotifyHeaderData(title: "The Fast And The Furious Soundtrack Collection", subtitle: "Various Artists", image: UIImage(named: "sp-header-icon")!)

// vs UIAlertController:
uiActionController.title = "The Fast And The Furious Soundtrack Collection" // no way to pass an image
uiActionController.message = "Various Artists"
// XLActionController:
let xlAction = Action(ActionData(title: "Save Full Album", image: UIImage(named: "sp-add-icon")!), style: .default, handler: { action in })
// notice that we are able to pass an image in addition to the title
xlActionController.addAction(xlAction)

// vs UIAlertController:
let uiAction = UIAlertAction(title: "Xmartlabs", style: .default, handler: { action in }))
uiActionController.addAction(uiAction)

This can be accomplished because XLActionController is a generic type.

Another important difference is that XLActionController provides a way to add action sections as illustrated in the code below:

  actionController.addSection(Section())

and also each section has a data property. This property is generic, so that it can hold any type. This data will be used to create this section's header view.

let section = actionController.addSection(Section())
section.data = "String" // assuming section data Type is String

Each section contains a set of actions. We typically use sections to show a header view above a set of actions.

Extensibility

ActionController uses a UICollectionView to show actions and headers on screen. Actions will be rendered as instances of UICollectionViewCell. You can use your own subclass of UICollectionViewCell by specifying it in the action controller declaration. Additionally, ActionController allows you to specify a global header and a section header. Headers are shown as collection view's supplementary views.

The ActionController class is a generic type that works with any cell, header, section header type and its associated data types.

Create your custom action sheet controller

XLActionController provides extension points to specify a whole new look and feel to our custom sheet controller and to tweak present and dismiss animations. Let's see an example:

// As first step we should extend the ActionController generic type
public class PeriscopeActionController: ActionController<PeriscopeCell, String, PeriscopeHeader, String, UICollectionReusableView, Void> {

    // override init in order to customize behavior and animations
    public override init(nibName nibNameOrNil: String? = nil, bundle nibBundleOrNil: Bundle? = nil) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        // customizing behavior and present/dismiss animations
        settings.behavior.hideOnScrollDown = false
        settings.animation.scale = nil
        settings.animation.present.duration = 0.6
        settings.animation.dismiss.duration = 0.5
        settings.animation.dismiss.options = .curveEaseIn
        settings.animation.dismiss.offset = 30

        // providing a specific collection view cell which will be used to display each action, height parameter expects a block that returns the cell height for a particular action.
        cellSpec = .nibFile(nibName: "PeriscopeCell", bundle: Bundle(for: PeriscopeCell.self), height: { _ in 60})
        // providing a specific view that will render each section header.
        sectionHeaderSpec = .cellClass(height: { _ in 5 })
        // providing a specific view that will render the action sheet header. We calculate its height according the text that should be displayed.
        headerSpec = .cellClass(height: { [weak self] (headerData: String) in
            guard let me = self else { return 0 }
            let label = UILabel(frame: CGRect(x: 0, y: 0, width: me.view.frame.width - 40, height: CGFloat.greatestFiniteMagnitude))
            label.numberOfLines = 0
            label.font = .systemFontOfSize(17.0)
            label.text = headerData
            label.sizeToFit()
            return label.frame.size.height + 20
        })

        // once we specify the views, we have to provide three blocks that will be used to set up these views.
        // block used to setup the header. Header view and the header are passed as block parameters
        onConfigureHeader = { [weak self] header, headerData in
            guard let me = self else { return }
            header.label.frame = CGRect(x: 0, y: 0, width: me.view.frame.size.width - 40, height: CGFloat.greatestFiniteMagnitude)
            header.label.text = headerData
            header.label.sizeToFit()
            header.label.center = CGPoint(x: header.frame.size.width  / 2, y: header.frame.size.height / 2)
        }
        // block used to setup the section header
        onConfigureSectionHeader = { sectionHeader, sectionHeaderData in
            sectionHeader.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
        }
        // block used to setup the collection view cell
        onConfigureCellForAction = { [weak self] cell, action, indexPath in
            cell.setup(action.data, detail: nil, image: nil)
            cell.separatorView?.isHidden = indexPath.item == self!.collectionView.numberOfItems(inSection: indexPath.section) - 1
            cell.alpha = action.enabled ? 1.0 : 0.5
            cell.actionTitleLabel?.textColor = action.style == .destructive ? UIColor(red: 210/255.0, green: 77/255.0, blue: 56/255.0, alpha: 1.0) : UIColor(red: 0.28, green: 0.64, blue: 0.76, alpha: 1.0)
        }
    }
}

ActionController type declaration:

public class ActionController<ActionViewType: UICollectionViewCell, ActionDataType, HeaderViewType: UICollectionReusableView, HeaderDataType, SectionHeaderViewType: UICollectionReusableView, SectionHeaderDataType>

When extending ActionController we must specify the following view types ActionViewType, HeaderViewType, SectionHeaderViewType. These types are the cell type used to render an action, the view used to render the action sheet header and the view used to render the section header.

Each view type has its associated data: ActionDataType, HeaderDataType, SectionHeaderDataType respectively.

If your custom action sheet doesn't have a header view we can use UICollectionReusableView as HeaderViewType and Void as HeaderDataType. If it doesn't have a section header view you can use UICollectionReusableView as SectionHeaderViewType and Void as SectionHeaderDataType.

The code below shows how we specify these types for the action controllers provided in the example project:

class PeriscopeActionController: ActionController<PeriscopeCell, String, PeriscopeHeader, String, UICollectionReusableView, Void> { ... } // doesn't need to show a section header
class SpotifyActionController: ActionController<SpotifyCell, ActionData, SpotifyHeaderView, SpotifyHeaderData, UICollectionReusableView, Void> { ... } // doesn't need to show a section header
class TwitterActionController: ActionController<TwitterCell, ActionData, TwitterActionControllerHeader, String, UICollectionReusableView, Void> { ... } // doesn't need to show a section header
class YoutubeActionController: ActionController<YoutubeCell, ActionData, UICollectionReusableView, Void, UICollectionReusableView, Void>

Tweaking default style and animation parameters

By following the previous section steps you should already be able to play with your custom action controller. It happens quite often that we need some other customization such as zooming out the presenting view, changing the status bar color or customizing the default present and dismiss animation.

ActionController class defines the settings property of type ActionSheetControllerSettings to tweak all these.

UICollectionView's behavior

// Indicates if the action controller must be dismissed when the user taps the background view. `true` by default.
settings.behavior.hideOnTap: Bool
// Indicates if the action controller must be dismissed when the user scrolls down the collection view. `true` by default.
settings.behavior.hideOnScrollDown: Bool
// Indicates if the collectionView's scroll is enabled. `false` by default.
settings.behavior.scrollEnabled: Bool
// Controls whether the collection view scroll bounces past the edge of content and back again. `false` by default.
settings.behavior.bounces: Bool
// Indicates if the collection view layout will use UIDynamics to animate its items. `false` by default.
settings.behavior.useDynamics: Bool
// Determines whether the navigation bar is hidden when action controller is being presented. `true` by default
settings.hideCollectionViewBehindCancelView: Bool

UICollectionView Style

// Margins between the collection view and the container view's margins. `0` by default
settings.collectionView.lateralMargin: CGFloat
// Cells height when UIDynamics is used to animate items. `50` by default.
settings.collectionView.cellHeightWhenDynamicsIsUsed: CGFloat

Animation settings

Struct that contains all properties related to presentation & dismissal animations

// Used to scale the presenting view controller when the action controller is being presented. If `nil` is set, then the presenting view controller won't be scaled. `(0.9, 0.9)` by default.
settings.animation.scale: CGSize? = CGSize(width: 0.9, height: 0.9)

Present animation settings

// damping value for the animation block. `1.0` by default.
settings.animation.present.damping: CGFloat
// delay for the animation block. `0.0` by default.
settings.animation.present.delay: TimeInterval
// Indicates the animation duration. `0.7` by default.
settings.animation.present.duration: TimeInterval
// Used as `springVelocity` for the animation block. `0.0` by default.
settings.animation.present.springVelocity: CGFloat
// Present animation options. `UIViewAnimationOptions.curveEaseOut` by default.
settings.animation.present.options: UIViewAnimationOptions

Dismiss animation settings

// damping value for the animation block. `1.0` by default.
settings.animation.dismiss.damping: CGFloat
// Used as delay for the animation block. `0.0` by default.
settings.animation.dismiss.delay: TimeInterval
// animation duration. `0.7` by default.
settings.animation.dismiss.duration: TimeInterval
// springVelocity for the animation block. `0.0` by default
settings.animation.dismiss.springVelocity: CGFloat
// dismiss animation options. `UIViewAnimationOptions.curveEaseIn` by default
settings.animation.dismiss.options: UIViewAnimationOptions

StatusBar Style

// Indicates if the status bar should be visible or hidden when the action controller is visible. Its default value is `true`
settings.statusBar.showStatusBar: Bool
// Determines the style of the deviceโ€™s status bar when the action controller is visible. `UIStatusBarStyle.LightContent` by default.
settings.statusBar.style: UIStatusBarStyle
// Determines whether the action controller takes over control of status bar appearance from the presenting view controller. `true` by default.
settings.statusBar.modalPresentationCapturesStatusBarAppearance: Bool

Cancel view style

Sometimes we need to show a cancel view below the collection view. This is the case of the SpotifyActionController. These properties have nothing to do with the actions added to an action Controller nor with the actions with .Cancel as style value.

 // Indicates if the cancel view is shown. `false` by default.
settings.cancelView.showCancel: Bool
 // Cancel view's title. "Cancel" by default.
settings.cancelView.title: String?
 // Cancel view's height. `60` by default.
settings.cancelView.height: CGFloat
 // Cancel view's background color. `UIColor.black.withAlphaComponent(0.8)` by default.
settings.cancelView.backgroundColor: UIColor
// Indicates if the collection view is partially hidden by the cancelView when it is pulled down.
settings.cancelView.hideCollectionViewBehindCancelView: Bool

Advanced animations

If tweaking previous settings is not enough to make the animations work like you want, XLActionController allows you to change the present/dismiss animation by overriding some functions.

Presentation

open func presentView(_ presentedView: UIView, presentingView: UIView, animationDuration: Double, completion: ((_ completed: Bool) -> Void)?)

The function above is responsible for making the present animation. It encapsulates how the presentation is performed and invokes onWillPresentView, performCustomPresentationAnimation and onDidPresentView to allow you to change a specific point of the animation.

Typically we don't need to override presentView function because overriding either onWillPresentView, performCustomPresentationAnimation or onDidPresentView is enough.

open func onWillPresentView()

onWillPresentView is called before the animation block starts. Any change here won't be animated. It's intended to set the initial animated properties values.

open func performCustomPresentationAnimation(_ presentedView: UIView, presentingView: UIView)

performCustomPresentationAnimation is called from within the main animation block.

open func onDidPresentView()

After the present animation is completed, presentView calls onDidPresentView from within completion callback.

onWillPresentView, performCustomPresentationAnimation, onDidPresentView won't be invoked if you override presentView implementation.

Dismissal

Dismissal animation can be customized in the same way as presentation animation.

open func dismissView(_ presentedView: UIView, presentingView: UIView, animationDuration: Double, completion: ((_ completed: Bool) -> Void)?)

The function above is responsible for making the dismissal animation. It encapsulates how the dismissal animation is performed and invokes onWillDismissView, performCustomDismissingAnimation and onDidDismissView to allow you to change an specific point of the animation.

Typically we don't need to override dismissView method because overriding either onWillDismissView, performCustomDismissingAnimationoronDidDismissView` is enough.

open func onWillDismissView()

Overrides onWillDismissView to perform any set up before the animation begins.

open func performCustomDismissingAnimation(_ presentedView: UIView, presentingView: UIView)

performCustomDismissingAnimation function is invoked from within the main animation block.

open func onDidDismissView()

After the dismissal animation completes, dismissView calls onDidDismissView from within completion callback.

onWillDismissView, performCustomDismissingAnimation, onDidDismissView won't be invoked if you override dismissView implementation.

To show how simple and powerful XLActionController is and give several examples of how to extend ActionController we have mimicked the Skype, Tweetbot, Twitter, Youtube, Periscope and Spotify action controllers.

Requirements

  • iOS 9.3+
  • Xcode 10.2+
  • Swift 5.0+

Getting involved

  • If you want to contribute please feel free to submit pull requests.
  • If you have a feature request please open an issue.
  • If you found a bug or need help please check older issues before submitting an issue.

If you use XLActionController in your app we would love to hear about it! Drop us a line on twitter.

Installation

CocoaPods

CocoaPods is a dependency manager for Cocoa projects.

Specify XLActionController into your project's Podfile:

source 'https://github.com/CocoaPods/Specs.git'
use_frameworks!

target '<Your App Target>' do
  # This will install just the library's core, won't include any examples
  pod 'XLActionController'

  # Uncomment depending on the examples that you want to install
  #pod 'XLActionController/Periscope'
  #pod 'XLActionController/Skype'
  #pod 'XLActionController/Spotify'
  #pod 'XLActionController/Tweetbot'
  #pod 'XLActionController/Twitter'
  #pod 'XLActionController/Youtube'
end

Then run the following command:

$ pod install

Carthage

Carthage is a simple, decentralized dependency manager for Cocoa.

Specify XLActionController into your project's Carthage:

github "xmartlabs/XLActionController" ~> 5.1.0

Manually as Embedded Framework

Clone XLActionController as a git submodule by running the following command from your project root git folder.

$ git submodule add https://github.com/xmartlabs/XLActionController.git

Open XLActionController folder that was created by the previous git submodule command and drag the XLActionController.xcodeproj into the Project Navigator of your application's Xcode project.

Select the XLActionController.xcodeproj in the Project Navigator and verify the deployment target matches with your application deployment target.

Select your project in the Xcode Navigation and then select your application target from the sidebar. Next select the "General" tab and click on the + button under the "Embedded Binaries" section.

Select XLActionController.framework and we are done!

Authors

License

XLActionController is released under MIT license and copyrighted by Xmartlabs SRL.

xlactioncontroller's People

Contributors

andrew-muzz avatar bcylin avatar cecipirotto avatar charliewilliams avatar ctrl-x avatar dmorrow avatar enrigalmig avatar erikbasargin avatar erneestoc avatar loryhuz avatar m-revetria avatar maryom avatar mats-claassen avatar migrant avatar mohammadsuhail98 avatar mohpor avatar mtnbarreto 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xlactioncontroller's Issues

Swift 3.0 Pod Support

Hi @m-revetria
Just a reminder: The #24 has been merged with master and effectively updated this lib to Swift 3, but podspec and a tag is required to make it available through cocoapods.

Thanks again,
M.

Support for multiple UIColectionViewCells

Not really an issue, more like a suggestion for improvement.
I have been struggling with trying to figure out how to use multiple UIColectionViewCells classes on a single action sheet.

For example, if I wanted a specific view at index N, with a height different from the other cells. Maybe a Decoration View would be more appopriate?

No repositioning for in-call status

XLActionController version: 4.0.0
Xcode version: 9.1
iOS version: 11.1

The problem occurs every time on every iOS device except iPhone X. Last XLActionController's cell is cut when in-call status bar is visible. Please check attached screenshot.

simulator screen shot - iphone se - 2017-11-11 at 14 55 46

Actionsheet Style

is there any difference in selecting any of the style
public enum ActionStyle {
case Default
case Cancel
case Destructive
}

because i don't think above struct used anywhere

Swift 4 Release?

Hello, thank you for the great library! Is a Swift 4 release coming within the next few weeks? I see there is a swift4 branch but would love to point directly to the latest release for Swift 4 support now that Swift 4 is officially released.

Objective-C compatible

This framework is not usable in objective C. Is it possible to add a @objc prefix before main classes? Otherwise the only accessible classes are those which are subclasses of NSObjects.

A Swift class or protocol must be marked with the @objc attribute to be accessible and usable in Objective-C.

HeaderView not part of the action sheet.

Heyo, I'm having trouble trying to get a proper header view working. I've implemented a header view, with code shown below. I've also included a screenshot:
screen shot 2016-11-23 at 1 09 03 pm
The header has a UITextField and UIImageView in it & I want the header to be the same color as the regular actions, like the cancel. But, it keeps getting darkened as I think the actionController doesn't know that the header is there and treating it as part of the background. What can I do about this? I'm following the Spotify example for making header but it isn't working out with the YouTube type cells.
My custom header view:

class ndJHeaderView: UICollectionReusableView {
    open lazy var imageView: UIImageView = {
        let imageView = UIImageView(frame: CGRect.zero)
        imageView.image = UIImage(named: "plusIcon")
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.contentMode = .scaleAspectFit
        imageView.sizeToFit()
        
        return imageView
    }()
    
    open lazy var textField: UITextField = {
        let textField = UITextField(frame: CGRect.zero)
        textField.textColor = UIColor(white: 0.098, alpha: 1.0)
        textField.translatesAutoresizingMaskIntoConstraints = false
        textField.sizeToFit()
        
        return textField
    }()
    
    public override init(frame: CGRect) {
        super.init(frame: frame)
        initialize()
    }
    
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    open override func awakeFromNib() {
        super.awakeFromNib()
        initialize()
    }
    
    func initialize() {
        self.translatesAutoresizingMaskIntoConstraints = false
        self.backgroundColor = UIColor.black.withAlphaComponent(0.0)
        self.addSubview(imageView)
        self.addSubview(textField)
        
        let views: [String : Any] = ["ico": imageView, "title": textField]
        let metrics = [ "icow": 40, "icoh": 40 ]
        let options = NSLayoutFormatOptions()
        self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[ico(icow)]-10@750-[title]-25-|", options: [.alignAllCenterY], metrics: metrics, views: views))
        self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-(>=25)-[title]", options: [.alignAllCenterY], metrics: metrics, views: views))
        self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[ico(icoh)]", options: options, metrics: metrics, views: views))
    }
}
  • Environment: XLActionController v3.0.1, Xcode 8.1 and iOS 10.1 version you are using.

ActionCell.xib doesn't have an outlet for actionTitleLabelConstraintToContainer or actionTitleLabelConstraintToImageView

XLActionController 3.0.0, XCode 8, iOS9

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<XLActionController.ActionCell 0x7ff32660de50> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key actionTitleLabelConstraintToContainer.'

It appears that actionTitleLabelConstraintToContainer and actionTitleLabelConstraintToImageView don't have outlets in ActionCell.swift.

Custom cancel button

Your component is great!

I just regret that we can't customize the cancel button.
In the example of spotify, if you want to put a button with title in black (white by default, you can not modify it) and add margins to the left and right), how can you do it?

Thank you in advance

Reload number of actions

Hi,

Is it a possibility to reload the number of actions when the action sheet is show ? For example, I wait for a web service call to hide a row.

Thx

Share Extension issue (App-Extension-Safe API Only)

I recently updated my pods to migrate to Swift 4 and saw that XLActionController has recently received an update that introduces Swift 4 support.

Everything works as expected but when I use it in a project that has a share extension I get a compile error that notes UIApplication.shared is not available.

This is likely caused by a commit for #66 where support for RTL designs was added with the function isRTL() in DynamicCollectionViewFlowLayout.swift. (4664dee)

I know that other frameworks often detect if UIApplication.shared is available and use other APIs if it is not.

When I set the "Only App-Extension-Safe API" build setting to "NO" for the XLActionController pod target the compile error is gone, but this is only a temporary solution because it resets with every pod update.

StatusBar hidden on iOS 10

Hi,

Just one little bug on iOS 10, the "status bar hidden" config doesn't work.
settings.statusBar.showStatusBar = false

Thx

CANCEL button layout is broken in 4.0.1

Recently I have updated XLActionController from 4.0.0 to 4.0.1 and found out that now there is a large gap between CANCEL button and first action item above it. It is observable on both the iPhone 8 and iPhone X (the gap is smaller on iPhone X) . I'm almost sure that it's the recently added support for iPhone X to blame - use of the safe area offset somehow messed up collection view content size/inset.
If CANCEL button is disabled - action sheet renders just fine.

P.S. I was forced to revert back to 4.0.0 and use my own two-lines fix to support iPhone X...

Environment: XLActionController 4.0.1, Xcode 9.3, Swift 4.1, iOS 11.0 (simulator), iOS 11.3 (iPhone X).

Thanks.

iOS 11 Crash !

An error occurred using iOS 11 devices, Please update your library.
The problem caused on this line.
return animator.items(in: rect) as? [UICollectionViewLayoutAttributes]

And the error log is
Fatal error: NSArray element failed to match the Swift Array Element type

Looks like a problem with casting animator.items

Example app crashes

Example app crashes in this method in DynamicCollectionViewFlowLayout:

override open func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let animator = dynamicAnimator else {
return super.layoutAttributesForElements(in: rect)
}

    return animator.items(in: rect) as? [UICollectionViewLayoutAttributes]
}

Here's the console log:
fatal error: NSArray element failed to match the Swift Array Element type
2017-10-23 16:27:45.074075-0400 Example[18698:29187926] fatal error: NSArray element failed to match the Swift Array Element type
(lldb)

Using XCode 9 with Swift 4. Choose Tweetbot from the tableview sample app options.

how to handle a dismiss function

is it possible to add? a dismiss handler to addAction function??

what i want to do is that i want to do someting after dismiss actionController...

Strange bug displaying XLActionController

Getting an error while attempting to display XLActionController, problem seems to arise below

// in DynamicCollectionViewFlowLayout
    override public func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath?) -> UICollectionViewLayoutAttributes? {
        guard let indexPath = indexPath else {
            return nil
        }

        guard let animator = dynamicAnimator else {
           --> Error thrown: return super.layoutAttributesForItemAtIndexPath(indexPath)
        }

        return animator.layoutAttributesForCellAtIndexPath(indexPath) ?? setupAttributesForIndexPath(indexPath)
    }

    override public func prepareForCollectionViewUpdates(updateItems: [UICollectionViewUpdateItem]) {
        super.prepareForCollectionViewUpdates(updateItems)

        updateItems.filter { $0.updateAction == .Insert && layoutAttributesForItemAtIndexPath($0.indexPathAfterUpdate) == nil } .forEach {
            setupAttributesForIndexPath($0.indexPathAfterUpdate)
        }
    }

// in ActionController.swift
// calculate content Inset
collectionView.layoutSubviews()
if let section = _sections.last where !settings.behavior.useDynamics {
            let lastSectionIndex = _sections.count - 1
 --> Error thrown: let layoutAtts = collectionViewLayout.layoutAttributesForItemAtIndexPath(NSIndexPath(forItem: section.actions.count - 1, inSection: hasHeader() ? lastSectionIndex + 1 : lastSectionIndex))
            contentHeight = layoutAtts!.frame.origin.y + layoutAtts!.frame.size.height
}

The layoutAtts causes a crash, not sure why. Editing contentHeight to hard coded values seems to resolve it...

Is there an alternate way to set the contentHeight and display position in place of depending on the layout attributes?

  • Using XCode 7.3
  • Swift 2.2

crash on rotation

I'm getting a crash on rotation at line 49 in ActionCell.swift.
actionTitleLabelConstraintToImageView?.priority = UILayoutPriorityDefaultHigh

the error I'm getting is:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Mutating a priority from required to not on an installed constraint (or vice-versa) is not supported. You passed priority 1000 and the existing priority was 1000.'
*** First throw call stack:

Incorrect insets in Spotify Example

Before submitting issues ...

  • Make sure you are using XLActionController latest release or master branch version.
  • Make sure your Xcode version is the latest stable one.
  • Check if the issue was already reported or fixed. We add labels to each issue in order to easily find related issues. If you found a match add a brief comment "I have the same problem" or "+1".

When submitting issues, please provide the following information to help maintainers to fix the problem faster:

  • Environment: XLActionController, Xcode and iOS version you are using.
  • In case of reporting errors, provide Xcode console output of stack trace or code compilation error.
  • Any other additional detail such as example code that you think it would be useful to understand, reproduce and solve the problem.

Xcode 8, iOS 10, latest XLActionController

It looks like the top inset in the Spotify Example are set too high (here's a screenshot after the tableView has been pulled down).

simulator screen shot 11-nov-2016 12 36 41 am

A simple fix right now looks like increasing the offset by the height of the header.

contentHeight = layoutAtts!.frame.origin.y + layoutAtts!.frame.size.height + 2 * (headerSpec?.height(headerData!))!

when calculating contentHeight.

I'd make a PR, however I've made lots of other changes to the examples, so it wouldn't be too useful: https://github.com/codeOfRobin/xlactionviewcontroller

110 errors - Xcode 8, Swift 3

Hello!

When I install XLActionController in my podfile and restart Xcode I get 110 errors. I thought it would be compatible with swift 3?

I tried it multiple times.

Do I have to specify branch?

Can we change the text or background color of individual Actions depending upon some condition?

  • Xcode 8 Swift 3 iOS 10.2
  • using YouTubeActionController

I have a situation where depending upon some condition I need to change either text or background color of an individual Action.

For eg. I have a list of books in which a book can be added to reading list and on tap of that I display action sheet where there are 4 actions. If that book is already added to reading list I have to show the reading list action in green color and if not added then default color.

Can this be possible? and if so then can you show me how to do it?
Thanks

clickable header

Hi,
Is there a simple way to make the header close the sheet when taped?

Thanks

Support for Swift 3.0

Just updated to Xcode 8 and have tons of compiler errors with the library. Support for Swift 3.0 would be great!

Use of unresolved identifier 'YoutubeActionController'?

Hi there,

Just got the pod and trying to play around with it. I keep getting "Use of unresolved identifier '...'", no matter which controller I try to instantiate, for example:

let actionsheet = YoutubeActionController()

I've imported the lib and all should be fine, however it's not. What to do?

Attempt to present <UIAlertController: 0x13c953a80> which is already presenting.

  • Environment: XLActionController (2.0), Xcode (7.3.1) and iOS version (9.3)

How do you present a UIAlertController during a click handler of an action?

Currently if you try to present an action (for Example 'Are you sure you want to delete'), then this error will occur:

Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior (<UIAlertController: 0x13c953a80>)

scrollViewDidScroll never called

I have created a controller that extend from ActionController and everything works fine, but im trying to use the scrollViewDidScroll but i can't detect the event when the user scroll.

i have implemented the delegate
collectionView.delegate = self
but the scrollViewDidScroll method never is called.

how can i use this method?? i need to change the scrollView indicator design.

No xlactioncontroller tag on stack overflow

It's weird, I can see the 'xlactioncontroller' tag coming from your link in github to stack overflow, but when I try to post a new question, it says that this 'xlactioncontroller' tag is a new tag.

And I would need some help:) Any idea on what's happening on stack overflow? Thanks!!

SkypeActionController ContextView background color

Hey, thanks for the great library. I'm using the out of the box Skype action controller, but it seems I can't change the background color without copying the source to my own project. Would be awesome, if it could be made changeable either from constructor or a class variable.

Skype dismiss speed

Xcode 7.3, iOS9, newest XLActionController.

Is there any way to alter the speed of dismissal of SkypeActionController? Changing the dismiss speed/velocity/damping in settings did not seem to do anything.

ActionController.swift collectionView:viewForSupplementaryElementOfKind not being called.

Environment: XLActionController v3.0.1, Xcode 8.1 and iOS 10.

I'm trying to make a custom header view but in testing, noticed it was not being added to the action sheet. After setting breakpoints, it seems as though my onConfigureHeader block in my actionController was not being called. Looking in ActionController.swift revealed that the method collectionView:viewForSupplementaryElementOfKind was not being called at all as part of the delegate. What would cause this? The following is what my actionController looks like:

`class ndJActionController: ActionController<ndJReusableActionCell, ActionData, ndJHeaderView, ndJActionHeaderData, UICollectionReusableView, Void> {

// override init in order to customize behavior and animations
public override init(nibName nibNameOrNil: String? = nil, bundle nibBundleOrNil: Bundle? = nil) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    
    collectionViewLayout.minimumLineSpacing = -0.5
    
    settings.behavior.hideOnScrollDown = false
    settings.animation.scale = nil
    settings.animation.present.duration = 0.6
    settings.animation.dismiss.duration = 0.6
    settings.animation.dismiss.offset = 30
    settings.animation.dismiss.options = .curveLinear
    
    cellSpec = .nibFile(nibName: "ndJActionCell", bundle: Bundle(for: ndJReusableActionCell.self), height: { _  in 46 })
    
    onConfigureCellForAction = { cell, action, indexPath in
        cell.setup(action.data?.title, detail: nil, image: action.data?.image)
        cell.alpha = action.enabled ? 1.0 : 0.5
        
        UIView.animate(withDuration: 0.30) {
        }
    }
    
    onConfigureHeader = { (header: ndJHeaderView, data: ndJActionHeaderData)  in
        header.imageView.image = data.image
        header.textField.placeholder = data.textFieldPlaceHolder
    }
}

required init?(coder aDecoder: NSCoder) {
    // Just call super. Probably could leave the fatalError code that was here since I don't think it'll ever be called, but oh whale ๐Ÿณ.
    super.init(coder: aDecoder)
}

}`

Add test suite for adding actions

Include tests to check that adding actions to the action controller is properly working. Right, it's natively supported adding actions before showing the action controller.

There is a workaround that allow the user to add more actions to the action controller after it was shown, take a look to this issue for reference on how to do it: #44. So this test suite may cover it.

Unnecessary insets on iOS 11

iOS 11 is inserting scroll view insets related to the safe area, which put more whitespace in the collection view than is necessary, pushing content off-screen and adding unnecessary scrolling.

I was able to correct this by adding the following to my subclass of ActionController:

if #available(iOS 11.0, *) {
  collectionView.contentInsetAdjustmentBehavior = .never
}

The code likely needs to be updated to account for the safe area changes, as well as the bottom area on iPhone X.

Segues not performing correctly

When I click on one of the skypeController cells where I have added a segue, it will perform the segue to another view controller but come back again in like 1 sec

Maximum Height

Hey guys,

Is there any way to apply a maximum height an action controller can have over the main view?

Thanks.

Undefined symbols for architecture armv7: "direct field offset forXLActionController.DynamicCollectionViewFlowLayout?

I am getting a build error

Undefined symbols for architecture armv7:
  "direct field offset for XLActionController.ActionController.(collectionViewLayout.storage in _A6CDD4E8E9CAF75D03A0E33C7BEC0AB2) : XLActionController.DynamicCollectionViewFlowLayout?", referenced from:
XLActionController.ActionController.collectionViewLayout.setter : XLActionController.DynamicCollectionViewFlowLayout in MenuViewControllerAnimatedTransitioning.o

XLActionController 3.0.1, XCode 8.2.1, Swift 3, Cocoapods 1.2.1

Other posts around this issue make it sound like an issue of subclassing a class that uses public lazy vars.
I am subclassing ActionController in order to update settings and onConfigureCellForAction

Creating Custom ActionController

Currently, I'm trying to combine the examples Spotify and Tweetbot to create my own custom ActionController like this:

new_group

I believe my current code should take care of this, but I'm not able to get the header view up and instead my code results in this:

screen shot 2018-02-26 at 9 10 06 pm

My current code looks like this:

screen shot 2018-02-26 at 9 18 10 pm

screen shot 2018-02-26 at 9 17 24 pm
screen shot 2018-02-26 at 9 17 37 pm

Does anyone know how I can get this to work the way I want?

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.