動態

詳情 返回 返回

推薦一款Swift開發框架 - Aquarius - 動態 詳情

大家好,我是K哥。一名獨立開發者,同時也是Swift開發框架【Aquarius】的作者,悦記愛尋車app的開發者。

Aquarius開發框架旨在幫助獨立開發者和中小型團隊,完成iOS App的快速實現與迭代。使用框架開發將給你帶來簡單、高效、易維護的編程體驗。


介紹

大家好,我是K哥,一名10多年的iOS老鳥。Swift開發框架 - Aquarius作者,悦記和愛尋車兩款app的開發者。

今天和大家推薦一下我開源的Swift開發框架 - Aquarius

Aquarius旨在幫助獨立開發者和中小型團隊,完成iOS App的快速實現與迭代。使用框架開發將給你帶來簡單、高效、易維護的編程體驗。

希望這款開發框架能夠幫助到大家。

框架地址:

https://github.com/JZXStudio/Aquarius
Aquarius.png

描述

Aquarius是以幫助獨立開發者規範化開發流程,提高開發效率為目的而設計的Swift開發框架。

框架提供高效率、低侵入式的framework,既支持新的項目工程,也支持加入到老的工程中

框架本身不依賴任何三方類庫,不會增大項目體積

框架以MVVM設計模式為核心,通過一系列定義的方法,提供新的開發方式

框架建議通過方法設置UI組件的屬性,基於此原則,重新封裝了大部分UI組件的屬性

框架提供數據綁定功能,既支持變量間的動態數據更新,也支持變量與UI組件屬性的動態數據更新

要求

  • iOS15.0
  • Swift5.x

新增功能

液態玻璃效果

新增按鈕的液態玻璃效果。

液態玻璃效果包括:

  1. Glass
  2. ClearGlass
  3. ProminentGlass
  4. ProminentClearGlass

針對以上四種按鈕液態玻璃效果,框架新增2個枚舉類型,包括:

  1. LiquidGlassType

    1. glass
    2. clearGlass
    3. prominentGlass
    4. prominentClearGlass
  2. LiquidGlassConfig

    1. title
    2. attributedTitle
    3. subtitle
    4. attributedSubtitle
    5. titlePadding
    6. titleAlignment
    7. image
    8. imagePadding
    9. baseForegroundColor
    10. baseBackgroundColor

新增的方法包括:

public func liquid(_ config: UIButton.Configuration)
public func liquid(
        type: LiquidGlassType,
        title: String?=nil,
        attributedTitle: AttributedString?=nil,
        subtitle: String?=nil,
        attributedSubtitle: AttributedString?=nil,
        titlePadding: CGFloat?=nil,
        titleAlignment:UIButton.Configuration.TitleAlignment?=nil,
        image: UIImage?=nil,
        imagePadding: CGFloat?=nil,
        baseForegroundColor: UIColor?=nil,
        baseBackgroundColor: UIColor?=nil)
public func liquid(type: LiquidGlassType, config: [LiquidGlassConfig : Any]?=nil)

<!---->

public func liquid_Glass(
        title: String?=nil,
        attributedTitle: AttributedString?=nil,
        subtitle: String?=nil,
        attributedSubtitle: AttributedString?=nil,
        titlePadding: CGFloat?=nil,
        titleAlignment:UIButton.Configuration.TitleAlignment?=nil,
        image: UIImage?=nil,
        imagePadding: CGFloat?=nil,
        baseForegroundColor: UIColor?=nil,
        baseBackgroundColor: UIColor?=nil)
public func liquid_Glass(_ config: [LiquidGlassConfig : Any]?=nil)

<!---->

public func liquid_ClearGlass(
        title: String?=nil,
        attributedTitle: AttributedString?=nil,
        subtitle: String?=nil,
        attributedSubtitle: AttributedString?=nil,
        titlePadding: CGFloat?=nil,
        titleAlignment:UIButton.Configuration.TitleAlignment?=nil,
        image: UIImage?=nil,
        imagePadding: CGFloat?=nil,
        baseForegroundColor: UIColor?=nil,
        baseBackgroundColor: UIColor?=nil)
public func liquid_ClearGlass(_ config: [LiquidGlassConfig : Any]?=nil)

<!---->

public func liquid_ProminentGlass(
        title: String?=nil,
        attributedTitle: AttributedString?=nil,
        subtitle: String?=nil,
        attributedSubtitle: AttributedString?=nil,
        titlePadding: CGFloat?=nil,
        titleAlignment:UIButton.Configuration.TitleAlignment?=nil,
        image: UIImage?=nil,
        imagePadding: CGFloat?=nil,
        baseForegroundColor: UIColor?=nil,
        baseBackgroundColor: UIColor?=nil)
public func liquid_ProminentGlass(_ config: [LiquidGlassConfig : Any]?=nil)

<!---->

public func liquid_ProminentClearGlass(
        title: String?=nil,
        attributedTitle: AttributedString?=nil,
        subtitle: String?=nil,
        attributedSubtitle: AttributedString?=nil,
        titlePadding: CGFloat?=nil,
        titleAlignment:UIButton.Configuration.TitleAlignment?=nil,
        image: UIImage?=nil,
        imagePadding: CGFloat?=nil,
        baseForegroundColor: UIColor?=nil,
        baseBackgroundColor: UIColor?=nil)
public func liquid_ProminentClearGlass(_ config: [LiquidGlassConfig : Any]?=nil)

liquid

單獨設置UIButton.Configuration

示例:

let button: UIButton = A.ui.button
var config: UIButton.Configuration = UIButton.Configuration.glass()
config.title = "test"
button.liquid(config)

設置液態玻璃類型,並做相關配置

示例:

let button: UIButton = A.ui.button
button.liguid(type: .glass, title: "test"...)

設置液態玻璃類型,並通過字典做相關配置

示例:

let type: LiquidGlassType = .glass
let config: [LiquidGlassConfig: Any] = [
    title : "test"
]
let button: UIButton = A.ui.button
button.liquid(type, config)

liquid\_Glass

設置Glass液態玻璃類型,並做相關配置

示例:

let button: UIButton = A.ui.button
button.liguid_Glass(title: "test")

設置Glass液態玻璃類型,並通過字典做相關配置

let config: [LiquidGlassConfig : Any] = [
   .title : "test"
]
let button: UIButton = A.ui.button
button.liquid_Glass(config)

liquid\_ClearGlass

設置ClearGlass液態玻璃類型,並做相關配置

示例:

let button: UIButton = A.ui.button
button.liguid_ClearGlass(title: "test")

設置ClearGlass液態玻璃類型,並通過字典做相關配置

let config: [LiquidGlassConfig : Any] = [
   .title : "test"
]
let button: UIButton = A.ui.button
button.liquid_ClearGlass(config)

liquid\_prominentGlass

設置prominentGlass液態玻璃類型,並做相關配置

示例:

let button: UIButton = A.ui.button
button.liguid_prominentGlass(title: "test")

設置prominentGlass液態玻璃類型,並通過字典做相關配置

let config: [LiquidGlassConfig : Any] = [
   .title : "test"
]
let button: UIButton = A.ui.button
button.liquid_prominentGlass(config)

liquid\_prominentClearGlass

設置prominentClearGlass液態玻璃類型,並做相關配置

示例:

let button: UIButton = A.ui.button
button.liguid_prominentClearGlass(title: "test")

設置prominentClearGlass液態玻璃類型,並通過字典做相關配置

let config: [LiquidGlassConfig : Any] = [
   .title : "test"
]
let button: UIButton = A.ui.button
button.liquid_prominentClearGlass(config)

核心功能

框架提供:

  1. MVVM設計模式
  2. 開發方法
  3. 數據綁定
  4. 處理UI的新方法
  5. 深色模式切換
  6. 格式轉換
  7. 依賴注入
  8. 自動管理
  9. 工具

    1. 通知
    2. userDefaults
    3. 內購
    4. 日曆/提醒
    5. 位置
    6. 日誌
    7. Timer
    8. 格式化屬性

MVVM設計模式

框架提供AViewAViewControllerAViewModel,開發中,需基於此三個基類開始開發。

AView

主要功能包括:

  1. 鍵盤管理
  2. 分層管理
  3. 事件管理
  4. Delegate管理
  5. 通知管理
  6. 數據綁定管理
  7. 日誌管理
  8. 熱更新管理

示例代碼:

import Aquarius


class TestView: AView {

}

AViewController

主要功能包括:

  1. 埋點
  2. 導航條管理
  3. 分層管理
  4. 主題管理
  5. 日誌管理
  6. 熱更新管理

示例代碼:

import Aquarius


class TestViewController: AViewController {

}

AViewModel

主要功能包括:

  1. 分層管理
  2. Delegate管理
  3. 通知管理
  4. 數據綁定管理
  5. 日誌管理
  6. 熱更新管理

示例代碼:

import Aquarius


class TestVM: AViewModel {

}

框架提供了代碼的低侵入性,可以在老的工程中引入Aquarius。引入後,新開發的功能繼承AViewAViewControllerAViewModel,老功能不受影響。

開發方法

洋葱開發法是作者為開發方法起的名字,方法主要將開發工作進行細分。

設計了多個方法,開發時只需要覆蓋這些方法體,它們會自動執行。

AViewController

初始化中執行的方法包括:

  1. a\_Preview:開始前執行
  2. a\_Begin:開始執行時調用
  3. a\_Navigation:定製化導航條
  4. a\_Delegate:設置delegate
  5. updateThemeStyle:深色模式切換時調用
  6. a\_Notification:設置通知
  7. a\_Bind:設置數據綁定
  8. a\_Observe:設置Observe
  9. a\_Event:設置事件

viewDidLoad方法中執行的方法主要包括:

  1. a\_UI:設置UI組件
  2. a\_UIConfig:設置UI組件參數
  3. a\_Layout:設置UI組件的佈局
  4. a\_Other:設置其它內容
  5. a\_End:代碼末尾執行
  6. a\_Test:測試的代碼函數,此函數值在debug模式下執行,發佈後不執行

deinit方法中執行的方法包括:

  1. a\_Clear:銷燬時執行

AView

初始化中執行的方法包括:

  1. a\_Preview:開始前執行
  2. a\_Begin:開始執行時調用
  3. a\_UI:設置UI組件
  4. a\_UIConfig:設置UI組件參數
  5. a\_Layout:設置UI組件的佈局
  6. a\_Notification:設置通知
  7. a\_Delegate:設置delegate
  8. updateThemeStyle:深色模式切換時調用
  9. a\_Bind:設置數據綁定
  10. a\_Event:設置事件
  11. a\_Other:設置其它內容
  12. a\_End:代碼末尾執行
  13. a\_Test:測試的代碼函數,此函數值在debug模式下執行,發佈後不執行

deinit方法中執行的方法包括:

  1. a\_Clear:銷燬時執行

AViewModel

初始化中執行的方法包括:

  1. a\_Preview:開始前執行
  2. a\_Begin:開始執行時調用
  3. a\_Notification:設置通知
  4. a\_Delegate:設置delegate
  5. a\_Observe:設置Observe
  6. a\_Other:設置其它內容
  7. a\_End:代碼末尾執行
  8. a\_Test:測試的代碼函數,此函數值在debug模式下執行,發佈後不執行

deinit方法中執行的方法包括:

  1. a\_Clear:銷燬時執行

ATableViewCell

初始化中執行的方法包括:

  1. a\_Preview:開始前執行
  2. a\_Begin:開始執行時調用
  3. a\_UI:設置UI組件
  4. a\_UIConfig:設置UI組件參數
  5. a\_Layout:設置UI組件的佈局
  6. updateThemeStyle:深色模式切換時調用
  7. a\_Notification:設置通知
  8. a\_Delegate:設置delegate
  9. a\_Observe:設置Observe
  10. a\_Bind:設置數據綁定
  11. a\_Event:設置事件
  12. a\_Other:設置其它內容
  13. a\_End:代碼末尾執行
  14. configWithCell(cellData: Any):cell接收數據時調用

deinit方法中執行的方法包括:

  1. a\_Clear:銷燬時執行

數據綁定

框架中AViewAViewModel,提供了數據綁定功能,幫助實現完全解耦的數據更新。

數據綁定主要提供如下方法:

bindableFrom(_ dict: Dictionary<String, String>)
bindablesFrom(_ o: Array<Dictionary<String, String>>)
bindableTo(_ dict: Dictionary<String, String>)
bindablesTo(_ o: Array<Dictionary<String, String>>)

方法需要聯動使用。

bindableFrom、bindablesFrom,負責更新數據。

bindableTobindalbesTo,負責接收更新數據。

TestView

示例代碼:

import UIKit
import Foundation

import Aquarius

class TestView: AView {
    private let testButton: UIButton = A.ui.button

    @objc dynamic
    private var testString: String = ""

    override func a_UI() {
        super.a_UI()

        addSubviews(views: [
            testButton
        ])
    }

    override func a_UIConfig() {
        super.a_UIConfig()

        testButton.prototypeDesign(.hollow)
        testButton.setTitle("測試數據綁定", for: .normal)
    }

    override func a_Layout() {
        super.a_Layout()

        testButton.size(sizes: [100, 150])
        testButton.point(points: [200, 400])
    }

    override func a_Bind() {
        super.a_Bind()

        bindableFrom([
            "bindKey" : #keyPath(testString)
        ])
    }

    override func a_Event() {
        super.a_Event()

        testButton.addTouchUpInsideBlock { [weak self] result in
            self?.testString = String.random(length: 16)
        }
    }
}

TestVM

示例代碼:

import Foundation

import Aquarius

class TestVM: AViewModel {
    @objc dynamic
    private var updateBindString: String = "" {
        willSet {
            A.log.info(newValue)
        }
    }

    override func a_Bind() {
        super.a_Bind()

        bindableTo([
            "bindKey" : #keyPath(updateBindString)
        ])
    }
}

處理UI的新方法

框架提供了一系列創建及處理UI組件的方法。方便開發者提高處理UI的效率。

快速初始化UI控件

A.ui.view//=UIView(frame: .zero)
A.ui.imageView//=UIImageView(frame: .zero)
A.ui.button//=UIButton(frame: .zero)
A.ui.label//=UILabel(frame: .zero)
A.ui.collectionView//=UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
A.ui.collectionViewCell//=UICollectionViewCell(frame: .zero)
A.ui.datePicker//=UIDatePicker(frame: .zero)
A.ui.navigationController//=UINavigationController()
A.ui.navigationItem//=UINavigationItem()
A.ui.pickerView//=UIPickerView(frame: .zero)
A.ui.scrollView//=UIScrollView(frame: .zero)
A.ui._switch//=UISwitch(frame: .zero)
A.ui.tabBarController//=UITabBarController()
A.ui.tabBarItem//=UITabBarItem()
A.ui.tableView//=UITableView(frame: .zero)
A.ui.tableViewCell//=UITableViewCell(frame: .zero)
A.ui.textField//=UITextField(frame: .zero)
A.ui.viewController//=UIViewController()
A.ui.searchBar//=UISearchBar(frame: .zero)
A.ui.textView//=UITextView(frame: .zero)
A.ui.refreshControl//=UIRefreshControl()
A.ui.activityIndicatorView//=UIActivityIndicatorView()
A.ui.webView//=WKWebView()
A.ui.progressView//=UIProgressView()
A.ui.alert//=UIAlertController(title: "", message: "", preferredStyle: .alert)
A.ui.mapView//=MKMapView()

屬性主要用於在UIView中快速的初始化UI控件。

示例代碼:

import UIKit
import Foundation

import Aquarius

class TestView: AView {
    private let testButton: UIButton = A.ui.button
    private let testLabel: UILabel = A.ui.label
    private let testTableView: UITableView = A.ui.tableView
    ...
}

UI佈局

基礎佈局

UI控件提供如下基礎佈局屬性和方法:

//獲取UI控件頂端y值
func y() -> CGFloat
func top() -> CGFloat
//獲取UI控件底端y值
func bottom() -> CGFloat
//獲取UI控件左側x值
func x() -> CGFloat
func left() -> CGFloat
//獲取UI控件右側y值
func right() -> CGFloat
//獲取UI控件寬度
func width() -> CGFloat
//獲取UI控件高度
func height() -> CGFloat
//獲取UI控件的size
func size() -> CGSize
//獲取UI控件的frame
func frame() -> CGRect
//獲取UI控件中間點x座標
func centerX() -> CGFloat
//獲取UI控件中間點y座標
func centerY() -> CGFloat
//獲取屏幕的Size
func screenSize() -> CGSize
//獲取屏幕的寬度
func screenWidth() -> CGFloat
//獲取屏幕的高度
func screenHeight() -> CGFloat
//獲取屏幕(去掉狀態欄)的高度
func screenHeightNoStatus() -> CGFloat
//獲取屏幕(去掉導航條)的高度
func screenHeightNoNavigation() -> CGFloat
//獲取屏幕(去掉狀態欄和導航條)的高度
func screenHeightNoStatusNoNavigation() -> CGFloat
//獲取屏幕(去掉底部安全區域)的高度
func screenHeightNoSafeAreaFooter() -> CGFloat
//獲取屏幕(去掉底部tabBar)的高度
func screenHeightNoTabBar() -> CGFloat
//獲取屏幕(去掉底部安全區域和tabBar)的高度
func screenHeightNoStatusNoSafeAreaFooter() -> CGFloat
//獲取屏幕(去掉狀態欄和tabBar)的高度
func screenHeightNoStatusNoTabBar() -> CGFloat
//獲取屏幕(去掉狀態欄、底部安全區域和tabBar)的高度
func screenHeightNoStatusNoSafeAreaFooterNoTabBar() -> CGFloat
//獲取屏幕(去掉導航條和底部安全區域)的高度
func screenHeightNoNavigationNoSafeAreaFooter() -> CGFloat
//獲取屏幕(去掉導航條和tabBar)的高度
func screenHeightNoNavigationNoTabBar() -> CGFloat
//獲取屏幕(去掉導航條、底部安全區域和tabBar)的高度
func screenHeightNoNavigationNoSafeAreaFooterNoTabBar() -> CGFloat
//獲取屏幕(去掉狀態欄、導航條和底部安全區域)的高度
func screenHeightNoStatusNoNavigationNoSafeAreaFooter() -> CGFloat
//獲取屏幕(去掉狀態欄、導航條和tabBar)的高度
func screenHeightNoStatusNoNavigationNoTabBar() -> CGFloat
//獲取屏幕(去掉狀態欄、導航條、底部安全區域和tabBar)的高度
func screenHeightNoStatusNoNavigationNoSafeAreaFooterNoTabBar() -> CGFloat
//獲取頂部安全區域高度
func safeAreaHeaderHeight() -> CGFloat
//獲取底部安全區域高度
func safeAreaFooterHeight() -> CGFloat
//獲取狀態欄高度
func statusBarHeight() -> CGFloat
//獲取導航條高度
func navigationBarHeight() -> CGFloat
//獲取tabBar高度
func tabBarHeight() -> CGFloat

UI控件設置佈局

UI控件提供如下設置佈局的方法:

//設置UI控件的y位置或頂部位置(支持動畫)
func y(y: CGFloat, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
func top(top: CGFloat, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//設置UI控件的底部位置(支持動畫)
func bottom(bottom: CGFloat, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//設置UI控件的x位置或左側位置(支持動畫)
func x(x: CGFloat, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
func left(left: CGFloat, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//設置UI控件的右側位置(支持動畫)
func right(right: CGFloat, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//設置UI控件的寬度(支持動畫)
func width(width: CGFloat, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//設置UI控件的高度(支持動畫)
func height(height: CGFloat, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//設置UI控件的size(設置寬和高)(支持動畫)
func size(width: CGFloat, height: CGFloat, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//設置UI控件的size(數組形式設置,0為寬度,1為高度)(支持動畫)
func size(sizes: Array<CGFloat>, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//設置UI控件的size(直接設置size)(支持動畫)
func size(size: CGSize, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//設置UI控件的size(寬和高相同)(支持動畫)
func size(widthHeight: CGFloat, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//設置UI控件的frame (支持動畫)
func frame(frame: CGRect, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//設置UI控件的frame(數組形式設置,0為x,1為y,2為width,3為height) (支持動畫)
func frame(frames: Array<CGFloat>, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//設置UI控件的frame(x和y相同,width和height相同時) (支持動畫)
func frame(xy: CGFloat, widthHeight: CGFloat, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//設置UI控件的frame (支持動畫)
func frame(x: CGFloat, y: CGFloat, w: CGFloat, h: CGFloat, animate: Bool = false, duration: TimeInterval = UIView.a_duration)

控件間佈局方法

UI控件提供如下控件間佈局的方法:

//UI控件頂部在view的底部,offset為間距(支持動畫)
func alignTop(view: UIView, offset: CGFloat = 0, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//UI控件底部在view的頂部,offset為間距(支持動畫)
func alignBottom(view: UIView, offset: CGFloat = 0, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//UI控件左側在view的右側,offset為間距(支持動畫)
func alignLeft(view: UIView, offset: CGFloat = 0, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//UI控件右側在view的左側,offset為間距(支持動畫)
func alignRight(view: UIView, offset: CGFloat = 0, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//UI控件頂部等於target頂部,offset為間距(支持動畫)
func equalTop(target: UIView, offset: CGFloat = 0, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//UI控件底部等於target底部,offset為間距(支持動畫)
func equalBottom(target: UIView, offset: CGFloat = 0, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//UI控件左側等於target左側,offset為間距(支持動畫)
func equalLeft(target: UIView, offset: CGFloat = 0, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//UI控件右側等於target右側,offset為間距(支持動畫)
func equalRight(target: UIView, offset: CGFloat = 0, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//UI控件size等於target的size(支持動畫)
func equalSize(target: UIView, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//UI控件point等於target的point(支持動畫)
func equalPoint(target: UIView, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//UI控件寬度等於target的寬度(支持動畫)
func equalWidth(target: UIView, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//UI控件高度等於target的高度(支持動畫)
func equalHeight(target: UIView, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//UI控件rect等於target的rect(支持動畫)
func equalRect(target: UIView, animate: Bool = false, duration: TimeInterval = UIView.a_duration)
//UI控件左側位置為0
func equalZeroLeft()
//UI控件頂部位置為0
func equalZeroTop()
//UI控件左側和頂部均為0
func equalZeroTopAndLeft()
//UI控件size等於屏幕的size
func equalScreenSize()
//UI控件寬度等於屏幕寬度(offset為內間距)
func equalScreenWidth(_ offset: CGFloat=0.0)
//UI控件高度等於屏幕高度(offset為內間距)
func equalScreenHeight(_ offset: CGFloat=0.0)

批量佈局

當兩個控件間有多個屬性相同,可以採用批量佈局的方法

示例代碼:

private let testLabel: UILabel = A.ui.lable
private let testButton: UIButton = A.ui.button

override func a_Layout() {
    super.a_layout()

    testLabel.size(widthHeight: 100.0)
    testLabel.top(top: 50.0)
    testLabel.left(left: 100.0)
    testLabel.target(testButton)
    testLabel.a_equals([
        .width,
        .height,
        .top,
        .left
    ])
    ...
}

支持批量設置的屬性包括:

widthheightlefttoprightbottompointsizerectbackgroundColorisHiddenalpha

layer相關屬性的快速設置

func layerCornerRadius(_ cornerRadius: CGFloat)
func layerCornerCurve(_ cornerCurve: CALayerCornerCurve)
func layerMasksToBounds(_ masksToBounds: Bool=true)
func layerBorderWidth(_ borderWidth: CGFloat)
func layerBorderColor(_ borderColor: UIColor)

背景顏色的快速設置

func clearBackgroundColor()
func whiteBackgroundColor()
func blackBackgroundColor()
func darkGrayBackgroundColor()
func lightGrayBackgroundColor()
func grayBackgroundColor()
func redBackgroundColor()
func greenBackgroundColor()
func blueBackgroundColor()
func cyanBackgroundColor()
func yellowBackgroundColor()
func magentaBackgroundColor()
func orangeBackgroundColor()
func purpleBackgroundColor()
func brownBackgroundColor()
//設置隨機背景色
func testBackgroundColor()

批量設置UI控件

當多個UI控件具有相同的屬性,可以將多個UI控件放入一個數組中,並直接處理數組。

示例代碼:

override func a_UIConfig() {
    super.a_UIConfig()

    let uiArray: [UIView] = [testButton, testLabel]
    uiArray.layerCornerRadius(8.0)
    uiArray.backgroundColor(0xFFFFFF.toColor)
    ...
}

支持批量設置的方法參見:Array++

UI控件的添加和刪除

框架支持單獨添加UI控件和批量添加UI控件。在實際開發中,建議使用批量添加UI控件的方法。

示例代碼:

private let testLabel: UILabel = A.ui.lable
private let testButton: UIButton = A.ui.button

override func a_UI() {
    super.a_UI()

    addSubViews(views:[
        testLabel,
        testButton
    ])
}

UITableViewCell也支持單獨添加UI控件和批量添加UI控件。在實際開發中,建議使用批量添加UI控件的方法。

示例代碼:

private let testLabel: UILabel = A.ui.lable
private let testButton: UIButton = A.ui.button

override func a_UI() {
    super.a_UI()

    addSubviewInContentView(views:[
        testLabel,
        testButton
    ])
}

導航條的相關設置

繼承於AViewControllerUIViewController可以快速的設置導航條

框架提供的方法包括:

public var navigation_Title: String
public var navigation_TitleView: UIView?
public var navigation_LeftBarButton: UIButton?
public var navigation_LeftBarButtonText: String?
public var navigation_LeftBarButtonImage: UIImage?
public var navigation_LeftBarButtonTintColor: UIColor?
public var navigation_LeftBarButtonAction: Selector?
public func navigation_LeftBarButtonSelector(executeBlock: (() -> Void)?)
public var navigation_RightBarButton: UIButton?
public var navigation_RightBarButtonText: String?
public var navigation_RightBarButtonImage: UIImage?
public var navigation_RightBarButtonTintColor: UIColor?
public var navigation_RightBarButtonAction: Selector?
public func navigation_RigthBarButtonSelector(executeBlock: (() -> Void)?)

深色模式切換

框架提供了支持模式切換的功能。開發過程中,建議使用主題文件的形式。

實現模式切換的步驟如下:

  1. 製作主題類
  2. 重寫updateThemeStyle方法

製作主題類

主題類需繼承DesignColorProtocol協議。

DesignColorProtocol協議提供了標準的顏色定義。詳細請查看DesignColorProtocol中的定義。

示例代碼:

import UIKit
import Foundation

import Aquarius

class ColorDesign: DesignColorProtocol {
    var textPrimaryColor: UIColor {
        get {
            AThemeStyle.getThemeColor([
                //普通模式顏色
                .Light : 0xF2F2F2.toColor,
                //深色模式顏色
                .Dark : 0x151F2E.toColor
            ])
        }
    }

    var primaryColor: UIColor {
        get {
            AThemeStyle.getThemeColor([
                .Light : 0xF2F2F2.toColor,
                .Dark : 0x151F2E.toColor
            ])
        }
    }

    public static let shared = ColorDesign()
}

updateThemeStyle方法

定義主題類後,AViewControllerAView提供了updateThemeStyle方法。

再此方法中更新主題。

示例代碼:

import UIKit
import Foundation

import Aquarius

class MainView: AView {
    public let testLabel: UILabel = A.ui.label
    public let testButton: UIButton = A.ui.button

    override func a_UI() {
        super.a_UI()

        addSubviews(views:[
            testLabel,
            testButton
        ])
    }

    override func updateThemeStyle() {
        super.updateThemeStyle()

        testLabel.textColor = ColorDesign.shared.textPrimaryColor
        testButton.backgroundColor = ColorDesign.shared.primaryColor
    }
}

示例中,當系統由普通模式轉換為深色模式,或者由深色模式轉換為普通模式時,繼承AView或者AViewController的類將自動執行updateThemeStyle方法。

方法體將重新設置testLabeltextColortestButtonbackgroundColor屬性。

textPrimaryColorprimaryColor將會根據主題類中的設置,自動判斷是普通模式還是深色模式,並返回對應的顏色值。

getThemeColor方法

不使用主題類的情況下,可以直接通過getThemeColor方法設置顏色

static func getThemeColor(_ themeColorDict: [AThemeStyleDarkModeType : UIColor]) -> UIColor

示例代碼:

import UIKit
import Foundation

import Aquarius

class MainView: AView {
    public let testLabel: UILabel = A.ui.label
    public let testButton: UIButton = A.ui.button

    override func a_UI() {
        super.a_UI()

        addSubviews(views:[
            testLabel,
            testButton
        ])
    }

    override func updateThemeStyle() {
        super.updateThemeStyle()

        testLabel.textColor = AThemeStyle.getThemeColor([
            .Light : 0xF2F2F2.toColor,
            .Dark : 0x151F2E.toColor
        ])
        testButton.backgroundColor = ColorDesign.shared.primaryColor
    }
}

格式轉換

框架提供大部分的格式相互轉換的簡寫方法。

示例代碼:

//顏色轉換
let color: UIColor = 0xFFFFFF.toColor
//Int字號轉換
let font1: UIFont = 18.toFont
let font2: UIFont = 18.toBoldFont
//Int轉CGFloat
let f: CGFloat = 18.toCGFloat
//Int轉NSNumber
let n: NSNumber = 18.toNumber
//Int轉Double
let double: Double = 18.toDouble
//字符串轉日期(默認為完整日期,包括日期+時間)
let date1: Date = "2025-05-10 18:00:00".toDate()
//字符串轉日期
let date2: Date = "2025-05-10".toShortDate()
//字符串轉日期(包括日期+時間)
let date3: Date = "2025-05-10".toLongDate()
//字符串轉圖片
let image1: UIImage = "name.png".toContentsOfFileImage()
let image2: UIImage = "name.png".toNamedImage()
let image3: UIImage = "setting.png".toSystemNameImage()
//字符串轉Int
let data: Int? = "1".toInt()
//字符串轉Bool
let flag: Bool = "1".toBool()
//字符串轉CGFloat
let f: CGFloat = "1".toCGFloat()
//字符串轉Double
let double: Double = "18.85".toDouble()
//CGFloat轉Font
let font1: UIFont = 18.0.toFont
let font2: UIFont = 18.0.toBoldFont
//CGFloat轉字符串
let string: String = 18.0.toString()
//日期轉String
let string1: String = Date().toString()
let string2: String = Date().toShortEnglishString()
let string3: String = Date().toShortChineseString()
let string4: String = Date().toLongEnglishString()
let string5: String = Date().toLongChineseString()
let yearString: String = Date().toYearString()
let year: Int? = Date().toYear()
let monthString: String = Date().toMonthString()
let month: Int? = Date().toMonth()
let dayString: String = Date().toDayString()
let day: Int? = Date().toDay()
let time: String = Date().toTimeString()
let hourString: String = Date().toHourString()
let hour: Int? = Date().toHour()
let minuteString: String = Date().toMinuteString()
let minute: Int? = Date().toMinute()
let secondString: String = Date().toSecondString()
let second: Int? = Date().toSecond()
//Bool轉Int
let flag: Int = false.toInt()
//Bool轉String
let flagString: String = false.toString()
//UIColor轉String
let colorString: String = 0xFFFFFF.toHexString()
//UIImage轉Data
let data1: Data? = image.toJPEGData()
let data2: Data? = image.toPNGData()
//Data轉UIImage
let image: UIImage? = data.toImage()

依賴注入

框架基於KVO提供依賴注入功能。

依賴注入主要解決MVVM設計模式中ControllerviewModel之間的解耦問題

建議此類功能代碼放到a\_Observe

TestVM

示例代碼:

import Aquarius

class TestVM: AViewModel {
    //依賴注入的變量建議以kObserveTag開頭
    @objc dynamic
    public var kObserveTag_RefreshTableView: Bool = false
    ...
}

TestVC

示例代碼:

import Aquarius

class TestVC: AViewController {
    private let viewModel: TestVM = TestVM()

    override func a_Observe() {
        super.a_Observe()

        self.viewModel.kvo = self.viewModel
            .observe(.kObserveTag_RefreshTableView, options: .new, changeHandler: { [weak self] (object, change) in
                if change.newValue! as Bool {
                    ...
                }
        })
    }
}

注意:建議將observe創建的實例保存到viewModel.kvo中,框架未來將提供自動管理oberve的能力

自動管理

當前,框架針對DelegateNotification提供自動管理功能。

基於自動管理模塊使用DelegateNotification只需關心創建即可,框架將在頁面銷燬時,自動刪除創建的DelegateNotification

Delegate

建議此類功能代碼放到a\_Delegate

AViewModel提供如下方法:

func Manage_SetDelegate(targetObject: AnyObject, delegateName: String, object: AnyObject)
func Manage_SetDelegate(targetObject: AnyObject, delegateNames: Array<String>, object: AnyObject)
func Manage_DeleteDelegate(object: AnyObject, delegateName: String)
func Manage_DeleteDelegate(object: AnyObject, delegateNames: Array<String>)

AProtocol提供如下方法:

public static let delegate: String
public static let emptyDelegate: String
public static let dataSource: String
public static let delegateAndDataSource: [String]

建議在Controller中使用。

TestView

示例代碼:

class TestView: AView {
    public let testTableView: UITableView = A.ui.tableView
    ...
}

TestVC

示例代碼:

class TestVC: AViewController {
    private let viewModel: TestVM = TestVM()
    private let a_view: TestView = TestView()

    override func a_Delegate() {
        super.a_Delegate()

        viewModel.Manage_SetDelegate(
            targetObject: a_view,
            delegateNames: AProtocol.delegateAndDataSource,
            object: self
        )
    }

    /*
     //另外兩種寫法
    override func a_Delegate() {
        super.a_Delegate()

        viewModel.Manage_SetDelegate(
            targetObject: a_view,
            delegateName: AProtocol.delegate,
            object: self
        )

        viewModel.Manage_SetDelegate(
            targetObject: a_view,
            delegateName: AProtocol.dataSource,
            object: self
        )
    }

    override func a_Delegate() {
        super.a_Delegate()

        viewModel.Manage_SetDelegate(
            targetObject: a_view,
            delegateName: "delegate",
            object: self
        )

        viewModel.Manage_SetDelegate(
            targetObject: a_view,
            delegateName: "dataSource",
            object: self
        )
    }
     */
    ...
}

Notification

建議此類功能代碼放到a\_Notification

AViewModelAView提供如下方法:

func Manage_SetNotification(_ notificationName: String)
func Manage_SetNotifications(_ notificationNames: Array<String>)
func Manage_DeleteNotification(_ notificationName: String)
func Manage_DeleteNotifications(_ notificationNames: Array<String>)
func Manage_PostNotification(_ notificationName: String, object:[String : Any]?=nil)
func Manage_PostNotifications(_ notificationNames: [String], objects: [[String : Any]?]?=nil)
func ANotificationReceive(notification: Notification)

TestView

示例代碼:

class TestView: AView {
    private let testButton: UIButton = A.ui.button

    override func a_Event() {
        super.a_Event()

        testButton.addTouchUpInsideBlock { [weak self] result in
            self?.Manage_PostNotification(
                "notificationID",
                object: ANotification.packageCoreNotificationDataValue(value: "123")
            )
        }
    }
    ...
}

TestVM

示例代碼:

class TestVM: AViewModel {
    override func a_Notification() {
        Manage_SetNotification("notificationID")
    }

    override func ANotificationReceive(notification: Notification) {
        super.ANotificationReceive(notification: notification)

        if notification.isNotificationName("notificationID") {
            let paramString: String = notification.objectValue(ANotification.kANotificationData) as! String
        }
    }
    ...
}

立即體驗Aquarius:

  • ⭐ Star & Fork 框架源碼: GitHub - JZXStudio/Aquarius
  • 📱 下載示例APP: 悦記 | 愛尋車
  • 💌 聯繫與反饋: studio_jzx@163.com
user avatar zouzaidadaomanshihuaxiang 頭像 zhoumo_62382eba4b454 頭像 openbayescom 頭像 alixitongruanjianjishu 頭像 swiftcommunity 頭像 slnongchang 頭像
點贊 6 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.