WandioCoreComponents 0.0.7

WandioCoreComponents 0.0.7

Kakhi Kiknadze 维护。



  • Kakhi Kiknadze

WandioCoreComponents

Version License Platform

一组自定义 UI 组件。

在内容和阴影周围都创建一个圆形半径的视图

  • RoundedShadowedView
  • RoundedShadowedButton
  • RoundedShadowedControl
  • RoundedShadowedTextField

示例

要运行示例项目,请克隆仓库并构建 WandioCoreComponentsExample 目标。

安装

WandioCoreComponents 通过 CocoaPods 提供使用。要安装它,只需将以下行添加到 Podfile 中

pod 'WandioCoreComponents'

用法

首先导入 WandioCoreComponents

import WandioCoreComponents

RoundedShadowedView

let shadowedView = RoundedShadowedView(frame: CGRect(x: 40, y: 40, width: 200, height: 100))
shadowedView.backgroundLayerColor = .red
shadowedView.backgroundLayerLineWidth = 4
shadowedView.backgroundLayerStrokeColor = .yellow
shadowedView.shadowColor = .black
shadowedView.shadowAlpha = 0.7
shadowedView.shadowRadius = 24
shadowedView.cornerRadius = 20
shadowedView.shadowOffset = CGSize(width: 3, height: 8)
view.addSubview(shadowedView)

或者设置以来Storyboard中的值
您可以将这些值乘以 screenFactor 以适应所有设备。如果是这样,您需要先设置 screenFactor。例如,当应用完成启动时。默认的 screenFactor 值为 1.0。

  • RoundedShadowedButton, RoundedShadowedControl, RoundedShadowedTextField
    使用与 RoundedShadowedView 相同的步骤。

CustomIntensityVisualEffectView

具有自定义强度值的视觉效果视图。您可以将其初始化为其父 UIVisualEffectView。唯一的不同之处在于您可以为效果提供强度值。

OTPView

您可以通过提供所需的文本字段数量来初始化单次有效密码视图,并处理所有文本字段之间的切换、自动填充、粘贴、返回当前 OTP 字符串、通知是否填写了所有字段等。

您可以子类化 OTPTextField 并注册您的自定义字段

class CustomField: OTPTextField {
	// Create your custom textfield
}

class ViewController: UIViewController {
	
    let otpView = OTPView()
    
    override func viewDidLoad() {
    	super.viewDidLoad()
        otpView.register(CustomField.self)
    }
    
}

OTPTextFieldRoundedShadowedTextField 的子类,因此您可以给它提供阴影和圆角半径。

您可以为文本字段提供水平、垂直填充和彼此之间的间距

otpView.spacing = 8
otpView.verticalPadding = 12
otpView.horizontalPadding = 20

verticalPadding 会被除以二,结果分配给字段的 y 原点。同样,horizontalPadding 也会被除以二,但其结果分配给第一个字段的 x 原点。

您可以为 OTPView 设置 delegate 并实现方法。当设置委托或显式调用 OTPView 上的 reload() 时,会调用这些方法。

func otpView(_ view: OTPView, didChangeValidity isValid: Bool, otp: String) // is valid if all fields are filled
func otpView(_ view: OTPView, textField field: OTPTextField, at index: Int) // returns the field at corresponding index and you can make some special modifications there.

通过显式调用 remakeFields(),将删除所有当前字段,并使用提供的字段数量创建新的字段。

您可以通过调用 getOTP() 来获取当前的 OTP 字符串,通过调用 showKeyboard()hideKeyboard()(显示键盘并聚焦到第一个字段)来显示/隐藏键盘,并通过调用 reset() 来重置 OTP 字符串。

通过在 OTPView 上调用 func updateState(_ state: OTPTextFieldState),您可以触发每个字段的 updateState 实现,并提供 .normal.error 状态。

OTPTextField

OTPTextFieldpreviousTextFieldnextTextFieldweak 引用。

它还具有状态 OTPTextFieldState,包含了 .normal.error 的情况。您可以通过调用 updateState(.error) 等方式改变状态,默认情况下,它将设置笔触颜色为 .red 并将边框的线条宽度设置为 2。当然,您可以通过子类化 OTPTextField 并重写 func updateState(_ state: OTPTextFieldState) 方法来创建自己的 UI 逻辑。

WandioBottomSheet

可扩展/折叠的底部框主要由三个主要内容构成:背景视图、处理区域和内容视图。您可以拖动处理区域或内容视图以展开、折叠或关闭底部框。点击背景也会触发关闭。

您可以通过继承 WandioBottomSheet 来创建自己的处理和内容实例。您可以使用 WandioBottomSheetHandlerView 作为处理区域或创建自己的自定义视图。处理区域可以通过不提供它来忽略,并且您可以用仅内容视图来使用。

class BottomSheetContent: UIView {
    
    let child = UIView()
    let label = UILabel()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        addSubview(child)
        child.backgroundColor = .clear
        child.translatesAutoresizingMaskIntoConstraints = false
        child.heightAnchor.constraint(equalToConstant: 360).isActive = true
        child.topAnchor.constraint(equalTo: topAnchor).isActive = true
        child.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        child.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        child.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        label.text = "Content"
        label.translatesAutoresizingMaskIntoConstraints = false
        child.addSubview(label)
        label.centerXAnchor.constraint(equalTo: child.centerXAnchor).isActive = true
        label.bottomAnchor.constraint(equalTo: child.safeAreaLayoutGuide.bottomAnchor).isActive = true
    }
    
    required init?(coder: NSCoder) {
        fatalError()
    }
    
}

class CustomBottomSheet: WandioBottomSheet {
    
    private let handler = WandioBottomSheetHandlerView()
    private let content = BottomSheetContent()
    
    public override init(frame: CGRect) {
        super.init(frame: frame)
        configure()
    }
    
    public required init?(coder: NSCoder) {
        super.init(coder: coder)
        configure()
    }
    
    private func configure() {
        contentHeight = 300 * screenFactor // setting contentHeight will fix content height by given value and ignore its original height
        addHandle(handler)
        addContent(content)
    }
    
}

class YourViewController: UIViewController {
  
  // Present bottom sheet by calling present on view controller or view itself

    @objc private func presentDefaultWandioBottomSheet() {
        DefaultWandioBottomSheet().present(on: self)
    }
    
    @objc private func presentCustomBottomSheet() {
        CustomBottomSheet().present(on: self)
    }
    
}

通过设置底部框的 delegate,您可以在拖动过程中实现这些方法并添加自己的自定义逻辑,例如在视图控制器或其他地方添加一些额外的动画。

/// Tells the delegate that bottom sheet pan gesture began
func bottomSheet(_ sheet: WandioBottomSheet, didBeginPanGesture recognizer: UIPanGestureRecognizer)
/// Tells the delegate that bottom sheet pan gesture changed
func bottomSheet(_ sheet: WandioBottomSheet, didChangePanGesture recognizer: UIPanGestureRecognizer)
/// Tells the delegate that bottom sheet pan gesture ended
func bottomSheet(_ sheet: WandioBottomSheet, didEndPanGesture recognizer: UIPanGestureRecognizer)

您可以在 WandioBottomSheet 子类中覆盖拖动手势期间调用的方法来自定义行为。

open func beganPanGesture(_ recognizer: UIPanGestureRecognizer)

open func changedPanGesture(_ recognizer: UIPanGestureRecognizer)

open func endedPanGesture(_ recognizer: UIPanGestureRecognizer)

您可以通过调用来添加内容和处理区域的子视图。

func addContent(_ content: UIView, at index: Int? = nil)
func addHandle(_ handle: UIView, at index: Int? = nil)

ImageLoader

从网络下载图像或从缓存中加载它。通过对 UIImageView 的简单扩展,您可以选择 UIImage 并设置它。

let imageView = UIImageView()
let url = URL(string: "www.yourimageurl.com")!
imageView.setImage(from: url, placeholderImage: UIImage(named: "youtImage"), cachePolicy: .useProtocolCachePolicy, completion: nil)

LoaderView

UIView 子类,具有 isLoading 属性和 start()stop() 方法来设置 isLoading 为真或假。继承 LoaderView 并创建自己的自定义加载器。重写 startstop 方法并触发你自己的自定义动画等。一旦你的自定义加载器完成,你可以将其分配到 LoaderView.shared,并通过简单地调用 startLoader()stopLoader()(要么在视图控制器上,要么在视图上)来开始或停止你的自定义加载动画。或者,你可以有你的自定义加载器实例在你的控制器或视图中,并将其作为参数发送。例如,startLoader(YourCustomLoader())

假设你有一个自定义加载器类

class MyLoader: LoaderView {
    
    let indicator = UIActivityIndicatorView(style: .large)
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
    }
    
    private func setup() {
        backgroundColor = UIColor.red.withAlphaComponent(0.5)
        addSubview(indicator)
        indicator.translatesAutoresizingMaskIntoConstraints = false
        indicator.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
        indicator.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
    }
    
    override func start() {
        super.start()
        indicator.startAnimating()
    }
    
    override func stop() {
        super.stop()
        indicator.stopAnimating()
    }
    
}

将加载器设置为 LoaderView.shared 实例,并且调用不带参数的加载方法将呈现出你的自定义加载器

class ViewController: UIViewController {
  
    let loader = MyLoader()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        LoaderView.shared = loader
    }

    @IBAction func buttonTap(_ sender: UIButton) {
        startLoader()
        DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
            self.stopLoader()
        }
    }
    
}

或者,如果你想为特殊情况进行不同的加载器,你可以将加载器实例存储在你的类中,并将其作为参数发送

class ViewController: UIViewController {
  
    let loader = MyLoader()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        LoaderView.shared = loader
    }

    @IBAction func buttonTap(_ sender: UIButton) {
        startLoader(loader)
        DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
            self.stopLoader(loader)
        }
    }
    
}

作者

卡奇·基克纳兹,[email protected]

许可证

WandioCoreComponents 在MIT 许可证下可用。有关更多信息,请参阅Licence文件。