[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-6986":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":16,"stars30d":16,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":17,"rankGlobal":10,"rankLanguage":10,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":19,"topics":22,"createdAt":10,"pushedAt":10,"updatedAt":30,"readmeContent":31,"aiSummary":32,"trendingCount":16,"starSnapshotCount":16,"syncStatus":33,"lastSyncTime":34,"discoverSource":35},6986,"XLActionController","xmartlabs\u002FXLActionController","xmartlabs","Fully customizable and extensible action sheet controller written in Swift","",null,"Swift",3312,311,72,26,0,59.48,"MIT License",false,"master",true,[23,24,25,26,27,28,29],"carthage","cocoapods","ios","ios-ui","swift","swift-library","uialertcontroller","2026-06-12 04:00:31","![XLActionController](https:\u002F\u002Fraw.githubusercontent.com\u002Fxmartlabs\u002FXLActionController\u002Fmaster\u002FXLActionController.png)\n\n\u003Cp align=\"left\">\n\u003Ca href=\"https:\u002F\u002Ftravis-ci.org\u002Fxmartlabs\u002FXLActionController\">\u003Cimg src=\"https:\u002F\u002Ftravis-ci.org\u002Fxmartlabs\u002FXLActionController.svg?branch=master\" alt=\"Build status\" \u002F>\u003C\u002Fa>\n\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fplatform-iOS-blue.svg?style=flat\" alt=\"Platform iOS\" \u002F>\n\u003Ca href=\"https:\u002F\u002Fdeveloper.apple.com\u002Fswift\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fswift5-compatible-4BC51D.svg?style=flat\" alt=\"Swift 5 compatible\" \u002F>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FCarthage\u002FCarthage\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FCarthage-compatible-4BC51D.svg?style=flat\" alt=\"Carthage compatible\" \u002F>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fcocoapods.org\u002Fpods\u002FXLActionController\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fcocoapods\u002Fv\u002FXLActionController.svg\" alt=\"CocoaPods compatible\" \u002F>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fraw.githubusercontent.com\u002Fxmartlabs\u002FXLActionController\u002Fmaster\u002FLICENSE\">\u003Cimg src=\"http:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-MIT-blue.svg?style=flat\" alt=\"License: MIT\" \u002F>\u003C\u002Fa>\n\u003C!-- \u003Ca href=\"https:\u002F\u002Fcodebeat.co\u002Fprojects\u002Fgithub-com-xmartlabs-xlactioncontroller\">\u003Cimg alt=\"codebeat badge\" src=\"https:\u002F\u002Fcodebeat.co\u002Fbadges\u002F24f48197-136d-44cc-b072-6703644d13b6\" \u002F>\u003C\u002Fa> -->\n\u003C\u002Fp>\n\nBy [XMARTLABS](http:\u002F\u002Fxmartlabs.com).\n\n**XLActionController** is an extensible library to quickly create any custom action sheet controller.\n\n## Examples\n\n\u003Ctable>\n \u003Ctr>\n  \u003Ctd>\n    \u003Cimg src=\"Media\u002Fdemo_spotify.gif\" width=\"300\"\u002F>\n  \u003C\u002Ftd>\n  \u003Ctd>\n    \u003Cimg src=\"Media\u002Fdemo_twitter.gif\" width=\"300\"\u002F>\n  \u003C\u002Ftd>\n  \u003Ctd>\n    \u003Cimg src=\"Media\u002Fdemo_tweetbot.gif\" width=\"300\"\u002F>\n  \u003C\u002Ftd>\n \u003C\u002Ftr>\n \u003Ctr>\n  \u003Ctd>\n    \u003Cimg src=\"Media\u002Fdemo_periscope.gif\" width=\"300\"\u002F>\n  \u003C\u002Ftd>\n  \u003Ctd>\n    \u003Cimg src=\"Media\u002Fdemo_youtube.gif\" width=\"300\"\u002F>\n  \u003C\u002Ftd>\n  \u003Ctd>\n    \u003Cimg src=\"Media\u002Fdemo_skype.gif\" width=\"300\"\u002F>\n  \u003C\u002Ftd>\n \u003C\u002Ftr>\n \u003C\u002Ftable>\n\nThe action sheet controllers shown above were entirely created using XLActionController and are included in the [Examples](\u002FExample\u002FCustomActionControllers).\nTo run the Example project: clone XLActionController repository, open XLActionController workspace and run the Example project.\n\nThe code snippet below shows how to present the Tweetbot action sheet controller:\n\n```swift\nlet actionController = TweetbotActionController()\n\nactionController.addAction(Action(\"View Details\", style: .default, handler: { action in\n  \u002F\u002F do something useful\n}))\nactionController.addAction(Action(\"View Retweets\", style: .default, handler: { action in\n  \u002F\u002F do something useful\n}))\nactionController.addAction(Action(\"View in Favstar\", style: .default, handler: { action in\n  \u002F\u002F do something useful\n}))\nactionController.addAction(Action(\"Translate\", style: .default, executeImmediatelyOnTouch: true, handler: { action in\n  \u002F\u002F do something useful\n}))\n\nactionController.addSection(Section())\nactionController.addAction(Action(\"Cancel\", style: .cancel, handler:nil))\n\npresent(actionController, animated: true, completion: nil)\n```\n\nAs you may have noticed, the library usage looks pretty similar to UIAlertController.\n\nActions' 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`.\n\n> Behind the scenes XLActionController uses a UICollectionView to display the action sheet.\n\n## Usage\n\nFirst 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](#extensibility) section.\n\nFor instance, let's suppose we've already created [`TwitterActionController`](Example\u002FCustomActionControllers\u002FTwitter.swift).\n\n```swift\n\u002F\u002F Instantiate custom action sheet controller\nlet actionSheet = TwitterActionController()\n\u002F\u002F set up a header title\nactionSheet.headerData = \"Accounts\"\n\u002F\u002F Add some actions, note that the first parameter of `Action` initializer is `ActionData`.\nactionSheet.addAction(Action(ActionData(title: \"Xmartlabs\", subtitle: \"@xmartlabs\", image: UIImage(named: \"tw-xmartlabs\")!), style: .default, handler: { action in\n   \u002F\u002F do something useful\n}))\nactionSheet.addAction(Action(ActionData(title: \"Miguel\", subtitle: \"@remer88\", image: UIImage(named: \"tw-remer\")!), style: .default, handler: { action in\n   \u002F\u002F do something useful\n}))\n\u002F\u002F present actionSheet like any other view controller\npresent(actionSheet, animated: true, completion: nil)\n```\n\u003Cimg src=\"Media\u002Fdemo_twitter.gif\" width=\"200\"\u002F>\n\nAs the code above illustrates, there are no relevant differences compared to the UIAlertController API.\n\nThe main difference is that XLActionController works with any header data type and not only the standard UIAlertController `title` and `message` properties.\nSimilarly XLActionController's Action works with any data Type and not only the `title` string.\n\n```swift\n\u002F\u002F XLActionController:\nxlActionController.headerData = SpotifyHeaderData(title: \"The Fast And The Furious Soundtrack Collection\", subtitle: \"Various Artists\", image: UIImage(named: \"sp-header-icon\")!)\n\n\u002F\u002F vs UIAlertController:\nuiActionController.title = \"The Fast And The Furious Soundtrack Collection\" \u002F\u002F no way to pass an image\nuiActionController.message = \"Various Artists\"\n```\n\n```swift\n\u002F\u002F XLActionController:\nlet xlAction = Action(ActionData(title: \"Save Full Album\", image: UIImage(named: \"sp-add-icon\")!), style: .default, handler: { action in })\n\u002F\u002F notice that we are able to pass an image in addition to the title\nxlActionController.addAction(xlAction)\n\n\u002F\u002F vs UIAlertController:\nlet uiAction = UIAlertAction(title: \"Xmartlabs\", style: .default, handler: { action in }))\nuiActionController.addAction(uiAction)\n```\n\n> This can be accomplished because XLActionController is a generic type.\n\nAnother important difference is that XLActionController provides a way to add action sections as illustrated in the code below:\n\n```swift\n  actionController.addSection(Section())\n```\n\nand 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.\n\n```swift\nlet section = actionController.addSection(Section())\nsection.data = \"String\" \u002F\u002F assuming section data Type is String\n```\n\n> Each section contains a set of actions. We typically use sections to show a header view above a set of actions.\n\n\n## Extensibility\n\nActionController uses a UICollectionView to show actions and headers on screen. Actions will be rendered as instances of UICollectionViewCell. You can use\nyour 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.\n\nThe `ActionController` class is a generic type that works with any cell, header, section header type and its associated data types.\n\n### Create your custom action sheet controller\n\nXLActionController 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:\n\n```swift\n\u002F\u002F As first step we should extend the ActionController generic type\npublic class PeriscopeActionController: ActionController\u003CPeriscopeCell, String, PeriscopeHeader, String, UICollectionReusableView, Void> {\n\n    \u002F\u002F override init in order to customize behavior and animations\n    public override init(nibName nibNameOrNil: String? = nil, bundle nibBundleOrNil: Bundle? = nil) {\n        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)\n        \u002F\u002F customizing behavior and present\u002Fdismiss animations\n        settings.behavior.hideOnScrollDown = false\n        settings.animation.scale = nil\n        settings.animation.present.duration = 0.6\n        settings.animation.dismiss.duration = 0.5\n        settings.animation.dismiss.options = .curveEaseIn\n        settings.animation.dismiss.offset = 30\n\n        \u002F\u002F 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.\n        cellSpec = .nibFile(nibName: \"PeriscopeCell\", bundle: Bundle(for: PeriscopeCell.self), height: { _ in 60})\n        \u002F\u002F providing a specific view that will render each section header.\n        sectionHeaderSpec = .cellClass(height: { _ in 5 })\n        \u002F\u002F providing a specific view that will render the action sheet header. We calculate its height according the text that should be displayed.\n        headerSpec = .cellClass(height: { [weak self] (headerData: String) in\n            guard let me = self else { return 0 }\n            let label = UILabel(frame: CGRect(x: 0, y: 0, width: me.view.frame.width - 40, height: CGFloat.greatestFiniteMagnitude))\n            label.numberOfLines = 0\n            label.font = .systemFontOfSize(17.0)\n            label.text = headerData\n            label.sizeToFit()\n            return label.frame.size.height + 20\n        })\n\n        \u002F\u002F once we specify the views, we have to provide three blocks that will be used to set up these views.\n        \u002F\u002F block used to setup the header. Header view and the header are passed as block parameters\n        onConfigureHeader = { [weak self] header, headerData in\n            guard let me = self else { return }\n            header.label.frame = CGRect(x: 0, y: 0, width: me.view.frame.size.width - 40, height: CGFloat.greatestFiniteMagnitude)\n            header.label.text = headerData\n            header.label.sizeToFit()\n            header.label.center = CGPoint(x: header.frame.size.width  \u002F 2, y: header.frame.size.height \u002F 2)\n        }\n        \u002F\u002F block used to setup the section header\n        onConfigureSectionHeader = { sectionHeader, sectionHeaderData in\n            sectionHeader.backgroundColor = UIColor(white: 0.95, alpha: 1.0)\n        }\n        \u002F\u002F block used to setup the collection view cell\n        onConfigureCellForAction = { [weak self] cell, action, indexPath in\n            cell.setup(action.data, detail: nil, image: nil)\n            cell.separatorView?.isHidden = indexPath.item == self!.collectionView.numberOfItems(inSection: indexPath.section) - 1\n            cell.alpha = action.enabled ? 1.0 : 0.5\n            cell.actionTitleLabel?.textColor = action.style == .destructive ? UIColor(red: 210\u002F255.0, green: 77\u002F255.0, blue: 56\u002F255.0, alpha: 1.0) : UIColor(red: 0.28, green: 0.64, blue: 0.76, alpha: 1.0)\n        }\n    }\n}\n```\n\nActionController type declaration:\n```swift\npublic class ActionController\u003CActionViewType: UICollectionViewCell, ActionDataType, HeaderViewType: UICollectionReusableView, HeaderDataType, SectionHeaderViewType: UICollectionReusableView, SectionHeaderDataType>\n```\n\nWhen 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.\n\nEach view type has its associated data: ActionDataType, HeaderDataType, SectionHeaderDataType respectively.\n\n> If your custom action sheet doesn't have a header view we can use `UICollectionReusableView` as `HeaderViewType` and `Void` as `HeaderDataType`.\n> If it doesn't have a section header view you can use `UICollectionReusableView` as `SectionHeaderViewType` and `Void` as `SectionHeaderDataType`.\n\nThe code below shows how we specify these types for the action controllers provided in the example project:\n```swift\nclass PeriscopeActionController: ActionController\u003CPeriscopeCell, String, PeriscopeHeader, String, UICollectionReusableView, Void> { ... } \u002F\u002F doesn't need to show a section header\nclass SpotifyActionController: ActionController\u003CSpotifyCell, ActionData, SpotifyHeaderView, SpotifyHeaderData, UICollectionReusableView, Void> { ... } \u002F\u002F doesn't need to show a section header\nclass TwitterActionController: ActionController\u003CTwitterCell, ActionData, TwitterActionControllerHeader, String, UICollectionReusableView, Void> { ... } \u002F\u002F doesn't need to show a section header\nclass YoutubeActionController: ActionController\u003CYoutubeCell, ActionData, UICollectionReusableView, Void, UICollectionReusableView, Void>\n```\n\n### Tweaking default style and animation parameters\n\nBy following the previous section steps you should already be able to play with your custom action controller.\nIt 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.\n\n`ActionController` class defines the `settings` property of type `ActionSheetControllerSettings` to tweak all these.\n\n#### UICollectionView's behavior\n```swift\n\u002F\u002F Indicates if the action controller must be dismissed when the user taps the background view. `true` by default.\nsettings.behavior.hideOnTap: Bool\n\u002F\u002F Indicates if the action controller must be dismissed when the user scrolls down the collection view. `true` by default.\nsettings.behavior.hideOnScrollDown: Bool\n\u002F\u002F Indicates if the collectionView's scroll is enabled. `false` by default.\nsettings.behavior.scrollEnabled: Bool\n\u002F\u002F Controls whether the collection view scroll bounces past the edge of content and back again. `false` by default.\nsettings.behavior.bounces: Bool\n\u002F\u002F Indicates if the collection view layout will use UIDynamics to animate its items. `false` by default.\nsettings.behavior.useDynamics: Bool\n\u002F\u002F Determines whether the navigation bar is hidden when action controller is being presented. `true` by default\nsettings.hideCollectionViewBehindCancelView: Bool\n```\n\n#### UICollectionView Style\n\n```swift\n\u002F\u002F Margins between the collection view and the container view's margins. `0` by default\nsettings.collectionView.lateralMargin: CGFloat\n\u002F\u002F Cells height when UIDynamics is used to animate items. `50` by default.\nsettings.collectionView.cellHeightWhenDynamicsIsUsed: CGFloat\n```\n\n#### Animation settings\nStruct that contains all properties related to presentation & dismissal animations\n\n```swift\n\u002F\u002F 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.\nsettings.animation.scale: CGSize? = CGSize(width: 0.9, height: 0.9)\n```\n\n#### Present animation settings\n\n```swift\n\u002F\u002F damping value for the animation block. `1.0` by default.\nsettings.animation.present.damping: CGFloat\n\u002F\u002F delay for the animation block. `0.0` by default.\nsettings.animation.present.delay: TimeInterval\n\u002F\u002F Indicates the animation duration. `0.7` by default.\nsettings.animation.present.duration: TimeInterval\n\u002F\u002F Used as `springVelocity` for the animation block. `0.0` by default.\nsettings.animation.present.springVelocity: CGFloat\n\u002F\u002F Present animation options. `UIViewAnimationOptions.curveEaseOut` by default.\nsettings.animation.present.options: UIViewAnimationOptions\n```\n\n#### Dismiss animation settings\n\n```swift\n\u002F\u002F damping value for the animation block. `1.0` by default.\nsettings.animation.dismiss.damping: CGFloat\n\u002F\u002F Used as delay for the animation block. `0.0` by default.\nsettings.animation.dismiss.delay: TimeInterval\n\u002F\u002F animation duration. `0.7` by default.\nsettings.animation.dismiss.duration: TimeInterval\n\u002F\u002F springVelocity for the animation block. `0.0` by default\nsettings.animation.dismiss.springVelocity: CGFloat\n\u002F\u002F dismiss animation options. `UIViewAnimationOptions.curveEaseIn` by default\nsettings.animation.dismiss.options: UIViewAnimationOptions\n```\n\n#### StatusBar Style\n\n```swift\n\u002F\u002F Indicates if the status bar should be visible or hidden when the action controller is visible. Its default value is `true`\nsettings.statusBar.showStatusBar: Bool\n\u002F\u002F Determines the style of the device’s status bar when the action controller is visible. `UIStatusBarStyle.LightContent` by default.\nsettings.statusBar.style: UIStatusBarStyle\n\u002F\u002F Determines whether the action controller takes over control of status bar appearance from the presenting view controller. `true` by default.\nsettings.statusBar.modalPresentationCapturesStatusBarAppearance: Bool\n```\n\n#### Cancel view style\n\nSometimes we need to show a cancel view below the collection view. This is the case of the `SpotifyActionController`.\nThese properties have nothing to do with the actions added to an action Controller nor with the actions with .Cancel as style value.\n\n```swift\n \u002F\u002F Indicates if the cancel view is shown. `false` by default.\nsettings.cancelView.showCancel: Bool\n \u002F\u002F Cancel view's title. \"Cancel\" by default.\nsettings.cancelView.title: String?\n \u002F\u002F Cancel view's height. `60` by default.\nsettings.cancelView.height: CGFloat\n \u002F\u002F Cancel view's background color. `UIColor.black.withAlphaComponent(0.8)` by default.\nsettings.cancelView.backgroundColor: UIColor\n\u002F\u002F Indicates if the collection view is partially hidden by the cancelView when it is pulled down.\nsettings.cancelView.hideCollectionViewBehindCancelView: Bool\n```\n\n### Advanced animations\n\nIf tweaking previous settings is not enough to make the animations work like you want, XLActionController allows you to change the present\u002Fdismiss animation by overriding some functions.\n\n#### Presentation\n\n```swift\nopen func presentView(_ presentedView: UIView, presentingView: UIView, animationDuration: Double, completion: ((_ completed: Bool) -> Void)?)\n```\nThe 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.\n\n>Typically we don't need to override `presentView` function because overriding either `onWillPresentView`, `performCustomPresentationAnimation` or `onDidPresentView` is enough.\n\n```swift\nopen func onWillPresentView()\n```\n`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.\n\n```swift\nopen func performCustomPresentationAnimation(_ presentedView: UIView, presentingView: UIView)\n```\n`performCustomPresentationAnimation` is called from within the main animation block.\n\n```swift\nopen func onDidPresentView()\n```\nAfter the present animation is completed, `presentView` calls `onDidPresentView` from within completion callback.\n\n> `onWillPresentView`, `performCustomPresentationAnimation`, `onDidPresentView` won't be invoked if you override `presentView` implementation.\n\n#### Dismissal\n\nDismissal animation can be customized in the same way as presentation animation.\n\n```swift\nopen func dismissView(_ presentedView: UIView, presentingView: UIView, animationDuration: Double, completion: ((_ completed: Bool) -> Void)?)\n```\n\nThe 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.\n\n>Typically we don't need to override `dismissView` method because overriding either onWillDismissView`, `performCustomDismissingAnimation` or `onDidDismissView` is enough.\n\n```swift\nopen func onWillDismissView()\n```\nOverrides `onWillDismissView` to perform any set up before the animation begins.\n\n```swift\nopen func performCustomDismissingAnimation(_ presentedView: UIView, presentingView: UIView)\n```\n`performCustomDismissingAnimation` function is invoked from within the main animation block.\n\n```swift\nopen func onDidDismissView()\n```\nAfter the dismissal animation completes, `dismissView` calls `onDidDismissView` from within completion callback.\n\n> `onWillDismissView`, `performCustomDismissingAnimation`, `onDidDismissView` won't be invoked if you override `dismissView` implementation.\n\n\n**To show how simple and powerful XLActionController is and give several examples of how to extend ActionController we have mimicked the [Skype](Example\u002FCustomActionControllers\u002FSkype.swift), [Tweetbot](Example\u002FCustomActionControllers\u002FTweetbot.swift), [Twitter](Example\u002FCustomActionControllers\u002FTwitter.swift), [Youtube](Example\u002FCustomActionControllers\u002FYoutube.swift), [Periscope](Example\u002FCustomActionControllers\u002FPeriscope.swift) and [Spotify](Example\u002FCustomActionControllers\u002FSpotify.swift)  action controllers.**\n\n\n## Requirements\n\n* iOS 9.3+\n* Xcode 10.2+\n* Swift 5.0+\n\n## Getting involved\n\n* If you **want to contribute** please feel free to **submit pull requests**.\n* If you **have a feature request** please **open an issue**.\n* If you **found a bug** or **need help** please **check older issues before submitting an issue**.\n\nIf you use **XLActionController** in your app we would love to hear about it!\nDrop us a line on [twitter](https:\u002F\u002Ftwitter.com\u002Fxmartlabs).\n\n## Installation\n\n### CocoaPods\n\n[CocoaPods](https:\u002F\u002Fcocoapods.org\u002F) is a dependency manager for Cocoa projects.\n\nSpecify XLActionController into your project's Podfile:\n\n```ruby\nsource 'https:\u002F\u002Fgithub.com\u002FCocoaPods\u002FSpecs.git'\nuse_frameworks!\n\ntarget '\u003CYour App Target>' do\n  # This will install just the library's core, won't include any examples\n  pod 'XLActionController'\n\n  # Uncomment depending on the examples that you want to install\n  #pod 'XLActionController\u002FPeriscope'\n  #pod 'XLActionController\u002FSkype'\n  #pod 'XLActionController\u002FSpotify'\n  #pod 'XLActionController\u002FTweetbot'\n  #pod 'XLActionController\u002FTwitter'\n  #pod 'XLActionController\u002FYoutube'\nend\n```\n\nThen run the following command:\n\n```sh\n$ pod install\n```\n\n### Carthage\n\n[Carthage](https:\u002F\u002Fgithub.com\u002FCarthage\u002FCarthage) is a simple, decentralized\ndependency manager for Cocoa.\n\nSpecify XLActionController into your project's Carthage:\n\n```\ngithub \"xmartlabs\u002FXLActionController\" ~> 5.1.0\n```\n\n### Manually as Embedded Framework\n\nClone XLActionController as a git [submodule](http:\u002F\u002Fgit-scm.com\u002Fdocs\u002Fgit-submodule) by\nrunning the following command from your project root git folder.\n\n```sh\n$ git submodule add https:\u002F\u002Fgithub.com\u002Fxmartlabs\u002FXLActionController.git\n```\n\nOpen XLActionController folder that was created by the previous git submodule\ncommand and drag the XLActionController.xcodeproj into the Project Navigator\nof your application's Xcode project.\n\nSelect the XLActionController.xcodeproj in the Project Navigator and verify the deployment\ntarget matches with your application deployment target.\n\nSelect your project in the Xcode Navigation and then select your application\ntarget from the sidebar. Next select the \"General\" tab and click on the + button\nunder the \"Embedded Binaries\" section.\n\nSelect XLActionController.framework and we are done!\n\n## Authors\n\n* [Miguel Revetria](https:\u002F\u002Fwww.github.com\u002Fm-revetria \"Miguel Revetria Github\")\n* [Martin Barreto](https:\u002F\u002Fwww.github.com\u002FmtnBarreto \"Martin Barreto Github\")\n\n## License\n\nXLActionController is released under [MIT license](https:\u002F\u002Fraw.githubusercontent.com\u002Fxmartlabs\u002FXLActionController\u002Fmaster\u002FLICENSE) and copyrighted by Xmartlabs SRL.\n","XLActionController 是一个用 Swift 编写的可完全自定义和扩展的动作表控制器库。它支持通过简单的 API 创建多种样式的动作表，包括 Spotify、Twitter 和 Tweetbot 等流行应用的样式，并且可以轻松添加自定义行为。该库兼容 iOS 平台，支持使用 Carthage 或 CocoaPods 进行集成，同时确保与 Swift 5 兼容。适用于需要在 iOS 应用中提供丰富用户交互体验的场景，特别是那些希望提升界面美观度和用户体验的应用开发项目。",2,"2026-06-11 03:09:59","top_language"]