Swift学习记录 Day 4

从100 Days of Swift中学习,实践

目前正在学习swift , 刚刚接触了解了一部分语法后就因为自己在OC上使用reactiveOBJC还算熟练,想直接学会rxswift和reactiveswift ,中间因为xcode有时候索引失效和一些其他原因,想过放弃学习,无意中看到 关于iOS学习进阶的必读一些博客总结 这个文章时看到了 100 Days of Swift, 感觉从一次次项目中,更加能够坚实我的基础, 所以决定从基础开始,跟着一步步往前走


Day 4

可以先来说一下我的ViewController分层
代码:

//MARK:-视图加载

//MARK:-自定义方法

//MARK:-事件

//MARK:-代理方法

//MARK:-数据源


//MARK:-生命周期
override func viewDidLoad() {
    super.viewDidLoad()
    
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

//MARK:-懒加载

当然在extension 里面实现delegate


PROJECT 7 - PASSING DATA TO ANOTHER VIEW
传递数据到另一个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
实现一个向下拖拽的方法,使键盘消失
代码:

    @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.富文本内容, 用NSAttributeString承接
4.在接收到图片以后需要进行哪里处理?
先将已有内容保存下来,然后用NSAttachment接收到Image ,然后通过其内的方法转为NSAttributeString

需要注意的事项

  1. NSAttachment.bounds可以用来调整图片大小和图片位置
  2. 在添加完图片以后需要调整光标位置,并且将view移动到光标处,并且需要设置内容的字体大小(之前设置的是textFont, NSAttributedText的字体还未设置)

未解决的问题

  • 在textview中 直接在NSAttributerString中追加"\n" 或者"\r\n" 无法换行,如果设置图片的模式是适配textview的宽度,那么就会导致添加图片后,光标在图片右边,而换行后的位置。 目前我还没有好的解决方案, 只能先做成在添加完图片以后,textview失去第一响应,来让用户自己选择光标位置。如果有什么好的解决方案, 请联系我!!

(学习过程用, 遇到不太会的知识, 尽量去找文档, 翻Dash,也许会比直接baidu现成的代码更好)
代码

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){
        //将现存所有文字转为 NSMutableAttributedString
        let mutableString = NSMutableAttributedString.init()
        mutableString.append(MessageTextView.attributedText)
        //获取光标的位置
        let mutableSelectRange = MessageTextView.selectedRange
        
        //创建附件,来保存图片
        let imgAttachment = NSTextAttachment.init()
        
        //用来保存附件 attachment转化的attributeString
        var imageAttributeString:NSAttributedString
        
        //主要两个属性   一个image,图片资源,   一个bounds 图片位置
        imgAttachment.image = image
        
        //根据模式选择图片放置的模式
        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文档上根据文档说明,步骤进行开发
        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:-数据源
    
    
    //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 其他内容也相对简单,整合在一起记录。

  • 使用ViewModel的Array 作为tableview的数据源
  • 查找tableview的delegate方法, 删除,移动,根据操作修改ViewModel的Array数据
  • 从SecondViewController中点击Done 添加此数据到ViewModel的Array中。并且通过闭包回调到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
//回调方法
        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:-数据源
    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
    }
    
}


在实际项目中实践,在书写记录中巩固,每日一记。

你可能感兴趣的:(Swift学习记录 Day 4)