1. 程式人生 > >[Swift4.2實際操作]九、完整例項-(7)登入頁面:建立自定義檢視及相關元件

[Swift4.2實際操作]九、完整例項-(7)登入頁面:建立自定義檢視及相關元件

本文將開始建立登入頁面,首先建立該頁面所需的一些自定義元件:
做為登入按鈕的自定義檢視物件。
在【RegLogin】組的名稱上點選滑鼠右鍵,開啟右鍵選單。
【New File】->【Cocoa Touch Class】建立新檔案【RegButton.swift】
Name:RegButton
Subclass:ShadowView
Language:Swift

 1 import UIKit
 2 
 3 class RegButton: ShadowView {
 4     //給類新增一個按鈕型別的屬性
 5     var bt : UIButton!
 6     //首先重寫父類的初始化方法
7 override init(frame: CGRect) { 8 super.init(frame: frame) 9 //設定字第個一檢視的背景顏色 10 self.backgroundColor = UIColor.white 11 //設定字第個一檢視的圓角半徑 12 self.cornerRadius = 4.0 13 //設定字第個一檢視的投影半徑 14 self.shadowRadius = 2.0 15 //設定投影的偏移 16 self.shadowOffset = CGSize(width: 0
, height: 1) 17 //設定陰影的顏色 18 self.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 126.0/255) 19 //初始化一個指定顯示區域的按鈕物件 20 let btFrame = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height) 21 //設定按鈕的字型 22 bt = UIButton(frame: btFrame) 23
bt.titleLabel?.font = UIFont(name: "PingFang SC", size: 14)! 24 //設定按鈕在正常狀態的標題顏色 25 bt.setTitleColor(.white, for: .normal) 26 //設定按鈕在失效狀態的標題顏色 27 bt.setTitleColor(UIColor(red: 230.0/255, green: 230.0/255, blue: 230.0/255, alpha: 1.0), for: .disabled) 28 //設定按鈕的標題 29 bt.setTitle("", for: .normal) 30 //設定按鈕的背景顏色 31 bt.backgroundColor = .clear 32 //將按鈕新增到自定義檢視中 33 self.addSubview(bt) 34 //呼叫自定義檢視物件的例項方法, 35 //設定當前檢視出於失效狀態 36 self.deActive() 37 } 38 //新增一個方法,用來設定當前的自定義檢視的狀態為啟用狀態, 39 //從而允許使用者點選自動定義檢視中的按鈕物件 40 func active() 41 { 42 //首先使按鈕出於正常狀態 43 self.bt.isEnabled = true 44 //按鈕正常狀態下的背景顏色 45 self.backgroundColor = UIColor(red: 255.0/255, green: 89.0/255, blue: 95.0/255, alpha: 1.0) 46 //正常狀態下的標題顏色 47 self.bt.titleLabel?.textColor = UIColor.white 48 } 49 //新增一個方法,用來設定當前的自定義檢視的狀態為啟用狀態, 50 //從而不允許使用者點選自動定義檢視中的按鈕物件 51 func deActive() 52 { 53 54 //首先使按鈕出於失效狀態 55 self.bt.isEnabled = false 56 //按鈕失效狀態下的背景顏色 57 self.backgroundColor = UIColor.white 58 } 59 //最後新增一個必須實現的初始化方法 60 required init?(coder aDecoder: NSCoder) { 61 fatalError("init(coder:) has not been implemented") 62 } 63 }

接著建立一個針對影象類的擴充套件。

【New File】->【Swift File】建立新檔案【ExtensionUIImage.swift】

接著開始編寫程式碼,完成對影象類的擴充套件。

 1 import UIKit
 2 //建立一個影象類的擴充套件
 3 extension UIImage
 4 {
 5     //新增一個擴充套件方法,該方法被用於修改文字框右側的刪除圖示的顏色
 6     func blendColor(_ color: UIColor, blendMode: CGBlendMode) -> UIImage
 7     {
 8         //獲得當前圖片的顯示區域
 9         let rect = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)
10         //獲得當前的圖形上下文。
11         //其中第一個引數表示畫布的大小
12         //第二個引數表示是否透明圖片
13         //第三個引數表示圖片的比例
14         UIGraphicsBeginImageContextWithOptions(size, false, scale)
15         //首先將指定的顏色設定為填充色。
16         color.setFill()
17         //然後將填充色填充在指定的區域內。
18         UIRectFill(rect)
19         //最後將指定區域的內容,繪製在當前的圖形上下文。
20         draw(in: rect, blendMode: blendMode, alpha: 1.0)
21         //從當前的圖形上下文中,獲得填充後的圖片,並關閉圖形上下文。
22         let blendedImage = UIGraphicsGetImageFromCurrentImageContext()
23         UIGraphicsEndImageContext()
24         //最後在方法的末尾,返回圖形上下文中獲得的圖片。
25         return blendedImage!
26     }
27 }

使用鍵盤上的快捷鍵【Command】+【N】,繼續建立一個類檔案。

接著建立一個針對影象類的擴充套件。

【New File】->【Cocoa Touch Class】建立新檔案【UserInfo.swift】

Name:UserInfo
Subclass:NSObjecct
Language:Swift

該類將用來在本地儲存使用者資訊

  1 import UIKit
  2 import Foundation
  3 //使類遵循編碼協議,它可以將類的例項轉化為序列化的資料進行儲存。
  4 class UserInfo : NSObject, NSCoding {
  5     //新增屬性:表示使用者的考試型別
  6     var myKeMu : PaperType = .ACT
  7     //新增屬性:使用者是否為海外使用者
  8     var isHaiWai : Bool = false
  9     //手機號碼
 10     var phone : String = ""
 11     //郵箱
 12     var email : String = ""
 13     //密碼
 14     var password : String = ""
 15     //暱稱
 16     var nickname : String = ""
 17     //驗證碼
 18     var verifyCode : String = ""
 19     //頭像圖片
 20     var avatar : UIImage = UIImage()
 21     //是否參加過考試
 22     var isTested : Bool = false
 23     //頭像路徑
 24     var head_img : String = ""
 25     //年級
 26     var grade : Int = 1
 27     //生日
 28     var birthday = ""
 29     //使用者的唯一標誌符
 30     var id = 0
 31     //性別
 32     var sex = 0
 33     //老師
 34     var teacher = ""
 35     //使用者考試型別
 36     var exam_type = 0
 37     //狀態
 38     var status = 0
 39     //當前總考分
 40     var current_score : Int = 0     //相當於伺服器中的current_score
 41     //英語
 42     var english : Int = 0           //相當於伺服器中的english
 43     //數學
 44     var math : Int = 0              //相當於伺服器中的math
 45     //閱讀
 46     var reading : Int = 0           //相當於伺服器中的reading
 47     //科學
 48     var science : Int = 0           //相當於伺服器中的science
 49     //寫作
 50     var writing : Int = 0           //相當於伺服器中的writing
 51     
 52     var expect_english : Int = 0
 53     var expect_reading : Int = 0
 54     var expect_science : Int = 0
 55     var expect_score : Int = 0
 56     var expect_writing : Int = 0
 57     var expect_math : Int = 0
 58     
 59     //實現協議中的方法
 60     //用來將使用者資訊進行編碼
 61     func encode(with aCoder: NSCoder)
 62     {
 63         //首先對使用者的手機、郵箱、密碼、暱稱、和是否參考過考試等屬性進行編碼
 64         //並設定對應的鍵名
 65         aCoder.encode(self.phone, forKey: "phone")
 66         aCoder.encode(self.email, forKey: "email")
 67         aCoder.encode(self.password, forKey: "password")
 68         aCoder.encode(self.nickname, forKey: "nickname")
 69         aCoder.encode(self.isTested, forKey: "isTested")
 70         //接著對另外八個屬性進行編碼
 71         aCoder.encode(self.head_img, forKey: "head_img")
 72         aCoder.encode(self.grade, forKey: "grade")
 73         aCoder.encode(self.birthday, forKey: "birthday")
 74         aCoder.encode(self.id, forKey: "id")
 75         aCoder.encode(self.sex, forKey: "sex")
 76         aCoder.encode(self.teacher, forKey: "teacher")
 77         aCoder.encode(self.exam_type, forKey: "exam_type")
 78         aCoder.encode(self.status, forKey: "status")
 79         //最後對剩餘的六個屬性進行編碼
 80         aCoder.encode(self.current_score, forKey: "current_score")
 81         aCoder.encode(self.english, forKey: "english")
 82         aCoder.encode(self.math, forKey: "math")
 83         aCoder.encode(self.reading, forKey: "reading")
 84         aCoder.encode(self.science, forKey: "science")
 85         aCoder.encode(self.writing, forKey: "writing")
 86         
 87         aCoder.encode(self.expect_english, forKey: "expect_english")
 88         aCoder.encode(self.expect_reading, forKey: "expect_reading")
 89         aCoder.encode(self.expect_science, forKey: "expect_science")
 90         aCoder.encode(self.expect_score, forKey: "expect_score")
 91         aCoder.encode(self.expect_writing, forKey: "expect_writing")
 92         aCoder.encode(self.expect_math, forKey: "expect_math")
 93     }
 94     //實現協議中的方法,用來將將過編碼的使用者資訊進行解碼
 95     required init(coder aDecoder: NSCoder)
 96     {
 97         super.init()
 98         //首先對使用者的手機、郵箱、密碼、暱稱、和是否參考過考試等屬性進行解碼
 99         self.phone = aDecoder.decodeObject(forKey: "phone") as! String
100         self.email = aDecoder.decodeObject(forKey: "email") as! String
101         self.password = aDecoder.decodeObject(forKey: "password") as! String
102         self.nickname = aDecoder.decodeObject(forKey: "nickname") as! String
103         self.nickname = aDecoder.decodeObject(forKey: "nickname") as! String
104          //接著對另外八個屬性進行解碼
105         self.head_img = aDecoder.decodeObject(forKey: "head_img") as! String
106         self.grade = aDecoder.decodeInteger(forKey: "grade")
107         self.birthday = aDecoder.decodeObject(forKey: "birthday") as! String
108         self.id = aDecoder.decodeInteger(forKey: "id")
109         self.sex = aDecoder.decodeInteger(forKey: "sex")
110         self.teacher = aDecoder.decodeObject(forKey: "teacher") as! String
111         self.exam_type = aDecoder.decodeInteger(forKey: "exam_type")
112         self.status = aDecoder.decodeInteger(forKey: "status")
113         //然後對剩餘的六個屬性進行解碼
114         self.current_score = aDecoder.decodeInteger(forKey: "current_score")
115         self.english = aDecoder.decodeInteger(forKey: "english")
116         self.math = aDecoder.decodeInteger(forKey: "math")
117         self.reading = aDecoder.decodeInteger(forKey: "reading")
118         self.science = aDecoder.decodeInteger(forKey: "science")
119         self.writing = aDecoder.decodeInteger(forKey: "writing")
120         
121         self.expect_english = aDecoder.decodeInteger(forKey: "expect_english")
122         self.expect_reading = aDecoder.decodeInteger(forKey: "expect_reading")
123         self.expect_science = aDecoder.decodeInteger(forKey: "expect_science")
124         self.expect_score = aDecoder.decodeInteger(forKey: "expect_score")
125         self.expect_writing = aDecoder.decodeInteger(forKey: "expect_writing")
126         self.expect_math = aDecoder.decodeInteger(forKey: "expect_math")
127         
128         
129     }
130     //最後新增一個初始化方法,完成使用者資訊類的建立
131     override init()
132     {
133         
134     }
135     
136     func setScore(num:Int, score:Int)
137     {
138         switch num {
139             case 0:
140                 self.current_score = score
141             case 1:
142                 self.english = score
143             case 2:
144                 self.math = score
145             case 3:
146                 self.reading = score
147             case 4:
148                 self.science = score
149             default: break
150             
151         }
152     }
153     
154     func setSATScore(num:Int, score:Int)
155     {
156         switch num {
157         case 0:
158             self.reading = score
159         case 1:
160             self.math = score
161         case 2:
162             self.writing = score
163         default: break
164             
165         }
166     }
167 }

使用鍵盤上的快捷鍵【Command】+【N】,繼續建立一個類檔案。

【New File】->【Swift File】建立新檔案【DataUtil.swift】

接著開始編寫程式碼,完成對影象類的擴充套件。

  1 import Foundation
  2 import UIKit
  3 import Alamofire
  4 import Toaster
  5 import PKHUD
  6 import Qiniu
  7 
  8 class DataUtil
  9 {
 10     class func hasLogined() -> Bool
 11     {
 12         return UserDefaults.standard.bool(forKey: "hasLogin")
 13     }
 14     class func setLogined()
 15     {
 16         UserDefaults.standard.set(true, forKey: "hasLogin")
 17         UserDefaults.standard.synchronize()
 18     }
 19     class func setLoginOut()
 20     {
 21         UserDefaults.standard.set(false, forKey: "hasLogin")
 22         UserDefaults.standard.synchronize()
 23     }
 24     
 25     class func hasShowIntro() -> Bool
 26     {
 27         return UserDefaults.standard.bool(forKey: "hasShowIntro")
 28     }
 29     class func setShowInfo()
 30     {
 31         UserDefaults.standard.set(true, forKey: "hasShowIntro")
 32         UserDefaults.standard.synchronize()
 33     }
 34     
 35     class func getTabBarHeight(vc:UIViewController) -> CGFloat
 36     {
 37         return (vc.tabBarController?.tabBar.frame.size.height)!
 38     }
 39     
 40     class func setCrtUser(userInfo : UserInfo)
 41     {
 42         let data = NSMutableData()
 43         let archive = NSKeyedArchiver(forWritingWith: data)
 44         archive.encode(userInfo, forKey: "crtUserInfo")
 45         archive.finishEncoding()
 46         
 47         let filePath = NSHomeDirectory() + "/Documents/crtUserInfo.data"
 48         data.write(toFile: filePath, atomically: true)
 49     }
 50     //新增一個類方法,用來獲得歸檔的使用者資訊
 51     class func getCrtUser() -> UserInfo
 52     {
 53         //首先獲得使用者歸檔檔案的儲存路徑
 54         let filePath = NSHomeDirectory() + "/Documents/crtUserInfo.data"
 55         //然後載入該路徑下的檔案,並初始化一個鍵值解碼器
 56         let fileData = NSMutableData(contentsOfFile: filePath)
 57         let unarchiver = NSKeyedUnarchiver(forReadingWith: fileData! as Data)
 58         //根據鍵名,對指定的歸檔進行解碼
 59         let savedUser = unarchiver.decodeObject(forKey: "crtUserInfo") as! UserInfo
 60         unarchiver.finishDecoding()
 61         //最後返回解碼後的使用者資訊物件
 62         return savedUser
 63     }
 64     //接著新增一個類方法,用來設定使用者使用遊客身份訪問應用程式
 65     class func setVisitorLogin(value:Bool)
 66     {
 67         UserDefaults.standard.set(value, forKey: "IsVisitorLogin")
 68         UserDefaults.standard.synchronize()
 69     }
 70     //新增一個類方法,用來判斷使用者是否為遊客身份
 71     class func isVisitorLogin() -> Bool
 72     {
 73         return UserDefaults.standard.bool(forKey: "IsVisitorLogin")
 74     }
 75     //新增一個類方法,用來將頭像資料儲存到沙盒目錄
 76     class func saveAvarta(data:Data)
 77     {
 78         let targetPath:String = NSHomeDirectory() + "/Documents/avarta.png"
 79         try? data.write(to: URL(fileURLWithPath: targetPath))
 80     }
 81      //新增一個類方法,用來讀取沙盒中儲存的頭像
 82     class func getAvarta() -> UIImage?
 83     {
 84         let targetPath:String = NSHomeDirectory() + "/Documents/avarta.png"
 85         
 86         let image = UIImage(contentsOfFile: targetPath)
 87         return image
 88     }
 89     //新增一個類方法,用來給影象檢視設定使用者的頭像
 90     class func setAvartaForImageView(imageView : UIImageView)
 91     {
 92         //首先讀取之前儲存的使用者頭像
 93         let localImage = getAvarta()
 94         //判斷當讀取的影象不為空時,設定影象檢視
 95         if(localImage == nil)
 96         {
 97             //如果沒有獲得使用者頭像,
 98             let user = getCrtUser()
 99             //則從儲存的使用者資訊中,獲取使用者頭像的遠端路徑
100             let imageUrl = user.head_img
101             //如果遠端路徑為空,則設定使用者頭像為預設圖片
102             if(imageUrl != "")
103             {
104                 //如果遠端路徑不為空,
105                 let url = URL(string: imageUrl)
106                 //則初始化一個指定網址的網路請求
107                 let request = URLRequest(url: url!)
108                 //使用非同步的方式,請求遠端伺服器上的圖片資源
109                 NSURLConnection.sendAsynchronousRequest(request, queue: OperationQueue.main, completionHandler: {(response:URLResponse?, data:Data?,error:Error?)->Void in
110                     //然後返回主執行緒,對影象檢視進行更新
111                     DispatchQueue.main.async(execute: { () -> Void in
112                         let image = UIImage(data: data!)
113                         imageView.image = image
114                     })
115                 })
116             }
117             else
118             {
119                 //則設定使用者頭像為預設圖片
120                 imageView.image = UIImage(named: "defaultAvarta")
121             }
122         }
123         else
124         {
125             imageView.image = localImage
126         }
127     }
128     //新增一個方法,用來將頭像上傳至七牛伺服器
129     class func uploadAvartaToQiNiu(baseUrl: String, avarta: UIImage)
130     {
131         //初始化一個字串常量,表示網路請求的介面地址
132         let url = "\(baseUrl)iOS/uploadAvarta.json"
133         //然後開始顯示載入動畫,並設定彈出框的字型樣式。
134         HUD.show(.progress)
135         ToastView.appearance().font = UIFont(name: "PingFang SC", size: 14)!
136         //使用第三方類庫,訪問指定的網址,並返回Json格式的結果
137         Alamofire.request(url, method: .get).responseJSON
138             { 
139                 //如果返回成功的結果
140                 //則獲得返回結果中的編碼和詳情欄位
141                 response in
142                 print(response)
143                 if let json = response.result.value as? [String: Any]
144                 {
145                     print("JSON: \(json)")
146                     let code = json["code"] as? Int ?? 0
147                     let detail = json["detail"] as? [String: Any]
148                     //設定彈出視窗到螢幕底部的距離
149                     ToastView.appearance().bottomOffsetPortrait = 150
150                     //如果返回值為0,則表示網路請求成功,
151                     if(code == 0)
152                     {
153                          //獲得伺服器返回的將要上傳至七牛的圖片名稱和上傳口令。
154                         let upload_name = detail?["upload_name"] as? String ?? ""
155                         //獲得伺服器返回的將要上傳至七牛的上傳口令。
156                         let upload_token = detail?["upload_token"] as? String ?? ""
157                         print(upload_token)
158                         //初始化一個七牛上傳管理器
159                         let upManager = QNUploadManager()
160                         //並將圖片轉換為二進位制
161                         let data = UIImagePNGRepresentation(avarta)
162                         //呼叫七牛上傳管理器的上傳方法,開始圖片的上傳。
163                         upManager?.put(data, key: upload_name, token: upload_token, complete:{ (info, key, resp) -> Void in
164                             
165                             print(info)
166                             print("----------")
167                             print(resp)
168                             //如果七牛返回的狀態碼為200,則表示上傳成功。
169                             if (info?.statusCode == 200 && resp != nil)
170                             {
171                                 //接著將使用者資訊進行更新,
172                                 //首先獲得已經儲存在沙盒中的當前的使用者
173                                 let userInfo = DataUtil.getCrtUser()
174                                 //定義一個網路地址,用來獲得伺服器上的使用者資訊
175                                 let url = "\(baseUrl)iOS/headImage.json"
176                                 //並設定訪問時傳遞的引數,以更新遠端伺服器上使用者的頭像資訊
177                                 let parameters = ["head_img": "https://www.cnblogs.com/strengthen/\(upload_name)"]
178                                 //使用第三方類庫,訪問指定的網址,並返回Json格式的結果
179                                 Alamofire.request(url, method: .get, parameters: parameters).responseJSON
180                                     { 
181                                         response in
182                                         HUD.hide(animated: true)
183                                         //對返回的結果進行判斷和處理
184                                         if let json = response.result.value as? [String: Any]
185                                         {
186                                             print("JSON: \(json)")
187                                             //獲得伺服器返回的狀態碼
188                                             let code = json["code"] as? Int ?? 0
189                                             //如果狀態碼為0,則表示請求成功,否則彈出失敗提示視窗
190                                             if(code == 0)
191                                             {
192                                                 //顯示彈出視窗,提示圖片上傳成功。
193                                                 ToastView.appearance().bottomOffsetPortrait = 80
194                                                 Toast(text: "Image was successfully uploaded!").show()
195                                                 //然後獲得伺服器返回的頭像路徑,
196                                                 //並更新使用者資訊中的頭像路徑。
197                                                 let detail = json["detail"] as? [String: Any]
198                                                 userInfo.head_img = detail?["head_img"] as? String ?? ""
199                                                 //最後更新儲存在本地的使用者資訊。
200                                                 DataUtil.setCrtUser(userInfo: userInfo)
201                                                 DataUtil.saveAvarta(data: data!)
202                                             }
203                                             else
204                                             {
205                                                 let detail = json["detail"] as? String ?? ""
206                                                 ToastView.appearance().bottomOffsetPortrait = 80
207                                                 Toast(text: detail).show()
208                                                 
209                                             }
210                                         }
211                                         else
212                                         {
213                                             ToastView.appearance().bottomOffsetPortrait = 80
214                                             Toast(text: "Upload failed!").show()
215                                         }
216                                 }
217                             }
218                             else
219                             {
220                                 HUD.hide(animated: true)
221                             }
222                             
223                         }, option: nil)
224                     }
225                     else
226                     {
227                         //r如果返回編碼的值不為零。則提示編碼失敗
228                         ToastView.appearance().bottomOffsetPortrait = 80
229                         //則開啟提示視窗,提示上傳失敗,
230                         Toast(text: "Upload failed!").show()
231                         //並隱藏載入動畫
232                         HUD.hide(animated: true)
233                     }
234                 }
235                 else
236                 {
237                      //如果上傳失敗,
238                     ToastView.appearance().bottomOffsetPortrait = 80
239                      //則開啟提示視窗,提示上傳失敗,
240                     Toast(text: "Upload failed!").show()
241                       //並隱藏載入動畫
242                     HUD.hide(animated: true)
243                 }
244         }
245     }
246 }
247 
248 func getKemuBySection(section: String) -> String
249 {
250     if(section == "english")
251     {
252         return "英語"
253     }
254     else if(section == "math")
255     {
256         return "數學"
257     }
258     else if(section == "reading")
259     {
260         return "閱讀"
261     }
262     else if(section == "science")
263     {
264         return "科學"
265     }
266     else if(section == "language")
267     {
268         return "語言"
269     }
270     else if(section == "mathc")
271     {
272         return "數學計算器"
273     }
274     else
275     {
276         return section
277     }
278 }
279 
280 func getLevel(level: String) -> String
281 {
282     if(level == "E")
283     {
284         return "簡單"
285     }
286     else if(level == "M")
287     {
288         return "中等"
289     }
290     else
291     {
292         return "困難"
293     }
294 }