基於MVVM構建聊天App (二)登陸UI的實現

一、一個完整的開發流程

通常的,一個正常的流程包括:git

  • 產品定需求,給出原型圖
  • 團隊確認需求
  • 由設計師開始設計圖,同步開發作開發前的準備工做,如技術調查,先後端如何配合等
  • 設計師完成設計後,團隊對比設計圖和原型圖再次確認需求
  • 開發團隊開始開發工做
  • 開發完成後由開發者自測 通常咱們在開發中編寫的單元測試代碼也屬於自測
  • 開發者自測後由產品測試,事實上在開發過程當中,產品也應該實時的關注開發
  • 交由專業測試人員作測試
  • 發佈內測版本,作大規模測試
  • 提交App Store審覈

二、storyboard啓動流程

通常的若是新建了一個Objective-C工程,默認先調用main函數,main函數內部會調用UIApplicationMain函數。github

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}
複製代碼

但在Swift項目中,並無main.m文件也沒有main函數。Swift工程是在AppDelegate中用一個@UIApplicationMain標籤。那麼UIApplicationMain作了哪些操做呢:windows

  • 建立UIApplication單例對象
  • 建立UIApplication的委託對象,即AppDelegate
  • 開啓事件循環監聽系統事件,當堅挺到對應的系統事件時會通知AppDelegate
  • 建立最底層的UIWindows對象,
  • 讀取Info.plist中設置的默認啓動storyboard文件名稱
  • 加載設置的is Initial View Controllerstoryboard文件,同時建立對應的View Controller對象
  • 設置建立的View ControllerUIWindows的根視圖rootViewController
  • 顯示Windows上的試圖

運行工程能夠看到以下圖: 最底層是一個UIWindwos後端

windows

三、沒有storyboard啓動App

通常的一個工程,默認從main.storyboard中的設置的Initial view controller啓動的,那麼咱們該如何設置本身的初始啓動View Controller呢?bash

在前面咱們工程的結構:RPChat_iOS是UI的顯示以及交互相關的代碼,因此在RPChat_iOS新建文件夾SignInapp

SignIn

新建登錄界面Controller命名爲SignInViewControlleride

AppDelegatedidFinishLaunchingWithOptions launchOptions回調方法中添加代碼,設置SignInViewController爲默認啓動控制器:函數

if #available(iOS 13, *) {
    
} else {
     window = UIWindow.init()
     window?.frame = UIScreen.main.bounds
     window?.makeKeyAndVisible()
     let signInVC = SignInViewController()
     window?.rootViewController = signInVC
}
複製代碼

SceneDelegateoptions connectionOptions方法中添加代碼:單元測試

guard let windowScene = (scene as? UIWindowScene) else { return }

window = UIWindow(frame: windowScene.coordinateSpace.bounds)
window?.windowScene = windowScene
window?.backgroundColor = .white
let tabBar = SignInViewController()
window?.rootViewController = tabBar
window?.makeKeyAndVisible()
複製代碼

四、登陸UI的實現

先看一下這是最終效果圖:測試

light Mode

  • 一、Auto Layout

至於UI,考慮到版本兼容和後期維護我採用了系統NSLayoutAnchor適配,

NSLayoutAnchor經常使用屬性

  • leadingAnchor
  • trailingAnchor
  • leftAnchor
  • rightAnchor
  • topAnchor
  • bottomAnchor
  • widthAnchor
  • heightAnchor
  • centerXAnchor
  • centerYAnchor
  • firstBaselineAnchor
  • lastBaselineAnchor

關於Auto Layout其餘更多使用細節請參考官方文檔:

High Performance Auto Layout

Apple Develope NSLayoutConstraint

Apple Develope NSLayoutAnchor

WWDC 2018 What's New in Cocoa Touch

  • 二、UI實現

新建一個View命名SignInRootView做爲登陸界面的主View,採用懶加載的方式初始化視圖

最頂部的Logo圖片實現代碼:

lazy var logoImg: UIImageView = {
        self.addSubview($0)
        $0.translatesAutoresizingMaskIntoConstraints = false
        let top = $0.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor, constant: 44)
        let centerX = $0.centerXAnchor.constraint(equalTo: self.centerXAnchor, constant: 0)
        let width = $0.widthAnchor.constraint(equalToConstant: 120)
        let height = $0.heightAnchor.constraint(equalToConstant: 120)
        NSLayoutConstraint.activate([top, centerX, width, height])
        return $0
    }(UIImageView())
複製代碼

用戶名輸入框實現代碼:

lazy var accountNumberView: UIView = {
        self.addSubview($0)
        $0.translatesAutoresizingMaskIntoConstraints = false
        let top = $0.topAnchor.constraint(equalTo: logoImg.bottomAnchor, constant: 20)
        let left = $0.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 40)
        let right = $0.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -40)
        let height = $0.heightAnchor.constraint(equalToConstant: 50)
        NSLayoutConstraint.activate([top, left, right, height])
        $0.layer.cornerRadius = 25
        return $0
    }(UIView())
 
    
    lazy var accountNumberLab: UITextField = {
        accountNumberView.addSubview($0)
        $0.translatesAutoresizingMaskIntoConstraints = false
        $0.topAnchor.constraint(equalTo: accountNumberView.topAnchor, constant: 0).isActive = true
        $0.leftAnchor.constraint(equalTo: accountNumberView.leftAnchor, constant: 16).isActive = true
        $0.rightAnchor.constraint(equalTo: accountNumberView.rightAnchor, constant: -16).isActive = true
        $0.bottomAnchor.constraint(equalTo: accountNumberView.bottomAnchor, constant: 0).isActive = true
        $0.font = UIFont.init(name: "PingFangTC-Semibold", size: 19)
        return $0
    }(UITextField())
複製代碼

密碼輸入框實現代碼:

lazy var inputPasswordView: UIView = {
           self.addSubview($0)
           $0.translatesAutoresizingMaskIntoConstraints = false
           let top = $0.topAnchor.constraint(equalTo: accountNumberView.bottomAnchor, constant: 20)
           let left = $0.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 40)
           let right = $0.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -40)
           let height = $0.heightAnchor.constraint(equalToConstant: 50)
           NSLayoutConstraint.activate([top, left, right, height])
           $0.layer.cornerRadius = 25
           return $0
       }(UIView())
    
       
    lazy var inputPasswordTxt: UITextField = {
           inputPasswordView.addSubview($0)
           $0.translatesAutoresizingMaskIntoConstraints = false
           $0.topAnchor.constraint(equalTo: inputPasswordView.topAnchor, constant: 0).isActive = true
           $0.leftAnchor.constraint(equalTo: inputPasswordView.leftAnchor, constant: 16).isActive = true
           $0.rightAnchor.constraint(equalTo: inputPasswordView.rightAnchor, constant: -16).isActive = true
           $0.bottomAnchor.constraint(equalTo: inputPasswordView.bottomAnchor, constant: 0).isActive = true
           $0.font = UIFont.init(name: "PingFangTC-Semibold", size: 19)
           return $0
       }(UITextField())
複製代碼

登陸按鈕實現代碼:

lazy var signInBtn: UIButton = {
        self.addSubview($0)
        $0.translatesAutoresizingMaskIntoConstraints = false
        let top = $0.topAnchor.constraint(equalTo: inputPasswordView.bottomAnchor, constant: 20)
        let left = $0.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 40)
        let right = $0.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -40)
        let height = $0.heightAnchor.constraint(equalToConstant: 50)
        NSLayoutConstraint.activate([top, left, right, height])
        $0.layer.cornerRadius = 25
        $0.titleLabel?.font = UIFont.init(name: "PingFangTC-Semibold", size: 20)
        $0.setTitle(NSLocalizedString("Sign In", comment: ""), for: .normal)
        return $0
   }(UIButton())
複製代碼

此處代碼較多,具體實現請看代碼: gitub RPChat

  • 三、設置背景顏色

因爲設計師給出的顏色通常爲16進制,此處須要作一個轉碼處理:

open class func hexStringToColor(hexadecimal: String) -> UIColor {
        var cstr = hexadecimal.trimmingCharacters(in:  CharacterSet.whitespacesAndNewlines).uppercased() as NSString;
        if(cstr.length < 6){
            return UIColor.clear;
        }
        if(cstr.hasPrefix("0X")){
            cstr = cstr.substring(from: 2) as NSString
        }
        if(cstr.hasPrefix("#")){
            cstr = cstr.substring(from: 1) as NSString
        }
        if(cstr.length != 6){
            return UIColor.clear;
        }
        var range = NSRange.init()
        range.location = 0
        range.length = 2
        let rStr = cstr.substring(with: range);
        range.location = 2;
        let gStr = cstr.substring(with: range)
        range.location = 4;
        let bStr = cstr.substring(with: range)
        var r :UInt32 = 0x0;
        var g :UInt32 = 0x0;
        var b :UInt32 = 0x0;
        Scanner.init(string: rStr).scanHexInt32(&r);
        Scanner.init(string: gStr).scanHexInt32(&g);
        Scanner.init(string: bStr).scanHexInt32(&b);
        return UIColor.init(red: CGFloat(r)/255.0, green: CGFloat(g)/255.0, blue: CGFloat(b)/255.0, alpha: 1)
    }
複製代碼

而後就能夠用設計師給的16進制設置背景顏色:

signInBtn.backgroundColor = UIColor.hexStringToColor(hexadecimal: "0xF5BE62")
複製代碼
  • 四、Drak Mode適配

因爲iOS 13以後蘋果處理Drak Mode,做爲開發者也應該作相應的兼容處理。如今我在代碼中並無此時調整模擬器爲暗模式,運行工程能夠看到在暗模式下,用戶名和密碼輸入框背景色不見了。此時就應該作暗模式的兼容處理。

drak mode

此處個人作法也很簡單,對UIColorextension處理,而後再擴展方法中分別對Drak ModeLight Mode兩種模式作對應的處理,代碼以下:

open class func configDarkModeViewColor() -> UIColor {
        let retColor: UIColor!
        if #available(iOS 13.0, *) {
            retColor = UIColor { (collection) -> UIColor in
                if (collection.userInterfaceStyle == .dark) {
                    return UIColor.init(red: 100/255, green: 100/255, blue: 100/255, alpha: 1)
                }
                return UIColor.white
            }
        } else {
            return UIColor.white
        }
        return retColor
    }
    
  open class func configDarkModeViewColorWithdDfaultColor(dfaultColor: UIColor) -> UIColor {
        let retColor: UIColor!
        if #available(iOS 13.0, *) {
            retColor = UIColor { (collection) -> UIColor in
                if (collection.userInterfaceStyle == .dark) {
                    return UIColor.init(red: 100/255, green: 100/255, blue: 100/255, alpha: 1)
                }
                return dfaultColor
            }
        } else {
            return dfaultColor
        }
        return retColor
    }
    
複製代碼

只須要在設置顏色時調用便可:

view.backgroundColor = UIColor.configDarkModeViewColorWithdDfaultColor(dfaultColor: UIColor.groupTableViewBackground)
複製代碼

再次運行項目,能夠看到界面已經兼容了暗模式:

drak Mode

本文主要寫了:

  • 不經過storyboard啓動App
  • 登陸UI的實現
  • Drak Mode的適配

本文demo: Github RPChat

相關文章
相關標籤/搜索