一天一个第三方库iOS-XLActionController使用
XLActionController
是一个支持各种自定义的底部选择框。
对于各种底部弹框非常好用,这个是我写的demo,二话不说先上图。
XLActionController.gif第一步引入第三方库
我习惯使用pod引入
在Podfile中加入下面代码
platform :ios, '9.0'
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
如果只pod XLActionController则是引入了核心库,实例中的效果则需要自己实现,我自己跟着实现了一下,没问题是没问题,就是太费事了。使用第三方目的就是提高生产力,如果太麻烦还不如自己写。所以,强烈建议,引入上述其他包,或者根据效果引入。
因为我自己实现过一次,且命名中有一个ActionData.swift。自己实现和后续引入的第三方库会有冲突。会抱一个错,意思是不能把Action<ActionData>
转换成Action<ActionData>
是不是非常奇怪,明明是一个数据类型,为何还要转换,关键是转不了。后来才发现是自己写的和第三方的库的冲突了。因此最好我还是删了自己的实现。
所以直接使用第三方的就好了。
Podfile文件写好之后,根据需要使用下列命令,安装依赖库
pod install
or
pod update
使用
使用是先导入第三方库
import XLActionController
下面的示例展示了如何弹出一个Tweetbot类型的底部弹窗
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)
使用起来和UIAlertController非常像。
动作行为通常都是在弹框从屏幕消失才触发的,你可以改变这种触发模式,让它立刻触发。你需要构建动作时,把executeImmediatelyOnTouch
参数设置为真。
自定义ActionController
ActionController使用的是UICollectionView来展示动作和头部视图的 。动作展示是由UICollectionViewCell渲染得到的。
你可以在ActionController的声明里指定它来使用自己继续自UICollectionViewCell的子类。此外,ActionController允许你指定一个全局的头部和组视图。
ActionController
这儿类是一个通用类型,在cell,头部,组头都可已使用。它关联任意类型。
XLActionController提供了扩展,来制定一个全新的外观和感觉,下面是自定义视图控制器的一个例子。
// 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的类型声明:
public class ActionController<ActionViewType: UICollectionViewCell, ActionDataType, HeaderViewType: UICollectionReusableView, HeaderDataType, SectionHeaderViewType: UICollectionReusableView, SectionHeaderDataType>
当继承ActionController时,我们必须指定这三种类型
ActionViewType, HeaderViewType, SectionHeaderViewType
就是用这些来渲染cell和头部视图及组视图。
每一个type都有与之相关的数据ActionDataType, HeaderDataType, SectionHeaderDataType
如果视图没有头部视图,可以使用UICollectionReusableView
替代,使用Void
来替代HeaderDataType
修改UICollectionView的行为、样式和动画设置
行为
// 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
样式
// 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
动画缩放
// 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)
出现动画设置
// 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
消失动画设置
// 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
状态栏样式
// 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
取消视图 的样式
// 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
如果上面的动画设置还满足不了你,你可以重写下面的方法来改变出现和消失的动画
出现动画
open func presentView(_ presentedView: UIView, presentingView: UIView, animationDuration: Double, completion: ((_ completed: Bool) -> Void)?)
上面的功能负责制作当前的动画。它将如何表现进行调用onwillpresentview,performcustompresentationanimation和ondidpresentview
因此我们通常不用重写上面的动画。而是重写上述三个钟的一个或两个就够了。
onWillPresentView
在动画之前开始调用,这里的任何更改都不是动画的,这里是为了初始化一些动画的属性值。
performCustomPresentationAnimation
执行动画主要走这个函数。
动画完成之后,presentView会调用onDidPresentView
同样的,消失动画,的重写
open func dismissView(_ presentedView: UIView, presentingView: UIView, animationDuration: Double, completion: ((_ completed: Bool) -> Void)?)
也通常是重写onWillDismissView
, performCustomDismissingAnimation
and onDidDismissView
目前使用时,有一个地方会崩溃,就是在使用TweetbotActionController时,会报错。
我想后续肯定会解决的。目前的临时解决办法请参考一下链接。
https://github.com/xmartlabs/XLActionController/issues/75