【Swift3】卡片功能

添加卡片信息(卡片正反照片,名称,卡号和密码)
编辑修改卡片信息
卡片列表:可删除,移动

添加卡片信息

  • 点击头部两个按钮,从相册分别添加正反照片

iOS8之后,使用UIImagePickerController调取相册的时候会崩溃,需要设置权限

原因是我们需要在info.plist文件中添加权限

Privacy - Photo Library Usage Description
是否允许访问相册
Privacy - Camera Usage Description
是否允许访问相机

  • 下面是代码部分
    isFront控制时正面照片还是反面照片
   isFront = btn.tag == 0 ? true : false
        //弹框提示如何选择图片
        let alertController = UIAlertController(title: btn.tag == 0 ? "正面图片" : "背面图片", message: nil, preferredStyle: .actionSheet)
        let cancelAction = UIAlertAction(title: "取消", style: .cancel, handler:
        {
            (UIAlertAction) -> Void in
            print("你点击了取消")
        })
        let okAction = UIAlertAction(title: "从相册中选择照片", style: .default, handler:
        {
            (UIAlertAction) -> Void in
            print("点击从相册中选择")
            let imagePicker = UIImagePickerController()
            imagePicker.delegate = self
            imagePicker.allowsEditing = true
            imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
            self.present(imagePicker, animated: true, completion: nil)
        })
        
        let okAction1 = UIAlertAction(title: "拍照", style: .default, handler:
        {
            (UIAlertAction) -> Void in
            if UIImagePickerController.isSourceTypeAvailable(.camera)
            {
                print("拍照可用")
                let imagePicker = UIImagePickerController()
                imagePicker.delegate = self
                imagePicker.allowsEditing = true
                imagePicker.sourceType = UIImagePickerControllerSourceType.camera
                self.present(imagePicker, animated: true, completion: nil)
            }
            else
            {
                print("拍照不可用")
            }
            
        })
        alertController.addAction(cancelAction)
        alertController.addAction(okAction)
        alertController.addAction(okAction1)
        self.present(alertController, animated: true, completion: nil)
  • 要想实现相册选择,必须同时实现UIImagePickerControllerDelegate,UINavigationControllerDelegate两种协议

###在代理中实现,将相册中选中的图片添加至tableView的头部按钮上

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
    {
        //在相册中选择完照片后的回调
        picker.dismiss(animated: true, completion: nil)
        let imageStr : UIImage = info[UIImagePickerControllerEditedImage] as! UIImage
        //显示
        if isFront
        {
            frontBtn.setImage(imageStr, for: UIControlState.normal)
        }
        else
        {
            backBtn.setImage(imageStr, for: UIControlState.normal)
        }  
    }
  • 点击保存时,检查是否均已输入,若没有则弹框提示,若全部输入则跳出
###判断三个textField

//1.在tableView中记录textField
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        cell.inputTextField.tag = indexPath.row
        return cell;
    }

//2.viewDidLoad中注册消息监听
       NotificationCenter.default.addObserver(self, selector: #selector(notificationResponse(notification:)), name: NSNotification.Name.UITextFieldTextDidChange, object: nil)

//3.实现实时监听,将textField的值赋值给变量
    func notificationResponse(notification: NSNotification)
    {
        let textField : UITextField = notification.object as! UITextField
        if textField.tag == 0
        {
            memberName = textField.text!
        }
        else if textField.tag == 1
        {
            memberNum = textField.text!
        }
        else
        {
            memberPassWord = textField.text!
        }
    }

//4.点击保存按钮的时候,判断变量是否有值
        if (memberName.lengthOfBytes(using: String.Encoding.utf8) == 0 ||
            memberNum.lengthOfBytes(using: String.Encoding.utf8) == 0 ||
            memberPassWord.lengthOfBytes(using: String.Encoding.utf8) == 0)
        {
            ToastView.instance.showToast(content: "输入不全", duration: 1.5)
        }
        else
        {
            print("保存")
        }
###判断正反面照片
###照片存本地文件:在documentDirectory下新建"/Documents/Member"的路径,将照片保存在文件中,,均保存在Member文件夹下,并且没张图片以当前时间戳命名
###点击保存时,判断正反面照片是否有值,将当前时间戳.jpg赋值给正反面照片的变量,判断此变量即可


###Tools工具类
getDocumentsMemberFile方法返回在documentDirectory下新建"/Documents/Member"的路径
getTimeSP返回当前时间戳

    //MAARK: - 获取Documents下的路径
    /*
     *在iOS8之前,我们获取到沙盒中的document、cache、tmp之后,下一次模拟器或真机无论怎样重启,这具体的路径是固定的了
     在iOS8之后,苹果可能考虑到安全因素,应用每一次重启,沙盒路径都动态的发生了变化,但是并不代表你原来沙盒路径中的数据发生了变化;同时,也并不代表路径会越来越多
     1>苹果会把你上一个路径中的数据转移到你新的路径中。
     2>你上一个路径也会被苹果毫无保留的删除,只保留最新的路径
     */
    public func getDocumentsMemberFile() -> String
    {
        //Documents下创建或找到文件
        let rootPath = NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask, true)[0] as String
        let filePath:String = rootPath + "/Documents/Member"
        return filePath
    }

    //MARK: - 获取当前时间戳
    public func getTimeSP() -> Int
    {
        let now = Date()
        let timeInterval:TimeInterval = now.timeIntervalSince1970
        let timeStamp = Int(timeInterval)
        return timeStamp
    }

###在相册选择照片的回调代理中,将已保存在本地文件的图片的最后名字(时间戳)赋值给变量
    //MARK: - UIImagePickerControllerDelegate
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
    {
        //在相册中选择完照片后的回调
        picker.dismiss(animated: true, completion: nil)
        let imageStr : UIImage = info[UIImagePickerControllerEditedImage] as! UIImage
        //将图片存入文件
        let filePath = Tools().getDocumentsMemberFile()
        let exist = FileManager.default.fileExists(atPath: filePath)
        if !exist
        {
            try! FileManager.default.createDirectory(atPath: filePath,
                                                     withIntermediateDirectories: true, attributes: nil)
        }
        //将图片保存在文件中
        let imagePath = "\(filePath)/\(Tools().getTimeSP()).jpg"
        let imageData = UIImageJPEGRepresentation(imageStr, 1.0)
        FileManager.default.createFile(atPath: imagePath, contents: imageData, attributes: nil)
        //保存相对路径
        let imageNSURL:NSURL = NSURL.init(fileURLWithPath: imagePath)
        let imageLastPath = imageNSURL.lastPathComponent!
        //显示
        if isFront
        {
            frontBtn.setImage(imageStr, for: UIControlState.normal)
            frontPhoto = imageLastPath
        }
        else
        {
            backBtn.setImage(imageStr, for: UIControlState.normal)
            backPhoto = imageLastPath
        } 
    }

###在点击保存按钮时,判断正反照片的变量是否有值即可
    

  • 若本次卡片信息全部输入,则保存本地

参考:
http://www.jianshu.com/writer#/notebooks/11959695/notes/12740387/preview

###先将本次信息保存字典
  var dic = [String:Any]()
            dic["frontPhoto"] = frontPhoto
            dic["backPhoto"] = backPhoto
            dic["memberName"] = memberName
            dic["memberNum"] = memberNum
            dic["memberPassWord"] = memberPassWord

###声明可变数组memberList,如果本地有memberList的内容,则将它取出来赋值给一个不可变数组,再将不可变数组内容for循环添加至memberList
            let memberList : NSMutableArray = []
            if UserDefaults.standard.value(forKey: "memberList") != nil
            {
                let array = UserDefaults.standard.value(forKey: "memberList") as! NSArray
                memberList.removeAllObjects()
                let num = array.count
                for i in 0..<num
                {
                    memberList.add(array[i])
                }
            }

###如果这个界面时新增卡片页面,则memberList直接添加dic即可,但如果是编辑页面,则需要移除原本的信息,再将新修改的信息保存
            if itemDic.count > 0
            {
                let index = memberList.index(of: itemDic)
                memberList.remove(itemDic)
                memberList.insert(dic, at: index)
            }
            else
            {
                memberList.add(dic)
            }

###再将memberList赋值给不可变数组,方便存入UserDefaults保存
            let array = memberList
            UserDefaults.standard.set(array, forKey: "memberList")
            
            //返回上一页
            navigationController?.popViewController(animated: true)


重新编辑卡片信息

是编辑还是新增,是靠itemDic来控制的

    //下面是进来编辑的
    var itemDic = [String:String]()

如果进页面时itemDic已经被赋值,证明是编辑

###tableView的代理cellForRowAt中,如果itemDic有内容,则显示itemDic内容
        if itemDic.count > 0
        {
            if indexPath.row == 0
            {
                cell.inputTextField.text = itemDic["memberName"]
                memberName = itemDic["memberName"]!
            }
            else if indexPath.row == 1
            {
                cell.inputTextField.text = itemDic["memberNum"]
                memberNum = itemDic["memberNum"]!
            }
            else
            {
                cell.inputTextField.text = itemDic["memberPassWord"]
                memberPassWord = itemDic["memberPassWord"]!
            }
        }

###tableView的头部显示代理viewForHeaderInSection中,如果itemDic有内容,则显示itemDic内容,此时需要拼接上"rootPath + "/Documents/Member""的路径
        if itemDic.count > 0
        {
            let frontImagePath = "\(Tools().getDocumentsMemberFile())/\((itemDic["frontPhoto"])!)"
            frontBtn.setImage(UIImage(named:frontImagePath), for: UIControlState.normal)
            let backImagePath = "\(Tools().getDocumentsMemberFile())/\((itemDic["backPhoto"])!)"
            backBtn.setImage(UIImage(named:backImagePath), for: UIControlState.normal)
            frontPhoto = itemDic["frontPhoto"]!
            backPhoto = itemDic["backPhoto"]!
        }

###保存的时候,如果itemDic有内容,则
            if itemDic.count > 0
            {
                let index = memberList.index(of: itemDic)
                memberList.remove(itemDic)
                memberList.insert(dic, at: index)
            }

卡片列表

  • tableView的行数由dataMutableArray的长度决定,但如果dataMutableArray长度为0,则显示背景图
###背景图
    //MARK: - 懒加载
    private lazy var tvBackgroundView: UIView =
    {
        let view = UIView()
        view.backgroundColor = UIColor.white
        let btn = UIButton()
        btn.frame = CGRect(x: ScreenWidth / 2 - 100, y: ScreenHeight / 2 - 25, width: 200, height: 50)
        btn.setTitle("点击添加第一张银行卡", for: UIControlState.normal)
        btn.setTitleColor(UIColor.darkGray, for: UIControlState.normal)
        btn.layer.borderColor = UIColor.hexStringToColor(hexString: ColorOfWaveBlueColor).cgColor
        btn.layer.borderWidth = 2
        btn.layer.cornerRadius = 8
        btn.layer.masksToBounds = true
        btn.addTarget(self, action:#selector(addMemberCardButtonAction), for: UIControlEvents.touchUpInside)
        view.addSubview(btn)
        return view
    }()

###每次进入页面的时候均判断数组长度
    override func viewWillAppear(_ animated: Bool)
    {
        super.viewWillAppear(true)
        print("保存本地的是\(String(describing: UserDefaults.standard.value(forKey: "memberList")))")
        //初始化,没有nil判空会崩溃
        if UserDefaults.standard.value(forKey: "memberList") != nil
        {
            let array = UserDefaults.standard.value(forKey: "memberList") as! NSArray
            dataMutableArray.removeAllObjects()
            let num = array.count
            for i in 0..<num
            {
                dataMutableArray.add(array[i])
            }
        }
        
        if dataMutableArray.count == 0
        {
            tableView?.backgroundView = tvBackgroundView
        }
        else
        {
            tableView?.backgroundView = nil
        }
        tableView.reloadData()
    }

###显示tableView内容
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        
        let identifier = "identtifier";
        
        let cell = memberCardCommonCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: identifier)
        cell.accessoryType=UITableViewCellAccessoryType.disclosureIndicator
        
        let item = dataMutableArray[indexPath.row] as! NSDictionary
        //因为字典里存的是绝对路径,需要再拼上相对路径
        let imagePath = "\(Tools().getDocumentsMemberFile())/\((item["frontPhoto"] as? String)!)"
        cell.frontImageView.image = UIImage(named:imagePath)
        cell.nameLabel.text = item["memberName"] as? String
        cell.numLabel.text = item["memberNum"] as? String
        
        return cell
        
    }
    


  • 编辑
###点击编辑按钮进入编辑状态
    func editMemberCardButtonAction()
    {
        if tableView.isEditing
        {
            tableView.isEditing = false
        }
        else
        {
            tableView.isEditing = true
        }
    }

###左滑删除
    //左滑删除
    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
    {
        //删除
        if editingStyle == UITableViewCellEditingStyle.delete
        {
            dataMutableArray.removeObject(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.fade)
            
            let array = dataMutableArray
            UserDefaults.standard.set(array, forKey: "memberList")
            
            if dataMutableArray.count == 0
            {
                tableView.backgroundView = tvBackgroundView
            }
            
        }
    }

###列表项的移动
    //编辑状态下的移动
    override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)
    {
        
        if sourceIndexPath != destinationIndexPath
        {
            let moveItem = dataMutableArray[sourceIndexPath.row]
            dataMutableArray.removeObject(at: sourceIndexPath.row)
            dataMutableArray.insert(moveItem, at: destinationIndexPath.row)
  
            let array = dataMutableArray
            UserDefaults.standard.set(array, forKey: "memberList")
        }
    }

###点击cell进入编辑页
    //点击
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
    {
        
        tableView.deselectRow(at: indexPath, animated: true)
        let vc = AddCardViewController()
        vc.itemDic = (dataMutableArray[indexPath.row] as! NSDictionary) as! [String : String]
        self.navigationController?.pushViewController(vc, animated: true)
        
    }

    

Demo地址
https://github.com/CarolineQian/FQAddCardDemo

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

推荐阅读更多精彩内容