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
    }
    
}


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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容

  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,409评论 2 45
  • 最近在公司做了我们的pc端网站。需求:实现网页的下拉加载页面思路: 中包含list,这是一个list中包含的元素块...
    薛云龙阅读 8,517评论 4 4
  • 反思:每天给自己安排大量的输入任务,是想增加认知,输入的目的是想证明自己可以学到多少东西,觉得自己缺,所以才贪婪。...
    和时间做朋友阅读 275评论 0 0