从框架中弹出的动画弹窗。您可以选择弹窗的方向和指向其起源的箭头。颜色、边框圆角和字体可以轻松自定义。此弹窗可用于在界面中留下微妙的提示,并提供有趣的界面引导弹窗。
截图
版本说明
版本 2.0.0
时,库是用 Swift 重写的,API 也略有更新。请参阅 1.5.x
以获取以前的 Objective-C 实现。
版本 3.0.0
引入了 Swift 4 支持,3.5.0
Swift 4.2。
使用 CocoaPods 设置
- 将
pod 'AMPopTip'
添加到Podfile
- 运行
pod install
- 运行
open App.xcworkspace
使用 Carthage 设置
- 添加
github "andreamazz/AMPopTip"
- 运行
carthage update
- 在您的项目中添加
AMPopTip.framework
然后您可以在项目中导入该框架
import AMPopTip
用法
API非常直观,您可以在任何时间显示和隐藏弹出层。
显示弹出层
您必须指定要在弹出层旁边显示的文本、弹出方向、包含弹出层的视图以及弹出箭头所指的视图的框架。
let popTip = PopTip()
popTip.show(text: "Hey! Listen!", direction: .up, maxWidth: 200, in: view, from: someView.frame)
您还可以将弹出层居中显示,不带箭头,在这种情况下,from
可以是整个视图
popTip.show(text: "Hey! Listen!", direction: .none, maxWidth: 200, in: view, from: view.frame)
坐标系
请注意,您预期提供的框架需要引用您要显示弹出层的视图的绝对坐标系。这意味着如果您在一个视图中显示弹出层,指向嵌套的子视图,您需要使用UIKit的convertRect(_:toView:)
来转换其框架。请参考此处。
方向
您可以指定小技巧将要占据的方向,或者通过使用auto
(所有轴)、autoHorizontal
(只左
或右
)或autoVertical
(只上
或下
)让库决定。一旦弹出层可见,direction
属性将保留已决定的方向。
显示自定义视图
您可以为将在 PopTip 中包装并显示的自定义视图提供。
let customView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
// Configure your view
popTip.show(customView: customView, direction: .down, in: view, from: someView.frame)
显示自定义 SwiftUI 视图
您可以为嵌入到 UIHostingController
、添加到父控制器,并随后在 PopTip 中包装和显示的自定义 SwiftUI 视图提供。
let customSwiftUIView = MySwiftUIView()
// Configure your view
popTip.show(rootView: customSwiftUIView, direction: .down, in: view, from: someView.frame, parent: someParentViewController)
关闭弹窗
您可以通过调用
popTip.hide()
您还可以指定弹窗的持续时间
popTip.show(text: "Hey! Listen!", direction: .up, maxWidth: 200, in: view, from: someView.frame, duration: 3)
您也可以允许用户通过点击弹窗外来关闭 PopTip(默认为 true
)
popTip.shouldDismissOnTap = true
您还可以允许用户通过点击弹窗外来关闭 PopTip(默认为 true
)
popTip.shouldDismissOnTapOutside = true
您还可以将起始帧视为 popTip 的一部分,即与点击弹窗相同地处理起始帧(默认为 false
)
popTip.shouldConsiderOriginatingFrameAsPopTip = true
您还可以将缺口视为单独的点击区域,该区域将调用不同的回调(默认为 false
)
popTip.shouldConsiderCutoutTapSeparately = true
您还可以允许用户通过在 PopTip 外滑动来关闭(默认为 false
)(方向通过 popTip.swipeRemoveGestureDirection
控制,使用 UISwipeGestureRecognizer.Direction
)
popTip.shouldDismissOnSwipeOutside = false
您可以在用户点击 PopTip 时调用一个块...
popTip.tapHandler = { popTip in
print("\(popTip) tapped")
}
... 当点击缺口时...
popTip.tapCutoutHandler = { popTip in
print("\(popTip) cutout tapped")
}
... 当显示弹窗时...
popTip.appearHandler = { popTip in
print("\(popTip) appeared")
};
... 或当弹窗关闭时
popTip.dismissHandler = { popTip in
print("\(popTip) dismissed")
}
popTip.tapOutsideHandler = { _ in
print("tap outside")
}
popTip.swipeOutsideHandler = { _ in
print("swipe outside")
}
在关闭时转发送击手势
默认情况下,“点击关闭”的手势识别器取消视图中的点击,如果您需要的话,可以手动启用此行为
popTip.tapToRemoveGestureRecognizer?.cancelsTouchesInView = false
更新 PopTip
您可以更新一个已出现PopTip的文字、属性文本或自定义视图
popTip.update(text: "New string")
popTip.update(attributedText: someAttributedString)
popTip.update(customView: someView)
通过更新from
属性也可以更改位置
let here = CGRect(x: 100, 100, 10, 10)
let there = CGRect(x: 400, 400, 10, 10)
popTip.show(text: "Hey! Listen!", direction: .up, maxWidth: 200, in: view, from: here)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
popTip.from = there
}
自定义进入动画
您可以选择在显示popTip时执行哪种动画
popTip.entranceAnimation = .scale;
可用的动画
PopTipEntranceAnimation.scale,
PopTipEntranceAnimation.transition,
PopTipEntranceAnimation.none,
PopTipEntranceAnimation.custom
PopTipEntranceAnimation.custom
当使用PopTipEntranceAnimation.custom
时,您可以提供自己的动画块
popTip.entranceAnimationHandler = { [weak self] completion in
guard let `self` = self else { return }
self.popTip.transform = CGAffineTransform(rotationAngle: 0.3)
UIView.animate(withDuration: 0.5, animations: {
self.popTip.transform = .identity
}, completion: { (_) in
completion()
})
}
此示例使PopTip在进入时旋转。请确保动画完成时调用完成块。请注意,当PopTip作为子视图添加时,动画立即触发。
动作动画
动作动画是微妙的动画,可以执行以吸引用户的注意。设置您喜欢的动画
popTip.actionAnimation = .bounce()
可用的动画
PopTipActionAnimation.bounce,
PopTipActionAnimation.float,
PopTipActionAnimation.pulse,
PopTipActionAnimation.none
一旦弹出视图进入场景并完成进入动画,动画就会触发,前提是将startActionAnimationOnShow
设置为true。
自定义动画
您可以将自定义值作为相关值传递以自定义动作动画
popTip.actionAnimation = .bounce(16) // This will bounce for 16px instead of the default value
自定义箭头位置
默认情况下,箭头居中,移动以避免屏幕边缘。您可以使用bubbleOffset
属性手动更改与中心的偏移量。
关于子视图的说明
弹窗视图显示在由in
参数提供的视图中。如果此视图比弹窗视图小,为了避免剪切,在显示视图中设置clipsToBounds = false
,并将constrainInContainerView = false
应用于弹窗提示实例。参见 #175 了解更多背景信息。
自定义
在使用实例之前使用外观代理来自定义弹窗,或者只需使用其公开属性。
textColor = <#UIColor#>;
textAlignment = <#NSTextAlignment#>
bubbleColor = <#UIColor#>
bubbleLayerGenerator = <#(PopTip)->Void#>
borderColor = <#UIColor#>
borderWidth = <#CGFloat#>
cornerRadius = <#CGFloat#> // Popover's border radius
isRounded = <#Bool#> // If set to YES the radius will equal frame.height / 2
offset = <#CGFloat#> // Offset between the popover and the origin
font = <#UIFont#>
padding = <#CGFloat#>
edgeInsets = <#UIEdgeInsets#>
arrowSize = <#CGSize#>
animationIn = <#TimeInterval#>
animationOut = <#TimeInterval#>
delayIn = <#TimeInterval#>
delayOut = <#TimeInterval#>
entranceAnimation = <#PopTipEntranceAnimation#>
exitAnimation = <#PopTipExitAnimation#>
actionAnimation = <#PopTipActionAnimation#>
actionAnimationIn = <#TimeInterval#>
actionAnimationOut = <#TimeInterval#>
actionDelayIn = <#TimeInterval#>
actionDelayOut = <#TimeInterval#>
edgeMargin = <#CGFloat#>
bubbleOffset = <#CGFloat#> // Offset between the bubble and the origin
arrowOffset = <#CGFloat#> // Offset between the bubble center and the arrow
arrowRadius = <#CGFloat#>
shadowOpacity = <#Float#>
shadowRadius = <#Float#>
shadowOffset = <#CGSize#>
shadowColor = <#UIColor#>
maskColor = <#UIColor#>
shouldShowMask = <#Bool#>
shouldCutoutMask = <#Bool#>
cutoutPathGenerator = <#(CGRect)->UIBezierPath#>
constrainInContainerView = <#Bool#>
背景遮罩
可以将背景遮罩应用于当PopTip处于活动状态时暗淡背景,这可以通过将公开属性设置为true
来启用。
popTip.shouldShowMask = true
颜色由maskColor
属性设置(默认为UIColor(red: 0, green: 0, blue: 0, alpha: 0.6)
)。
popTip.maskColor = UIColor(red: 1, green: 0, blue: 0, alpha: 0.6)
添加轮廓
可以应用于背景遮罩,以允许视图在变暗的背景中可见。要使其生效,必须设置shouldShowMask
和shouldCutoutMask
都为true
。切出路径是通过具有签名(_ from: CGRect) -> UIBezierPath
的闭包提供的,该签名存储在与公开属性`cutoutPathGenerator`关联的路径生成器中。闭包将提供一个参数,该参数是提供给`popTip.show(...)`的CGRect
框架。
默认生成器向from
框架区域四周添加一个8
的圆形角矩形,左右各添加8
填充,如下,但可以根据需要更改:
popTip.cutoutPathGenerator = { from in
UIBezierPath(roundedRect: from.insetBy(dx: -8, dy: -8), byRoundingCorners: .allCorners, cornerRadii: CGSize(width: 8, height: 8))
}
如果同时设置shouldShowMask
和shouldCutoutMask
为true
,还可以调用单独的回调闭包,其如下所示:
popTip.tapCutoutHandler = { popTip in
print("\(popTip) cutout tapped")
}
自定义气泡背景
可以通过一个标识为 (_ path: UIBezierPath) -> CALayer?
的闭包使用自定义的 CALayer
作为 PopTip 气泡的背景,这个闭包存储在公开属性 bubbleLayerGenerator
中。闭包将提供一个参数,即表示 PopTip 气泡和箭头的绘制路径的 UIBezierPath
。
如果 bubbleLayerGenerator
是 nil
,则将使用 bubbleColor
作为实心背景填充。如果 bubbleLayerGenerator
不是 nil
,则将使用它,前提是它提供了一个有效的 CALayer
,否则将使用作为实色后备的 bubbleColor
。以下是一个示例:
popTip.bubbleLayerGenerator = { path in
let gradient = CAGradientLayer()
gradient.frame = path.bounds
gradient.colors = [UIColor.black.withAlphaComponent(0.4).cgColor, UIColor.black.withAlphaComponent(0.3)]
gradient.locations = [0, 1]
gradient.startPoint = CGPoint(x: 0.5, y: 0.0)
gradient.endPoint = CGPoint(x: 0.5, y: 1.0)
let shapeMask = CAShapeLayer()
shapeMask.path = path.cgPath
gradient.mask = shapeMask
return gradient
}
作者
Andrea Mazzini。我可以免费工作,欢迎联系我。
想要支持这些免费库(《CocoaPods》)的开发吗?买我一杯咖啡
贡献者
感谢所有提交了 pull request 的人。
MIT 许可证
Copyright (c) 2017 Andrea Mazzini. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.