從100 Days of Swift中學習疾层,實踐
目前正在學習swift , 剛剛接觸了解了一部分語法后就因為自己在OC上使用reactiveOBJC還算熟練,想直接學會rxswift和reactiveswift 矢渊,中間因為xcode有時候索引失效和一些其他原因,想過放棄學習枉证,無意中看到 關于iOS學習進階的必讀一些博客總結 這個文章時看到了 100 Days of Swift矮男, 感覺從一次次項目中,更加能夠堅實我的基礎室谚, 所以決定從基礎開始昂灵,跟著一步步往前走
Day 4
可以先來說一下我的ViewController分層
代碼:
//MARK:-視圖加載
//MARK:-自定義方法
//MARK:-事件
//MARK:-代理方法
//MARK:-數(shù)據(jù)源
//MARK:-生命周期
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK:-懶加載
當然在extension 里面實現(xiàn)delegate
PROJECT 7 - PASSING DATA TO ANOTHER VIEW
傳遞數(shù)據(jù)到另一個view**
代碼:
//FirstViewController
let secondVC:SecondViewController = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
secondVC.restoreText = self.message
//SecondViewController
var restoreText:String?
PROJECT 8 - SWIPE TO DISMISS KEYBOARD
實現(xiàn)一個向下拖拽的方法,使鍵盤消失
代碼:
@IBOutlet weak var MessageTextView: UITextView!
fileprivate func initEvents(){
let swipeDownGesture = UISwipeGestureRecognizer(target: self, action:#selector(downGesture(_:)))
swipeDownGesture.direction = UISwipeGestureRecognizerDirection.down //不設置是右
MessageTextView.addGestureRecognizer(swipeDownGesture)
}
@objc fileprivate func downGesture(_ gesture:UISwipeGestureRecognizer){
MessageTextView.resignFirstResponder()
}
PROJECT 9 - ADD PHOTO FROM CAMERA ROLL
- Access the Camera Roll from within the App
- Create Image Picker Controller
- Handle a selected image in the Camera Roll
- Control how the image is displayed to prevent stretching
主要難點在于添加圖片到textview中
思路:
1.首先要能夠進入相冊(我這里直接使用了相冊舞萄, 并沒有使用camera)
2.選中圖片后獲取到圖片
3.富文本內(nèi)容眨补, 用NSAttributeString
承接
4.在接收到圖片以后需要進行哪里處理?
先將已有內(nèi)容保存下來倒脓,然后用NSAttachment
接收到Image
撑螺,然后通過其內(nèi)的方法轉(zhuǎn)為NSAttributeString
需要注意的事項
-
NSAttachment.bounds
可以用來調(diào)整圖片大小和圖片位置 - 在添加完圖片以后需要調(diào)整光標位置,并且將view移動到光標處崎弃,并且需要設置內(nèi)容的字體大懈饰睢(之前設置的是textFont, NSAttributedText的字體還未設置)
未解決的問題
- 在textview中 直接在
NSAttributerString
中追加"\n" 或者"\r\n" 無法換行,如果設置圖片的模式是適配textview的寬度饲做,那么就會導致添加圖片后线婚,光標在圖片右邊,而換行后的位置盆均。 目前我還沒有好的解決方案塞弊, 只能先做成在添加完圖片以后,textview失去第一響應泪姨,來讓用戶自己選擇光標位置游沿。如果有什么好的解決方案, 請聯(lián)系我0估诀黍!
(學習過程用, 遇到不太會的知識仗处, 盡量去找文檔眯勾, 翻Dash枣宫,也許會比直接baidu現(xiàn)成的代碼更好)
代碼
import UIKit
enum ImageAttachmentMode {
case Default //默認(不改變大小)
case FitTextLine //使尺寸適應行高
case FitTextView //使尺寸適應textView
}
class ViewController: UIViewController {
@IBOutlet weak var MessageTextView: UITextView!
var message:String?
//MARK:-視圖加載
fileprivate func setupUI() {
// let rightItem = UIBarButtonItem.init(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: #selector(rightBtnClick(_:)))
let rightItem = UIBarButtonItem.init(barButtonSystemItem: UIBarButtonSystemItem.camera, target: self, action: #selector(rightBtnClick(_:)))
// rightItem.setBackgroundImage(UIImage(), for: UIControlState.normal, barMetrics: UIBarMetrics.default)
// rightItem.setBackgroundImage(UIImage(), for: UIControlState.highlighted, barMetrics: UIBarMetrics.default)
// rightItem.
self.navigationItem.rightBarButtonItem = rightItem
}
//MARK:-自定義方法
fileprivate func initEvents(){
let swipeDownGesture = UISwipeGestureRecognizer(target: self, action:#selector(downGesture(_:)))
swipeDownGesture.direction = UISwipeGestureRecognizerDirection.down //不設置是右
MessageTextView.addGestureRecognizer(swipeDownGesture)
}
fileprivate func insertPicture(_ image:UIImage,_ model:ImageAttachmentMode = .Default){
//將現(xiàn)存所有文字轉(zhuǎn)為 NSMutableAttributedString
let mutableString = NSMutableAttributedString.init()
mutableString.append(MessageTextView.attributedText)
//獲取光標的位置
let mutableSelectRange = MessageTextView.selectedRange
//創(chuàng)建附件吃环,來保存圖片
let imgAttachment = NSTextAttachment.init()
//用來保存附件 attachment轉(zhuǎn)化的attributeString
var imageAttributeString:NSAttributedString
//主要兩個屬性 一個image也颤,圖片資源, 一個bounds 圖片位置
imgAttachment.image = image
//根據(jù)模式選擇圖片放置的模式
switch model {
//適應文字大小
case .FitTextLine:
imgAttachment.bounds = CGRect.init(x: 0, y: -4, width: (MessageTextView.font?.lineHeight)!, height: (MessageTextView.font?.lineHeight)!)
//適應textview的寬度 撐滿一行
case .FitTextView:
let imageWidth = MessageTextView.bounds.width-10
let imageHeight = image.size.height/image.size.width*imageWidth
imgAttachment.bounds = CGRect.init(x: 0, y: 0, width: imageWidth, height: imageHeight)
default:
break
}
imageAttributeString = NSAttributedString.init(attachment: imgAttachment)
mutableString.append(imageAttributeString)
mutableString.addAttribute(NSAttributedStringKey.font, value: UIFont.systemFont(ofSize: 17), range: NSMakeRange(0,mutableString.length))
//記住新的光標位置
let newSelectRange = NSMakeRange(mutableSelectRange.location+1,0)
//賦值到textview
MessageTextView.attributedText = mutableString
//刷新光標
MessageTextView.selectedRange = newSelectRange
//滾動到光標位置
MessageTextView.scrollRangeToVisible(newSelectRange)
}
//MARK:-事件
@objc fileprivate func rightBtnClick(_ sender:UIBarButtonItem){
// let secondVC:SecondViewController = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
// secondVC.restoreText = self.message
// self.navigationController?.pushViewController(secondVC, animated: true)
//訪問相冊頁面
//從Dash文檔上根據(jù)文檔說明模叙,步驟進行開發(fā)
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.photoLibrary){
UIImagePickerController.availableMediaTypes(for: UIImagePickerControllerSourceType.photoLibrary)
let vc = UIImagePickerController.init()
vc.delegate = self
self.present(vc, animated: true, completion: {
})
}
else {
}
}
@objc fileprivate func downGesture(_ gesture:UISwipeGestureRecognizer){
MessageTextView.resignFirstResponder()
}
//MARK:-代理方法
//MARK:-數(shù)據(jù)源
//MARK:-生命周期
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
initEvents()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK:-懶加載
}
extension ViewController: UIImagePickerControllerDelegate,UINavigationControllerDelegate{
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage]
self.insertPicture(image as! UIImage,.FitTextView)
self.MessageTextView.resignFirstResponder()
picker.dismiss(animated: true, completion: nil)
}
}
extension ViewController:UITextViewDelegate{
func textViewDidEndEditing(_ textView: UITextView) {
message = textView.text
textView.resignFirstResponder()
}
}
PROJECT 10 - PULL TO REFRESH TABLE VIEW (未完成自定義refresh功能)
- Build a custom Table View Controller
- Create custom Refresh Control
- Stop refresh animation when data finishes updating
- Update the table with refreshed local data
還在學習MJRefresh源碼中歇拆, 之后補上
PROJECT 11 - DELETING AND REARRANGING
- Remove data from Data Source
- Delete data from Table Row
- Animate the item deletion
- Handle rearranging Table Rows
- Enable swipe to delete Table Row
PROJECT 12 - ADD NEW ITEM
- Create a Model to interact with View Controllers
- Add data to the Model
- Update the Table View when the View loads
- Dismiss the View from the Keyboard Done key
- Segue to new Views from a Button (沒有使用segue)
除了project 10 其他內(nèi)容也相對簡單,整合在一起記錄范咨。
- 使用ViewModel的Array 作為tableview的數(shù)據(jù)源
- 查找tableview的delegate方法故觅, 刪除,移動渠啊,根據(jù)操作修改ViewModel的Array數(shù)據(jù)
- 從SecondViewController中點擊Done 添加此數(shù)據(jù)到ViewModel的Array中输吏。并且通過閉包回調(diào)到FirstViewController,刷新tableview
代碼:
FirstViewController
import UIKit
class ViewController: UITableViewController {
//MARK:-視圖加載
//MARK:-自定義方法
//MARK:-事件
@objc func Edit(){
self.tableView.isEditing = !self.tableView.isEditing
}
@objc func Add(){
let vc:AddViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "AddViewController") as! AddViewController
self.navigationController?.pushViewController(vc, animated: true)
weak var weakself = self
//回調(diào)方法
vc.sendHandler { (str) in
weakself?.viewmodel.Movies.append(str)
weakself?.tableView.reloadData()
}
}
//MARK:-代理方法
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// UIStoryboard mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
// MainViewController *mainController = [mainStoryboard instantiateViewControllerWithIdentifier:@"MainViewController"];
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "TimeViewController")
self.navigationController?.pushViewController(vc, animated: true)
}
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let tmp:String = viewmodel.Movies[sourceIndexPath.row]
viewmodel.Movies.remove(at: sourceIndexPath.row)
viewmodel.Movies.insert(tmp, at: destinationIndexPath.row)
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
print("\(#function)")
if editingStyle == .delete {
viewmodel.Movies.remove(at: indexPath.row)
tableView.reloadData()
}
else if editingStyle == .insert
{
}
}
//MARK:-數(shù)據(jù)源
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewmodel.Movies.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = viewmodel.Movies[indexPath.row]
cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
cell.selectionStyle = .none
return cell
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
//MARK:-生命周期
override func viewDidLoad() {
super.viewDidLoad()
// self.tableView.delegate = self
// self.tableView.dataSource = self
self.tableView.tableFooterView = UIView.init(frame: CGRect.zero)
self.tableView.register(object_getClass(UITableViewCell()), forCellReuseIdentifier: "cell")
let leftItem = UIBarButtonItem.init(title: "Edit", style: UIBarButtonItemStyle.plain, target: self, action: #selector(Edit))
self.navigationItem.leftBarButtonItem = leftItem
let rightAddItem = UIBarButtonItem.init(barButtonSystemItem: UIBarButtonSystemItem.add, target: self, action: #selector(Add))
self.navigationItem.rightBarButtonItem = rightAddItem
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK:-懶加載
lazy var viewmodel: ViewModel = {
let vm = ViewModel()
return vm
}()
}
SecondViewController
import UIKit
class AddViewController: UIViewController {
//閉包定義
typealias SendBlockHandler = (_ str:String)->Void
var sendHandlerClosuer:SendBlockHandler?
//必須要用方法承接閉包替蛉, 不能像OC一樣定義完Block以后贯溅,可以直接使用這個屬性
func sendHandler(closure:@escaping SendBlockHandler) -> Void {
sendHandlerClosuer = closure
}
override func viewDidLoad() {
super.viewDidLoad()
AddTextView.becomeFirstResponder()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBOutlet weak var AddTextView: UITextView!
@IBAction func SwipDownGesture(_ sender: Any) {
AddTextView.resignFirstResponder()
}
}
extension AddViewController:UITextViewDelegate{
//控制Return
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text == "\n" {
textView.resignFirstResponder()
self.navigationController?.popViewController(animated: true)
sendHandlerClosuer!(textView.text)
return false
}
return true
}
}
在實際項目中實踐,在書寫記錄中鞏固躲查,每日一記它浅。