这篇文章主要是记录下 UIView 的常用扩展,方便自己使用的时候寻找查看,将从以下基础操作几何操作、样式和外观、动画系统、手势处理、布局公布工具、视图管理、调试工具、高级效果、性能优化、使用工具等方面进行分类归纳。
1、Frame相关属性扩展
swift
// MARK: - Frame相关属性扩展
extension UIView {
/// 视图的x坐标
/// - Note: 设置时会保持其他frame属性不变
/// - Example:
/// ```
/// view.x = 100
/// print(view.x) // 100
/// ```
var x: CGFloat {
get { return frame.origin.x }
set { frame.origin.x = newValue }
}
/// 视图的y坐标
/// - Note: 设置时会保持其他frame属性不变
/// - Example:
/// ```
/// view.y = 50
/// print(view.y) // 50
/// ```
var y: CGFloat {
get { return frame.origin.y }
set { frame.origin.y = newValue }
}
/// 视图的宽度
/// - Note: 设置时会保持origin不变
/// - Example:
/// ```
/// view.width = 200
/// print(view.width) // 200
/// ```
var width: CGFloat {
get { return frame.size.width }
set { frame.size.width = newValue }
}
/// 视图的高度
/// - Note: 设置时会保持origin不变
/// - Example:
/// ```
/// view.height = 300
/// print(view.height) // 300
/// ```
var height: CGFloat {
get { return frame.size.height }
set { frame.size.height = newValue }
}
/// 视图的origin点
/// - Note: 包含x和y坐标
/// - Example:
/// ```
/// view.origin = CGPoint(x: 10, y: 20)
/// print(view.origin) // (10.0, 20.0)
/// ```
var origin: CGPoint {
get { return frame.origin }
set { frame.origin = newValue }
}
/// 视图的size
/// - Note: 包含宽度和高度
/// - Example:
/// ```
/// view.size = CGSize(width: 100, height: 200)
/// print(view.size) // (100.0, 200.0)
/// ```
var size: CGSize {
get { return frame.size }
set { frame.size = newValue }
}
/// 视图的中心点x坐标
/// - Note: 基于父视图坐标系
/// - Example:
/// ```
/// view.centerX = 150
/// print(view.centerX) // 150
/// ```
var centerX: CGFloat {
get { return center.x }
set { center.x = newValue }
}
/// 视图的中心点y坐标
/// - Note: 基于父视图坐标系
/// - Example:
/// ```
/// view.centerY = 200
/// print(view.centerY) // 200
/// ```
var centerY: CGFloat {
get { return center.y }
set { center.y = newValue }
}
/// 视图的右边界x坐标
/// - Note: 等于x + width
/// - Example:
/// ```
/// view.right = 300 // 会自动调整x坐标
/// print(view.right) // 300
/// ```
var right: CGFloat {
get { return frame.origin.x + frame.size.width }
set { frame.origin.x = newValue - frame.size.width }
}
/// 视图的底边界y坐标
/// - Note: 等于y + height
/// - Example:
/// ```
/// view.bottom = 400 // 会自动调整y坐标
/// print(view.bottom) // 400
/// ```
var bottom: CGFloat {
get { return frame.origin.y + frame.size.height }
set { frame.origin.y = newValue - frame.size.height }
}
}
2、圆角和边框相关
swift
// MARK: - 圆角和边框相关
extension UIView {
/// 设置视图圆角
/// - Parameter radius: 圆角半径
/// - Note: 会自动设置clipsToBounds为true
/// - Example:
/// ```
/// view.setCornerRadius(10)
/// ```
func setCornerRadius(_ radius: CGFloat) {
layer.cornerRadius = radius
clipsToBounds = true
}
/// 设置视图边框
/// - Parameters:
/// - width: 边框宽度
/// - color: 边框颜色
/// - Example:
/// ```
/// view.setBorder(width: 2, color: .red)
/// ```
func setBorder(width: CGFloat, color: UIColor) {
layer.borderWidth = width
layer.borderColor = color.cgColor
}
/// 设置视图阴影
/// - Parameters:
/// - color: 阴影颜色
/// - opacity: 阴影透明度
/// - offset: 阴影偏移量
/// - radius: 阴影模糊半径
/// - Example:
/// ```
/// view.setShadow(color: .black, opacity: 0.3, offset: CGSize(width: 2, height: 2), radius: 4)
/// ```
func setShadow(color: UIColor, opacity: Float, offset: CGSize, radius: CGFloat) {
layer.shadowColor = color.cgColor
layer.shadowOpacity = opacity
layer.shadowOffset = offset
layer.shadowRadius = radius
layer.masksToBounds = false
}
/// 同时设置圆角和阴影
/// - Parameters:
/// - cornerRadius: 圆角半径
/// - shadowColor: 阴影颜色
/// - shadowOpacity: 阴影透明度
/// - shadowOffset: 阴影偏移量
/// - shadowRadius: 阴影模糊半径
/// - Note: 使用容器视图解决圆角和阴影冲突问题
/// - Example:
/// ```
/// view.setCornerRadiusWithShadow(
/// cornerRadius: 10,
/// shadowColor: .black,
/// shadowOpacity: 0.3,
/// shadowOffset: CGSize(width: 0, height: 2),
/// shadowRadius: 4
/// )
/// ```
func setCornerRadiusWithShadow(cornerRadius: CGFloat,
shadowColor: UIColor,
shadowOpacity: Float,
shadowOffset: CGSize,
shadowRadius: CGFloat) {
// 创建容器视图
let containerView = UIView()
containerView.frame = frame
containerView.backgroundColor = UIColor.clear
// 设置阴影
containerView.layer.shadowColor = shadowColor.cgColor
containerView.layer.shadowOpacity = shadowOpacity
containerView.layer.shadowOffset = shadowOffset
containerView.layer.shadowRadius = shadowRadius
containerView.layer.masksToBounds = false
// 设置圆角
layer.cornerRadius = cornerRadius
clipsToBounds = true
// 调整frame
frame = bounds
// 添加到容器
superview?.insertSubview(containerView, belowSubview: self)
containerView.addSubview(self)
}
}
// MARK: - 指定角圆角扩展
extension UIView {
/// 设置指定角的圆角
/// - Parameters:
/// - corners: 要设置圆角的角(可多选)
/// - radius: 圆角半径
/// - Example:
/// ```
/// // 只设置顶部两个角为圆角
/// view.setRoundCorners([.topLeft, .topRight], radius: 16)
///
/// // 只设置左侧两个角为圆角
/// view.setRoundCorners([.topLeft, .bottomLeft], radius: 12)
/// ```
func setRoundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(
roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius)
)
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
layer.mask = maskLayer
}
/// 设置指定角的圆角(支持不同半径)
/// - Parameters:
/// - topLeft: 左上角半径
/// - topRight: 右上角半径
/// - bottomLeft: 左下角半径
/// - bottomRight: 右下角半径
/// - Example:
/// ```
/// // 每个角设置不同的圆角半径
/// view.setRoundCorners(topLeft: 16, topRight: 16, bottomLeft: 0, bottomRight: 0)
/// ```
func setRoundCorners(topLeft: CGFloat = 0,
topRight: CGFloat = 0,
bottomLeft: CGFloat = 0,
bottomRight: CGFloat = 0) {
let path = UIBezierPath()
let width = bounds.width
let height = bounds.height
// 从左上角开始,顺时针绘制路径
path.move(to: CGPoint(x: topLeft, y: 0))
// 顶边
path.addLine(to: CGPoint(x: width - topRight, y: 0))
// 右上角
if topRight > 0 {
path.addArc(withCenter: CGPoint(x: width - topRight, y: topRight),
radius: topRight,
startAngle: -CGFloat.pi/2,
endAngle: 0,
clockwise: true)
}
// 右边
path.addLine(to: CGPoint(x: width, y: height - bottomRight))
// 右下角
if bottomRight > 0 {
path.addArc(withCenter: CGPoint(x: width - bottomRight, y: height - bottomRight),
radius: bottomRight,
startAngle: 0,
endAngle: CGFloat.pi/2,
clockwise: true)
}
// 底边
path.addLine(to: CGPoint(x: bottomLeft, y: height))
// 左下角
if bottomLeft > 0 {
path.addArc(withCenter: CGPoint(x: bottomLeft, y: height - bottomLeft),
radius: bottomLeft,
startAngle: CGFloat.pi/2,
endAngle: CGFloat.pi,
clockwise: true)
}
// 左边
path.addLine(to: CGPoint(x: 0, y: topLeft))
// 左上角
if topLeft > 0 {
path.addArc(withCenter: CGPoint(x: topLeft, y: topLeft),
radius: topLeft,
startAngle: CGFloat.pi,
endAngle: -CGFloat.pi/2,
clockwise: true)
}
path.close()
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
layer.mask = maskLayer
}
/// 使用CACornerMask设置指定角圆角(iOS 11+)
/// - Parameters:
/// - corners: 要设置圆角的角
/// - radius: 圆角半径
/// - Example:
/// ```
/// // 使用更高效的方式设置圆角(iOS 11+)
/// view.setRoundCorners(corners: [.layerMinXMinYCorner, .layerMaxXMinYCorner], radius: 16)
/// ```
@available(iOS 11.0, *)
func setRoundCorners(corners: CACornerMask, radius: CGFloat) {
layer.cornerRadius = radius
layer.maskedCorners = corners
clipsToBounds = true
}
/// 设置顶部圆角
/// - Parameter radius: 圆角半径
/// - Example:
/// ```
/// headerView.setRoundTopCorners(radius: 16)
/// ```
func setRoundTopCorners(radius: CGFloat) {
if #available(iOS 11.0, *) {
setRoundCorners(corners: [.layerMinXMinYCorner, .layerMaxXMinYCorner], radius: radius)
} else {
setRoundCorners([.topLeft, .topRight], radius: radius)
}
}
/// 设置底部圆角
/// - Parameter radius: 圆角半径
/// - Example:
/// ```
/// footerView.setRoundBottomCorners(radius: 16)
/// ```
func setRoundBottomCorners(radius: CGFloat) {
if #available(iOS 11.0, *) {
setRoundCorners(corners: [.layerMinXMaxYCorner, .layerMaxXMaxYCorner], radius: radius)
} else {
setRoundCorners([.bottomLeft, .bottomRight], radius: radius)
}
}
/// 设置左侧圆角
/// - Parameter radius: 圆角半径
/// - Example:
/// ```
/// leftPanelView.setRoundLeftCorners(radius: 12)
/// ```
func setRoundLeftCorners(radius: CGFloat) {
if #available(iOS 11.0, *) {
setRoundCorners(corners: [.layerMinXMinYCorner, .layerMinXMaxYCorner], radius: radius)
} else {
setRoundCorners([.topLeft, .bottomLeft], radius: radius)
}
}
/// 设置右侧圆角
/// - Parameter radius: 圆角半径
/// - Example:
/// ```
/// rightPanelView.setRoundRightCorners(radius: 12)
/// ```
func setRoundRightCorners(radius: CGFloat) {
if #available(iOS 11.0, *) {
setRoundCorners(corners: [.layerMaxXMinYCorner, .layerMaxXMaxYCorner], radius: radius)
} else {
setRoundCorners([.topRight, .bottomRight], radius: radius)
}
}
/// 移除圆角mask(恢复原始形状)
/// - Example:
/// ```
/// view.removeCornerRadius()
/// ```
func removeCornerRadius() {
layer.mask = nil
layer.cornerRadius = 0
if #available(iOS 11.0, *) {
layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner,
.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
}
}
}
3、渐变背景相关
swift
// MARK: - 渐变背景相关
extension UIView {
/// 设置线性渐变背景
/// - Parameters:
/// - colors: 渐变颜色数组
/// - startPoint: 起始点 (0,0)到(1,1)
/// - endPoint: 结束点 (0,0)到(1,1)
/// - Example:
/// ```
/// view.setGradientBackground(
/// colors: [UIColor.red, UIColor.blue],
/// startPoint: CGPoint(x: 0, y: 0),
/// endPoint: CGPoint(x: 1, y: 1)
/// )
/// ```
func setGradientBackground(colors: [UIColor], startPoint: CGPoint, endPoint: CGPoint) {
let gradientLayer = CAGradientLayer()
gradientLayer.colors = colors.map { $0.cgColor }
gradientLayer.startPoint = startPoint
gradientLayer.endPoint = endPoint
gradientLayer.frame = bounds
layer.sublayers?.removeAll { $0 is CAGradientLayer }
layer.insertSublayer(gradientLayer, at: 0)
}
/// 设置径向渐变背景
/// - Parameters:
/// - colors: 渐变颜色数组
/// - center: 渐变中心点
/// - radius: 渐变半径
/// - Example:
/// ```
/// view.setRadialGradientBackground(
/// colors: [UIColor.white, UIColor.black],
/// center: CGPoint(x: 0.5, y: 0.5),
/// radius: 100
/// )
/// ```
func setRadialGradientBackground(colors: [UIColor], center: CGPoint, radius: CGFloat) {
let gradientLayer = CAGradientLayer()
gradientLayer.type = .radial
gradientLayer.colors = colors.map { $0.cgColor }
gradientLayer.startPoint = center
gradientLayer.endPoint = CGPoint(x: center.x + radius / bounds.width, y: center.y + radius / bounds.height)
gradientLayer.frame = bounds
layer.sublayers?.removeAll { $0 is CAGradientLayer }
layer.insertSublayer(gradientLayer, at: 0)
}
}
4、动画相关
swift
// MARK: - 动画相关
extension UIView {
/// 淡入动画
/// - Parameters:
/// - duration: 动画时长
/// - completion: 完成回调
/// - Example:
/// ```
/// view.fadeIn(duration: 0.3) {
/// print("淡入动画完成")
/// }
/// ```
func fadeIn(duration: TimeInterval = 0.3, completion: (() -> Void)? = nil) {
alpha = 0
UIView.animate(withDuration: duration, animations: {
self.alpha = 1
}) { _ in
completion?()
}
}
/// 淡出动画
/// - Parameters:
/// - duration: 动画时长
/// - completion: 完成回调
/// - Example:
/// ```
/// view.fadeOut(duration: 0.3) {
/// print("淡出动画完成")
/// }
/// ```
func fadeOut(duration: TimeInterval = 0.3, completion: (() -> Void)? = nil) {
UIView.animate(withDuration: duration, animations: {
self.alpha = 0
}) { _ in
completion?()
}
}
/// 缩放动画
/// - Parameters:
/// - scale: 缩放比例
/// - duration: 动画时长
/// - completion: 完成回调
/// - Example:
/// ```
/// view.scale(to: 1.5, duration: 0.3) {
/// print("缩放动画完成")
/// }
/// ```
func scale(to scale: CGFloat, duration: TimeInterval = 0.3, completion: (() -> Void)? = nil) {
UIView.animate(withDuration: duration, animations: {
self.transform = CGAffineTransform(scaleX: scale, y: scale)
}) { _ in
completion?()
}
}
/// 弹簧动画
/// - Parameters:
/// - damping: 阻尼比例 (0.0 - 1.0)
/// - velocity: 初始速度
/// - duration: 动画时长
/// - animations: 动画操作
/// - completion: 完成回调
/// - Example:
/// ```
/// view.springAnimation(damping: 0.7, velocity: 0.5, duration: 0.5, animations: {
/// view.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
/// })
/// ```
func springAnimation(damping: CGFloat = 0.7,
velocity: CGFloat = 0.5,
duration: TimeInterval = 0.5,
animations: @escaping () -> Void,
completion: (() -> Void)? = nil) {
UIView.animate(withDuration: duration,
delay: 0,
usingSpringWithDamping: damping,
initialSpringVelocity: velocity,
options: .curveEaseInOut,
animations: animations) { _ in
completion?()
}
}
/// 震动动画
/// - Parameters:
/// - intensity: 震动强度
/// - duration: 动画时长
/// - Example:
/// ```
/// view.shake(intensity: 10, duration: 0.5)
/// ```
func shake(intensity: CGFloat = 10, duration: TimeInterval = 0.5) {
let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
animation.timingFunction = CAMediaTimingFunction(name: .linear)
animation.duration = duration
animation.values = [-intensity, intensity, -intensity, intensity, -intensity/2, intensity/2, -intensity/4, intensity/4, 0]
layer.add(animation, forKey: "shake")
}
/// 旋转动画
/// - Parameters:
/// - angle: 旋转角度 (弧度)
/// - duration: 动画时长
/// - completion: 完成回调
/// - Example:
/// ```
/// view.rotate(angle: .pi, duration: 1.0) {
/// print("旋转动画完成")
/// }
/// ```
func rotate(angle: CGFloat, duration: TimeInterval = 1.0, completion: (() -> Void)? = nil) {
UIView.animate(withDuration: duration, animations: {
self.transform = self.transform.rotated(by: angle)
}) { _ in
completion?()
}
}
/// 无限旋转动画
/// - Parameters:
/// - duration: 一圈的时长
/// - clockwise: 是否顺时针
/// - Example:
/// ```
/// view.startRotating(duration: 2.0, clockwise: true)
/// // 停止旋转
/// view.stopRotating()
/// ```
func startRotating(duration: TimeInterval = 2.0, clockwise: Bool = true) {
let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotationAnimation.fromValue = 0
rotationAnimation.toValue = clockwise ? CGFloat.pi * 2 : -CGFloat.pi * 2
rotationAnimation.duration = duration
rotationAnimation.repeatCount = Float.infinity
layer.add(rotationAnimation, forKey: "rotationAnimation")
}
/// 停止旋转动画
/// - Example:
/// ```
/// view.stopRotating()
/// ```
func stopRotating() {
layer.removeAnimation(forKey: "rotationAnimation")
}
}
5、视图层次相关
swift
// MARK: - 视图层次相关
extension UIView {
/// 移除所有子视图
/// - Example:
/// ```
/// containerView.removeAllSubviews()
/// ```
func removeAllSubviews() {
subviews.forEach { $0.removeFromSuperview() }
}
/// 添加多个子视图
/// - Parameter subviews: 子视图数组
/// - Example:
/// ```
/// containerView.addSubviews([label, button, imageView])
/// ```
func addSubviews(_ subviews: [UIView]) {
subviews.forEach { addSubview($0) }
}
/// 获取指定类型的父视图
/// - Parameter type: 父视图类型
/// - Returns: 指定类型的父视图,如果没有找到返回nil
/// - Example:
/// ```
/// if let tableView = view.parentView(of: UITableView.self) {
/// print("找到父级TableView")
/// }
/// ```
func parentView<T: UIView>(of type: T.Type) -> T? {
var currentView = superview
while currentView != nil {
if let targetView = currentView as? T {
return targetView
}
currentView = currentView?.superview
}
return nil
}
/// 获取所有指定类型的子视图
/// - Parameter type: 子视图类型
/// - Returns: 指定类型的子视图数组
/// - Example:
/// ```
/// let allLabels = containerView.subviews(of: UILabel.self)
/// print("找到 \(allLabels.count) 个标签")
/// ```
func subviews<T: UIView>(of type: T.Type) -> [T] {
var result: [T] = []
for subview in subviews {
if let targetView = subview as? T {
result.append(targetView)
}
result.append(contentsOf: subview.subviews(of: type))
}
return result
}
/// 将视图移到最前面
/// - Example:
/// ```
/// view.bringToFront()
/// ```
func bringToFront() {
superview?.bringSubviewToFront(self)
}
/// 将视图移到最后面
/// - Example:
/// ```
/// view.sendToBack()
/// ```
func sendToBack() {
superview?.sendSubviewToBack(self)
}
// MARK: - 视图查找相关
extension UIView {
/// 通过tag查找子视图
/// - Parameter tag: 视图tag
/// - Returns: 找到的视图,如果没有找到返回nil
/// - Example:
/// ```
/// if let targetView = containerView.findSubview(withTag: 100) {
/// targetView.isHidden = true
/// }
/// ```
func findSubview(withTag tag: Int) -> UIView? {
return viewWithTag(tag)
}
/// 递归查找指定类型的第一个子视图
/// - Parameter type: 视图类型
/// - Returns: 找到的视图,如果没有找到返回nil
/// - Example:
/// ```
/// if let button = containerView.findFirstSubview(of: UIButton.self) {
/// button.isEnabled = false
/// }
/// ```
func findFirstSubview<T: UIView>(of type: T.Type) -> T? {
for subview in subviews {
if let targetView = subview as? T {
return targetView
}
if let found = subview.findFirstSubview(of: type) {
return found
}
}
return nil
}
}
}
6、截图和图像相关
swift
// MARK: - 截图和图像相关
extension UIView {
/// 截取视图截图
/// - Returns: 视图的截图
/// - Example:
/// ```
/// let screenshot = view.takeScreenshot()
/// imageView.image = screenshot
/// ```
func takeScreenshot() -> UIImage? {
UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main.scale)
defer { UIGraphicsEndImageContext() }
guard let context = UIGraphicsGetCurrentContext() else { return nil }
layer.render(in: context)
return UIGraphicsGetImageFromCurrentImageContext()
}
/// 截取视图指定区域的截图
/// - Parameter rect: 截图区域
/// - Returns: 指定区域的截图
/// - Example:
/// ```
/// let cropRect = CGRect(x: 0, y: 0, width: 100, height: 100)
/// let croppedImage = view.takeScreenshot(in: cropRect)
/// ```
func takeScreenshot(in rect: CGRect) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(rect.size, false, UIScreen.main.scale)
defer { UIGraphicsEndImageContext() }
guard let context = UIGraphicsGetCurrentContext() else { return nil }
context.translateBy(x: -rect.origin.x, y: -rect.origin.y)
layer.render(in: context)
return UIGraphicsGetImageFromCurrentImageContext()
}
}
7、约束相关扩展
swift
// MARK: - 约束相关扩展
extension UIView {
/// 设置视图相对于父视图的约束
/// - Parameters:
/// - top: 顶部边距
/// - left: 左边边距
/// - bottom: 底部边距
/// - right: 右边边距
/// - Note: 使用Auto Layout,确保translatesAutoresizingMaskIntoConstraints = false
/// - Example:
/// ```
/// view.pinToSuperview(top: 20, left: 16, bottom: 20, right: 16)
/// ```
func pinToSuperview(top: CGFloat? = nil,
left: CGFloat? = nil,
bottom: CGFloat? = nil,
right: CGFloat? = nil) {
guard let superview = superview else { return }
translatesAutoresizingMaskIntoConstraints = false
if let top = top {
topAnchor.constraint(equalTo: superview.topAnchor, constant: top).isActive = true
}
if let left = left {
leadingAnchor.constraint(equalTo: superview.leadingAnchor, constant: left).isActive = true
}
if let bottom = bottom {
superview.bottomAnchor.constraint(equalTo: bottomAnchor, constant: bottom).isActive = true
}
if let right = right {
superview.trailingAnchor.constraint(equalTo: trailingAnchor, constant: right).isActive = true
}
}
/// 设置视图尺寸约束
/// - Parameters:
/// - width: 宽度
/// - height: 高度
/// - Example:
/// ```
/// view.setSize(width: 100, height: 200)
/// ```
func setSize(width: CGFloat? = nil, height: CGFloat? = nil) {
translatesAutoresizingMaskIntoConstraints = false
if let width = width {
widthAnchor.constraint(equalToConstant: width).isActive = true
}
if let height = height {
heightAnchor.constraint(equalToConstant: height).isActive = true
}
}
/// 设置视图居中约束
/// - Parameters:
/// - centerX: 是否水平居中
/// - centerY: 是否垂直居中
/// - offsetX: 水平偏移量
/// - offsetY: 垂直偏移量
/// - Example:
/// ```
/// view.centerInSuperview(centerX: true, centerY: true, offsetX: 10, offsetY: -5)
/// ```
func centerInSuperview(centerX: Bool = false,
centerY: Bool = false,
offsetX: CGFloat = 0,
offsetY: CGFloat = 0) {
guard let superview = superview else { return }
translatesAutoresizingMaskIntoConstraints = false
if centerX {
centerXAnchor.constraint(equalTo: superview.centerXAnchor, constant: offsetX).isActive = true
}
if centerY {
centerYAnchor.constraint(equalTo: superview.centerYAnchor, constant: offsetY).isActive = true
}
}
}
8、手势相关扩展
swift
// MARK: - 手势相关扩展
extension UIView {
// MARK: - 私有方法和关联对象
public struct AssociatedKeys {
static var tapAction = "tapAction"
static var longPressAction = "longPressAction"
static var panAction = "panAction"
}
/// 添加点击手势
/// - Parameter action: 点击回调
/// - Example:
/// ```
/// view.addTapGesture {
/// print("视图被点击了")
/// }
/// ```
func addTapGesture(_ action: @escaping () -> Void) {
isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer()
tapGesture.addTarget(self, action: #selector(handleTapGesture(_:)))
addGestureRecognizer(tapGesture)
objc_setAssociatedObject(self, &AssociatedKeys.tapAction, action, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
/// 添加长按手势
/// - Parameters:
/// - minimumPressDuration: 最小按压时长
/// - action: 长按回调
/// - Example:
/// ```
/// view.addLongPressGesture(minimumPressDuration: 1.0) {
/// print("视图被长按了")
/// }
/// ```
func addLongPressGesture(minimumPressDuration: TimeInterval = 0.5, _ action: @escaping () -> Void) {
isUserInteractionEnabled = true
let longPressGesture = UILongPressGestureRecognizer()
longPressGesture.minimumPressDuration = minimumPressDuration
longPressGesture.addTarget(self, action: #selector(handleLongPressGesture(_:)))
addGestureRecognizer(longPressGesture)
objc_setAssociatedObject(self, &AssociatedKeys.longPressAction, action, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
/// 添加拖拽手势
/// - Parameter action: 拖拽回调,参数为拖拽手势识别器
/// - Example:
/// ```
/// view.addPanGesture { panGesture in
/// let translation = panGesture.translation(in: self.superview)
/// view.center = CGPoint(x: view.center.x + translation.x, y: view.center.y + translation.y)
/// panGesture.setTranslation(.zero, in: self.superview)
/// }
/// ```
func addPanGesture(_ action: @escaping (UIPanGestureRecognizer) -> Void) {
isUserInteractionEnabled = true
let panGesture = UIPanGestureRecognizer()
panGesture.addTarget(self, action: #selector(handlePanGesture(_:)))
addGestureRecognizer(panGesture)
objc_setAssociatedObject(self, &AssociatedKeys.panAction, action, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
}
9、安全区域相关 (iOS 11+)
swift
// MARK: - 安全区域相关 (iOS 11+)
extension UIView {
/// 获取安全区域边距
/// - Returns: 安全区域边距
/// - Example:
/// ```
/// let safeInsets = view.safeAreaLayoutMargins
/// print("Top safe area: \(safeInsets.top)")
/// ```
@available(iOS 11.0, *)
var safeAreaLayoutMargins: UIEdgeInsets {
return safeAreaInsets
}
/// 将视图固定到安全区域
/// - Parameters:
/// - top: 顶部边距
/// - leading: 左边边距
/// - bottom: 底部边距
/// - trailing: 右边边距
/// - Example:
/// ```
/// view.pinToSafeArea(top: 20, leading: 16, bottom: 20, trailing: 16)
/// ```
@available(iOS 11.0, *)
func pinToSafeArea(top: CGFloat? = nil,
leading: CGFloat? = nil,
bottom: CGFloat? = nil,
trailing: CGFloat? = nil) {
guard let superview = superview else { return }
translatesAutoresizingMaskIntoConstraints = false
if let top = top {
topAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.topAnchor, constant: top).isActive = true
}
if let leading = leading {
leadingAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.leadingAnchor, constant: leading).isActive = true
}
if let bottom = bottom {
superview.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor, constant: bottom).isActive = true
}
if let trailing = trailing {
superview.safeAreaLayoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor, constant: trailing).isActive = true
}
}
}
10、 工具方法
swift
// MARK: - 工具方法
extension UIView {
/// 检查视图是否完全可见
/// - Returns: 是否完全可见
/// - Example:
/// ```
/// if view.isCompletelyVisible {
/// print("视图完全可见")
/// }
/// ```
var isCompletelyVisible: Bool {
guard let superview = superview,
let window = window else { return false }
let viewFrameInWindow = superview.convert(frame, to: window)
return window.bounds.contains(viewFrameInWindow)
}
/// 获取视图的响应链
/// - Returns: 响应链数组
/// - Example:
/// ```
/// let chain = view.responderChain
/// chain.forEach { print(type(of: $0)) }
/// ```
var responderChain: [UIResponder] {
var chain: [UIResponder] = [self]
var current: UIResponder? = self
while let next = current?.next {
chain.append(next)
current = next
}
return chain
}
/// 将点转换为其他视图的坐标系
/// - Parameters:
/// - point: 原始点
/// - view: 目标视图
/// - Returns: 转换后的点
/// - Example:
/// ```
/// let pointInOtherView = view.convert(point: CGPoint(x: 10, y: 10), to: otherView)
/// ```
func convert(point: CGPoint, to view: UIView?) -> CGPoint {
return convert(point, to: view)
}
/// 检查点是否在视图内
/// - Parameter point: 要检查的点
/// - Returns: 是否在视图内
/// - Example:
/// ```
/// let touchPoint = CGPoint(x: 50, y: 50)
/// if view.contains(point: touchPoint) {
/// print("点在视图内")
/// }
/// ```
func contains(point: CGPoint) -> Bool {
return bounds.contains(point)
}
/// 检查两个视图是否重叠
/// - Parameter otherView: 另一个视图
/// - Returns: 是否重叠
/// - Example:
/// ```
/// if view1.isOverlapping(with: view2) {
/// print("两个视图重叠了")
/// }
/// ```
func isOverlapping(with otherView: UIView) -> Bool {
guard let superview = superview,
let otherSuperview = otherView.superview,
superview == otherSuperview else { return false }
return frame.intersects(otherView.frame)
}
/// 计算两个视图的重叠区域
/// - Parameter otherView: 另一个视图
/// - Returns: 重叠区域,如果不重叠返回nil
/// - Example:
/// ```
/// if let overlapRect = view1.overlapArea(with: view2) {
/// print("重叠区域: \(overlapRect)")
/// }
/// ```
func overlapArea(with otherView: UIView) -> CGRect? {
guard let superview = superview,
let otherSuperview = otherView.superview,
superview == otherSuperview else { return nil }
let intersection = frame.intersection(otherView.frame)
return intersection.isNull ? nil : intersection
}
/// 创建分隔线视图
/// - Parameters:
/// - color: 分隔线颜色
/// - thickness: 分隔线厚度
/// - horizontal: 是否为水平分隔线
/// - Returns: 分隔线视图
/// - Example:
/// ```
/// let separator = UIView.createSeparator(color: .lightGray, thickness: 1, horizontal: true)
/// containerView.addSubview(separator)
/// ```
static func createSeparator(color: UIColor = .lightGray,
thickness: CGFloat = 1,
horizontal: Bool = true) -> UIView {
let separator = UIView()
separator.backgroundColor = color
separator.translatesAutoresizingMaskIntoConstraints = false
if horizontal {
separator.heightAnchor.constraint(equalToConstant: thickness).isActive = true
} else {
separator.widthAnchor.constraint(equalToConstant: thickness).isActive = true
}
return separator
}
/// 创建间距视图
/// - Parameters:
/// - width: 宽度
/// - height: 高度
/// - Returns: 间距视图
/// - Example:
/// ```
/// let spacer = UIView.createSpacer(width: 20, height: 10)
/// stackView.addArrangedSubview(spacer)
/// ```
static func createSpacer(width: CGFloat = 0, height: CGFloat = 0) -> UIView {
let spacer = UIView()
spacer.backgroundColor = .clear
spacer.translatesAutoresizingMaskIntoConstraints = false
if width > 0 {
spacer.widthAnchor.constraint(equalToConstant: width).isActive = true
}
if height > 0 {
spacer.heightAnchor.constraint(equalToConstant: height).isActive = true
}
return spacer
}
/// 获取当前视图控制器
/// - Returns: 当前视图控制器
/// - Example:
/// ```
/// if let currentVC = view.currentViewController {
/// currentVC.present(alertController, animated: true)
/// }
/// ```
var currentViewController: UIViewController? {
var responder = next
while responder != nil {
if let viewController = responder as? UIViewController {
return viewController
}
responder = responder?.next
}
return nil
}
}
11、额外的几何计算扩展
swift
// MARK: - 额外的几何计算扩展
extension UIView {
/// 视图的对角线长度
/// - Returns: 对角线长度
/// - Example:
/// ```
/// let diagonal = view.diagonalLength
/// print("对角线长度: \(diagonal)")
/// ```
var diagonalLength: CGFloat {
return sqrt(width * width + height * height)
}
/// 视图的面积
/// - Returns: 视图面积
/// - Example:
/// ```
/// let area = view.area
/// print("视图面积: \(area)")
/// ```
var area: CGFloat {
return width * height
}
/// 视图的周长
/// - Returns: 视图周长
/// - Example:
/// ```
/// let perimeter = view.perimeter
/// print("视图周长: \(perimeter)")
/// ```
var perimeter: CGFloat {
return 2 * (width + height)
}
/// 获取视图的四个角的坐标点
/// - Returns: 包含四个角坐标的数组 [左上, 右上, 右下, 左下]
/// - Example:
/// ```
/// let corners = view.cornerPoints
/// print("左上角: \(corners[0])")
/// ```
var cornerPoints: [CGPoint] {
return [
CGPoint(x: x, y: y), // 左上
CGPoint(x: right, y: y), // 右上
CGPoint(x: right, y: bottom), // 右下
CGPoint(x: x, y: bottom) // 左下
]
}
}
12、状态相关扩展
swift
// MARK: - 状态相关扩展
extension UIView {
/// 视图是否真正可见(不仅仅是hidden=false)
/// - Returns: 是否真正可见
/// - Note: 检查alpha、hidden、superview等因素
/// - Example:
/// ```
/// if view.isActuallyVisible {
/// print("视图真正可见")
/// }
/// ```
var isActuallyVisible: Bool {
return !isHidden && alpha > 0 && superview != nil && window != nil
}
/// 切换视图的显示/隐藏状态
/// - Parameter animated: 是否使用动画
/// - Example:
/// ```
/// view.toggleVisibility(animated: true)
/// ```
func toggleVisibility(animated: Bool = false) {
if animated {
if isHidden {
isHidden = false
fadeIn()
} else {
fadeOut { [weak self] in
self?.isHidden = true
self?.alpha = 1 // 重置alpha以备下次显示
}
}
} else {
isHidden.toggle()
}
}
/// 设置视图启用/禁用状态(包括所有子视图)
/// - Parameters:
/// - enabled: 是否启用
/// - alpha: 禁用时的透明度
/// - Example:
/// ```
/// containerView.setEnabled(false, alpha: 0.5)
/// ```
func setEnabled(_ enabled: Bool, alpha: CGFloat = 0.5) {
isUserInteractionEnabled = enabled
self.alpha = enabled ? 1.0 : alpha
subviews.forEach { subview in
if let control = subview as? UIControl {
control.isEnabled = enabled
} else {
subview.setEnabled(enabled, alpha: alpha)
}
}
}
}
13、主题和样式相关扩展
swift
// MARK: - 主题和样式相关扩展
extension UIView {
/// 应用圆形样式
/// - Note: 会根据视图的最小边长设置圆角
/// - Example:
/// ```
/// avatarImageView.makeCircular()
/// ```
func makeCircular() {
layer.cornerRadius = min(width, height) / 2
clipsToBounds = true
}
/// 应用卡片样式
/// - Parameters:
/// - cornerRadius: 圆角半径
/// - shadowOpacity: 阴影透明度
/// - shadowOffset: 阴影偏移
/// - shadowRadius: 阴影半径
/// - Example:
/// ```
/// cardView.applyCardStyle(cornerRadius: 12, shadowOpacity: 0.1)
/// ```
func applyCardStyle(cornerRadius: CGFloat = 8,
shadowOpacity: Float = 0.1,
shadowOffset: CGSize = CGSize(width: 0, height: 2),
shadowRadius: CGFloat = 4) {
backgroundColor = backgroundColor ?? .white
layer.cornerRadius = cornerRadius
layer.shadowColor = UIColor.black.cgColor
layer.shadowOpacity = shadowOpacity
layer.shadowOffset = shadowOffset
layer.shadowRadius = shadowRadius
layer.masksToBounds = false
}
/// 应用按钮样式
/// - Parameters:
/// - cornerRadius: 圆角半径
/// - borderWidth: 边框宽度
/// - borderColor: 边框颜色
/// - Example:
/// ```
/// buttonView.applyButtonStyle(cornerRadius: 8, borderWidth: 1, borderColor: .blue)
/// ```
func applyButtonStyle(cornerRadius: CGFloat = 8,
borderWidth: CGFloat = 1,
borderColor: UIColor = .systemBlue) {
layer.cornerRadius = cornerRadius
layer.borderWidth = borderWidth
layer.borderColor = borderColor.cgColor
clipsToBounds = true
}
}
14、调试相关
swift
// MARK: - 调试相关
extension UIView {
/// 为视图添加调试边框
/// - Parameters:
/// - color: 边框颜色
/// - width: 边框宽度
/// - Example:
/// ```
/// #if DEBUG
/// view.addDebugBorder(color: .red, width: 1)
/// #endif
/// ```
func addDebugBorder(color: UIColor = .red, width: CGFloat = 1) {
#if DEBUG
layer.borderColor = color.cgColor
layer.borderWidth = width
#endif
}
/// 打印视图层次结构
/// - Parameter level: 层级缩进
/// - Example:
/// ```
/// #if DEBUG
/// view.printHierarchy()
/// #endif
/// ```
func printHierarchy(level: Int = 0) {
#if DEBUG
let indent = String(repeating: " ", count: level)
print("\(indent)\(type(of: self)) - frame: \(frame)")
for subview in subviews {
subview.printHierarchy(level: level + 1)
}
#endif
}
/// 为视图添加标识标签(调试用)
/// - Parameter text: 标签文本
/// - Example:
/// ```
/// #if DEBUG
/// view.addDebugLabel("MainView")
/// #endif
/// ```
func addDebugLabel(_ text: String) {
#if DEBUG
let label = UILabel()
label.text = text
label.font = UIFont.systemFont(ofSize: 10)
label.textColor = .red
label.backgroundColor = UIColor.white.withAlphaComponent(0.8)
label.sizeToFit()
label.frame.origin = CGPoint(x: 2, y: 2)
addSubview(label)
#endif
}
}
15、链式编程支持
swift
// MARK: - 链式编程支持
extension UIView {
/// 设置背景色(链式调用)
/// - Parameter color: 背景色
/// - Returns: 自身实例,支持链式调用
/// - Example:
/// ```
/// let view = UIView()
/// .backgroundColor(.red)
/// .cornerRadius(8)
/// .border(width: 1, color: .black)
/// ```
@discardableResult
func backgroundColor(_ color: UIColor) -> Self {
backgroundColor = color
return self
}
/// 设置透明度(链式调用)
/// - Parameter alpha: 透明度
/// - Returns: 自身实例,支持链式调用
@discardableResult
func alpha(_ alpha: CGFloat) -> Self {
self.alpha = alpha
return self
}
/// 设置圆角(链式调用)
/// - Parameter radius: 圆角半径
/// - Returns: 自身实例,支持链式调用
@discardableResult
func cornerRadius(_ radius: CGFloat) -> Self {
layer.cornerRadius = radius
clipsToBounds = true
return self
}
/// 设置边框(链式调用)
/// - Parameters:
/// - width: 边框宽度
/// - color: 边框颜色
/// - Returns: 自身实例,支持链式调用
@discardableResult
func border(width: CGFloat, color: UIColor) -> Self {
layer.borderWidth = width
layer.borderColor = color.cgColor
return self
}
/// 设置阴影(链式调用)
/// - Parameters:
/// - color: 阴影颜色
/// - opacity: 阴影透明度
/// - offset: 阴影偏移
/// - radius: 阴影半径
/// - Returns: 自身实例,支持链式调用
@discardableResult
func shadow(color: UIColor = .black,
opacity: Float = 0.3,
offset: CGSize = CGSize(width: 0, height: 2),
radius: CGFloat = 4) -> Self {
layer.shadowColor = color.cgColor
layer.shadowOpacity = opacity
layer.shadowOffset = offset
layer.shadowRadius = radius
layer.masksToBounds = false
return self
}
/// 设置用户交互(链式调用)
/// - Parameter enabled: 是否启用用户交互
/// - Returns: 自身实例,支持链式调用
@discardableResult
func userInteraction(_ enabled: Bool) -> Self {
isUserInteractionEnabled = enabled
return self
}
/// 设置标签(链式调用)
/// - Parameter tag: 标签值
/// - Returns: 自身实例,支持链式调用
@discardableResult
func tag(_ tag: Int) -> Self {
self.tag = tag
return self
}
/// 设置指定角圆角(链式调用)
/// - Parameters:
/// - corners: 要设置圆角的角
/// - radius: 圆角半径
/// - Returns: 自身实例,支持链式调用
/// - Example:
/// ```
/// let cardView = UIView()
/// .backgroundColor(.white)
/// .roundCorners([.topLeft, .topRight], radius: 16)
/// .shadow(color: .black, opacity: 0.1)
/// ```
@discardableResult
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) -> Self {
setRoundCorners(corners, radius: radius)
return self
}
/// 设置顶部圆角(链式调用)
/// - Parameter radius: 圆角半径
/// - Returns: 自身实例,支持链式调用
@discardableResult
func roundTopCorners(radius: CGFloat) -> Self {
setRoundTopCorners(radius: radius)
return self
}
/// 设置底部圆角(链式调用)
/// - Parameter radius: 圆角半径
/// - Returns: 自身实例,支持链式调用
@discardableResult
func roundBottomCorners(radius: CGFloat) -> Self {
setRoundBottomCorners(radius: radius)
return self
}
/// 设置左侧圆角(链式调用)
/// - Parameter radius: 圆角半径
/// - Returns: 自身实例,支持链式调用
@discardableResult
func roundLeftCorners(radius: CGFloat) -> Self {
setRoundLeftCorners(radius: radius)
return self
}
/// 设置右侧圆角(链式调用)
/// - Parameter radius: 圆角半径
/// - Returns: 自身实例,支持链式调用
@discardableResult
func roundRightCorners(radius: CGFloat) -> Self {
setRoundRightCorners(radius: radius)
return self
}
}
16、高级动画和效果扩展
swift
// MARK: - 高级动画和效果扩展
extension UIView {
// MARK: - 粒子效果类型枚举
enum ParticleType {
case confetti
case snow
case stars
}
/// 创建波纹效果动画
/// - Parameters:
/// - center: 波纹中心点
/// - color: 波纹颜色
/// - duration: 动画时长
/// - Example:
/// ```
/// view.addRippleEffect(center: tapLocation, color: .blue, duration: 0.6)
/// ```
func addRippleEffect(center: CGPoint, color: UIColor = .lightGray, duration: TimeInterval = 0.6) {
let rippleLayer = CALayer()
let diameter = max(bounds.width, bounds.height) * 2
rippleLayer.frame = CGRect(x: center.x - diameter/2, y: center.y - diameter/2, width: diameter, height: diameter)
rippleLayer.cornerRadius = diameter / 2
rippleLayer.backgroundColor = color.cgColor
rippleLayer.opacity = 0.3
layer.addSublayer(rippleLayer)
let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")
scaleAnimation.fromValue = 0
scaleAnimation.toValue = 1
let opacityAnimation = CABasicAnimation(keyPath: "opacity")
opacityAnimation.fromValue = 0.3
opacityAnimation.toValue = 0
let groupAnimation = CAAnimationGroup()
groupAnimation.animations = [scaleAnimation, opacityAnimation]
groupAnimation.duration = duration
groupAnimation.timingFunction = CAMediaTimingFunction(name: .easeOut)
CATransaction.begin()
CATransaction.setCompletionBlock {
rippleLayer.removeFromSuperlayer()
}
rippleLayer.add(groupAnimation, forKey: "ripple")
CATransaction.commit()
}
/// 添加粒子效果
/// - Parameters:
/// - type: 粒子类型
/// - colors: 粒子颜色数组
/// - duration: 效果持续时间
/// - Example:
/// ```
/// view.addParticleEffect(type: .confetti, colors: [.red, .blue, .yellow], duration: 3.0)
/// ```
func addParticleEffect(type: ParticleType, colors: [UIColor], duration: TimeInterval = 2.0) {
let emitterLayer = CAEmitterLayer()
emitterLayer.emitterPosition = CGPoint(x: bounds.midX, y: bounds.minY)
emitterLayer.emitterShape = .line
emitterLayer.emitterSize = CGSize(width: bounds.width, height: 1)
var emitterCells: [CAEmitterCell] = []
for color in colors {
let cell = CAEmitterCell()
cell.birthRate = 10
cell.lifetime = Float(duration)
cell.velocity = 100
cell.velocityRange = 50
cell.emissionRange = .pi / 4
cell.scale = 0.3
cell.scaleRange = 0.2
cell.color = color.cgColor
switch type {
case .confetti:
cell.contents = createConfettiImage().cgImage
cell.spin = .pi
cell.spinRange = .pi
case .snow:
cell.contents = createSnowflakeImage().cgImage
cell.yAcceleration = 50
case .stars:
cell.contents = createStarImage().cgImage
cell.spin = .pi / 2
}
emitterCells.append(cell)
}
emitterLayer.emitterCells = emitterCells
layer.addSublayer(emitterLayer)
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
emitterLayer.removeFromSuperlayer()
}
}
/// 添加发光效果
/// - Parameters:
/// - color: 发光颜色
/// - radius: 发光半径
/// - opacity: 发光透明度
/// - Example:
/// ```
/// button.addGlowEffect(color: .blue, radius: 10, opacity: 0.8)
/// ```
func addGlowEffect(color: UIColor, radius: CGFloat = 10, opacity: Float = 0.8) {
layer.shadowColor = color.cgColor
layer.shadowOffset = .zero
layer.shadowRadius = radius
layer.shadowOpacity = opacity
layer.masksToBounds = false
// 添加动态发光动画
let pulseAnimation = CABasicAnimation(keyPath: "shadowOpacity")
pulseAnimation.fromValue = opacity * 0.3
pulseAnimation.toValue = opacity
pulseAnimation.duration = 1.0
pulseAnimation.repeatCount = .infinity
pulseAnimation.autoreverses = true
pulseAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
layer.add(pulseAnimation, forKey: "glowPulse")
}
/// 移除发光效果
/// - Example:
/// ```
/// button.removeGlowEffect()
/// ```
func removeGlowEffect() {
layer.removeAnimation(forKey: "glowPulse")
layer.shadowOpacity = 0
layer.shadowRadius = 0
}
// MARK: - 私有辅助方法
private func createConfettiImage() -> UIImage {
let size = CGSize(width: 10, height: 10)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
defer { UIGraphicsEndImageContext() }
let context = UIGraphicsGetCurrentContext()!
context.setFillColor(UIColor.red.cgColor)
context.fillEllipse(in: CGRect(origin: .zero, size: size))
return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
}
private func createSnowflakeImage() -> UIImage {
let size = CGSize(width: 8, height: 8)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
defer { UIGraphicsEndImageContext() }
let context = UIGraphicsGetCurrentContext()!
context.setFillColor(UIColor.white.cgColor)
context.fillEllipse(in: CGRect(origin: .zero, size: size))
return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
}
private func createStarImage() -> UIImage {
let size = CGSize(width: 12, height: 12)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
defer { UIGraphicsEndImageContext() }
let context = UIGraphicsGetCurrentContext()!
context.setFillColor(UIColor.yellow.cgColor)
// 绘制星形
let center = CGPoint(x: size.width/2, y: size.height/2)
let radius: CGFloat = 5
context.move(to: CGPoint(x: center.x, y: center.y - radius))
// 简化的星形绘制
context.addLine(to: CGPoint(x: center.x + radius, y: center.y + radius))
context.addLine(to: CGPoint(x: center.x - radius, y: center.y + radius/3))
context.addLine(to: CGPoint(x: center.x + radius, y: center.y + radius/3))
context.addLine(to: CGPoint(x: center.x - radius, y: center.y + radius))
context.closePath()
context.fillPath()
return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
}
}
17、布局相关高级扩展
swift
// MARK: - 布局相关高级扩展
extension UIView {
/// 创建视图的快照视图
/// - Returns: 快照视图
/// - Example:
/// ```
/// let snapshot = originalView.createSnapshot()
/// containerView.addSubview(snapshot)
/// ```
func createSnapshot() -> UIView {
let snapshotView = UIView(frame: frame)
snapshotView.backgroundColor = backgroundColor
snapshotView.layer.contents = takeScreenshot()?.cgImage
return snapshotView
}
/// 均匀分布子视图(水平)
/// - Parameters:
/// - subviews: 要分布的子视图数组
/// - margin: 左右边距
/// - spacing: 视图间距
/// - Example:
/// ```
/// containerView.distributeSubviewsHorizontally(subviews: [view1, view2, view3], margin: 20, spacing: 10)
/// ```
func distributeSubviewsHorizontally(_ subviews: [UIView], margin: CGFloat = 0, spacing: CGFloat = 0) {
guard !subviews.isEmpty else { return }
let totalSpacing = spacing * CGFloat(subviews.count - 1)
let totalMargin = margin * 2
let availableWidth = width - totalSpacing - totalMargin
let viewWidth = availableWidth / CGFloat(subviews.count)
for (index, subview) in subviews.enumerated() {
let x = margin + (viewWidth + spacing) * CGFloat(index)
subview.frame = CGRect(x: x, y: subview.y, width: viewWidth, height: subview.height)
if subview.superview != self {
addSubview(subview)
}
}
}
/// 均匀分布子视图(垂直)
/// - Parameters:
/// - subviews: 要分布的子视图数组
/// - margin: 上下边距
/// - spacing: 视图间距
/// - Example:
/// ```
/// containerView.distributeSubviewsVertically(subviews: [view1, view2, view3], margin: 20, spacing: 10)
/// ```
func distributeSubviewsVertically(_ subviews: [UIView], margin: CGFloat = 0, spacing: CGFloat = 0) {
guard !subviews.isEmpty else { return }
let totalSpacing = spacing * CGFloat(subviews.count - 1)
let totalMargin = margin * 2
let availableHeight = height - totalSpacing - totalMargin
let viewHeight = availableHeight / CGFloat(subviews.count)
for (index, subview) in subviews.enumerated() {
let y = margin + (viewHeight + spacing) * CGFloat(index)
subview.frame = CGRect(x: subview.x, y: y, width: subview.width, height: viewHeight)
if subview.superview != self {
addSubview(subview)
}
}
}
/// 网格布局子视图
/// - Parameters:
/// - subviews: 要布局的子视图数组
/// - columns: 列数
/// - spacing: 间距
/// - margin: 边距
/// - Example:
/// ```
/// containerView.layoutSubviewsInGrid(subviews: imageViews, columns: 3, spacing: 10, margin: 20)
/// ```
func layoutSubviewsInGrid(_ subviews: [UIView], columns: Int, spacing: CGFloat = 0, margin: CGFloat = 0) {
guard !subviews.isEmpty && columns > 0 else { return }
let rows = Int(ceil(Double(subviews.count) / Double(columns)))
let availableWidth = width - margin * 2 - spacing * CGFloat(columns - 1)
let availableHeight = height - margin * 2 - spacing * CGFloat(rows - 1)
let itemWidth = availableWidth / CGFloat(columns)
let itemHeight = availableHeight / CGFloat(rows)
for (index, subview) in subviews.enumerated() {
let row = index / columns
let column = index % columns
let x = margin + (itemWidth + spacing) * CGFloat(column)
let y = margin + (itemHeight + spacing) * CGFloat(row)
subview.frame = CGRect(x: x, y: y, width: itemWidth, height: itemHeight)
if subview.superview != self {
addSubview(subview)
}
}
}
}
18、性能优化相关扩展
swift
// MARK: - 性能优化相关扩展
extension UIView {
/// 启用/禁用光栅化以优化性能
/// - Parameter enabled: 是否启用光栅化
/// - Example:
/// ```
/// complexView.setRasterization(enabled: true) // 提升滚动性能
/// ```
func setRasterization(enabled: Bool) {
layer.shouldRasterize = enabled
layer.rasterizationScale = enabled ? UIScreen.main.scale : 1.0
}
/// 预加载视图(触发布局和渲染)
/// - Example:
/// ```
/// heavyView.preload() // 在后台预加载复杂视图
/// ```
func preload() {
_ = layer.presentation()
layoutIfNeeded()
}
/// 异步更新UI
/// - Parameter updates: 更新操作
/// - Example:
/// ```
/// view.asyncUpdateUI {
/// // 执行UI更新
/// self.backgroundColor = .red
/// }
/// ```
func asyncUpdateUI(_ updates: @escaping () -> Void) {
DispatchQueue.main.async {
updates()
}
}
}