动画弹出框,从一个框架中弹出。您可以指定弹出框的方向以及指向其原点的箭头。颜色、边框半径和字体都可以轻松自定义。此弹出框可用于留下关于您的 UI 的细微提示,并提供有趣的上岗引导弹出窗口。
在 2.0.0
版本中,该库已使用 Swift 重新编写,并且 API 略有更新。请查看 1.5.x
版本获取之前的 Objective-C 实现。
3.0.0
版本引入了 Swift 4 支持,3.5.0
引入了 Swift 4.2。
pod 'AMPopTip'
添加到您的 Podfile
pod install
open App.xcworkspace
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
(仅 left
或 right
)或 autoVertical
(仅 up
或 down
)来决定。一旦弹出窗口可见,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 中并显示。
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)
您还可以让用户通过点击弹出框来关闭它(默认值为 true
)
popTip.shouldDismissOnTap = true
您还可以让用户通过点击弹出框外部来关闭 PopTip(默认值为 true
)
popTip.shouldDismissOnTapOutside = true
您还可以将原点框架视为 popTip 的一部分,即,将原点框架视为与点击 popover 相同(默认值为 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.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
时,您可以提供自己的动画块
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
,并将 pop tip 实例上的 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)
可以将镂空应用于背景蒙版,以允许 from
视图通过调暗的背景可见。 shouldShowMask
和 shouldCutoutMask
必须都为 true
才能使其工作。镂空路径通过闭包提供,其签名为 (_ from: CGRect) -> UIBezierPath
,存储在公共属性 cutoutPathGenerator
中。闭包将提供一个参数,该参数是提供给 popTip.show(...)
的 CGRect
框架。
默认生成器在 from
框架区域周围添加一个 8
圆角矩形,该矩形在 x
和 y
方向上具有 8
填充,如下所示,但可以更改为所需的任何内容
popTip.cutoutPathGenerator = { from in
UIBezierPath(roundedRect: from.insetBy(dx: -8, dy: -8), byRoundingCorners: .allCorners, cornerRadii: CGSize(width: 8, height: 8))
}
如果 shouldShowMask
和 shouldCutoutMask
都为 true
,则可以在点击 cutoutPathGenerator
定义的区域时调用一个单独的回调闭包,闭包如下所示
popTip.tapCutoutHandler = { popTip in
print("\(popTip) cutout tapped")
}
可以使用自定义 CALayer
作为 PopTip 气泡的背景,这通过一个闭包提供,其签名为 ((_ path: UIBezierPath) -> CALayer?)?
,存储在公共属性 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。我可以提供自由职业工作,请随时与我联系。
想支持这些免费库的开发吗? 通过 Paypal 给我买杯咖啡 ☕️ 吧。
感谢每个人慷慨地提交 pull request。
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.