iosswiftvoice-recordingio-socket

Canceling a Voice Note Like WhatsApp Swift


I hope you all are doing well. I am working on a chat module in which I can record a voice memo/note. My recording a voice function runs fine but I want to add a swipe gesture like WhatsApp. I want to stop recording while swiping right while holding the button. i am looking for something like this:

Video of WhatsApp

thanks


Solution

  • I have figured it out myself. By the following code you can record a voice memo and can cancel it by swiping

    I have used this code to achieve what I want to do.

    protocol SPKRecordViewDelegate: class {
    
        func SPKRecordViewDidSelectRecord(sender : SPKRecordView, button: UIView)
        func SPKRecordViewDidStopRecord(sender : SPKRecordView, button: UIView)
        func SPKRecordViewDidCancelRecord(sender : SPKRecordView, button: UIView)
    
    }
    
    class SPKRecordView: UIView {
    
        enum SPKRecordViewState {
    
            case Recording
            case None
    
        }
    
        var state : SPKRecordViewState = .None {
    
            didSet {
    
                UIView.animate(withDuration: 0.3) { () -> Void in
    
                    self.slideToCancel.alpha = 1.0
                    self.invalidateIntrinsicContentSize()
                    self.setNeedsLayout()
                    self.layoutIfNeeded()
    
                }
    
            }
        }
    
        let recordButton : UIButton = UIButton(type: .custom)
        let slideToCancel : UILabel = UILabel(frame: CGRect.zero)
    
        weak var delegate : SPKRecordViewDelegate?
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            self.translatesAutoresizingMaskIntoConstraints = false
    
            setupRecordButton()
            setupLabel()
        }
    
        func setupRecordButton() {
    
            recordButton.translatesAutoresizingMaskIntoConstraints = false
            addSubview(recordButton)
            let hConsts = NSLayoutConstraint.constraints(withVisualFormat: "H:[recordButton]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["recordButton":recordButton])
            self.addConstraints(hConsts)
    
            let vConsts = NSLayoutConstraint.constraints(withVisualFormat: "V:|[recordButton]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["recordButton":recordButton])
            self.addConstraints(vConsts)
    
            recordButton.setImage(UIImage(named: "mike")!, for: .normal)
            let longPress = UILongPressGestureRecognizer(target: self, action: #selector(userDidTapRecord(_:)))
            longPress.cancelsTouchesInView = false
            longPress.allowableMovement = 10
            longPress.minimumPressDuration = 0.2
            recordButton.addGestureRecognizer(longPress)
    
        }
    
        func setupLabel() {
    
            slideToCancel.translatesAutoresizingMaskIntoConstraints = false
            addSubview(slideToCancel)
            backgroundColor = UIColor.clear
    
            let hConsts = NSLayoutConstraint.constraints(withVisualFormat: "H:|[slideToCancel][bt]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["slideToCancel":slideToCancel,"bt":recordButton])
            self.addConstraints(hConsts)
    
            let vConsts = NSLayoutConstraint.constraints(withVisualFormat: "V:|[slideToCancel]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["slideToCancel":slideToCancel])
            self.addConstraints(vConsts)
    
            slideToCancel.alpha = 0.0
            slideToCancel.font = UIFont(name: "Lato-Bold", size: 17)
            slideToCancel.textAlignment = .center
            slideToCancel.textColor = UIColor.black
        }
    
    
        override public var intrinsicContentSize: CGSize {
            if state == .none {
                return recordButton.intrinsicContentSize
            } else {
    
                return CGSize(width: recordButton.intrinsicContentSize.width * 3, height: recordButton.intrinsicContentSize.height)
            }
        }
    
        func userDidTapRecordThenSwipe(sender: UIButton) {
            slideToCancel.text = nil
            delegate?.SPKRecordViewDidCancelRecord(sender: self, button: sender)
    
    
        }
    
        func userDidStopRecording(sender: UIButton) {
            slideToCancel.text = nil
            delegate?.SPKRecordViewDidStopRecord(sender: self, button: sender)
        }
    
        func userDidBeginRecord(sender : UIButton) {
            slideToCancel.text = "check"
            delegate?.SPKRecordViewDidSelectRecord(sender: self, button: sender)
    
        }
    
        @objc func userDidTapRecord(_ sender: UIGestureRecognizer) {
    
            print("Long Tap")
    
            let button = sender.view as! UIButton
    
            let location = sender.location(in: button)
    
            print("Swipe location",location.x)
    
    
            var startLocation = CGPoint.zero
    
            switch sender.state {
    
            case .began:
                startLocation = location
                userDidBeginRecord(sender: button)
            case .changed:
    
                let translate = CGPoint(x: location.x - startLocation.x, y: location.y - startLocation.y)
                print("Swipe location new", translate)
                if translate.x <= -150 {
    
                    if state == .Recording {
                        userDidTapRecordThenSwipe(sender: button)
                    }
                }
    
            case .ended:
    
                if state == .None { return }
    
                let translate = CGPoint(x: location.x - startLocation.x, y: location.y - startLocation.y)
    
    
    
                    userDidStopRecording(sender: button)
    
    
    
            case .failed, .possible ,.cancelled :
    
                if state == .Recording {
                    userDidStopRecording(sender: button)
                }
                else {
                    userDidTapRecordThenSwipe(sender: button)
                }
            }
    
    
        }
    
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }
    
    extension IndividualChatViewController : SPKRecordViewDelegate {
    
    
    
        func SPKRecordViewDidCancelRecord(sender: SPKRecordView, button: UIView) {
            UIView.animate(withDuration: 2.0) {
                  sender.state = .None
                      self.audioRecorder.stop()
                      self.customView.slideView.isHidden = true
                      self.CountTimer?.invalidate()
                      self.counter = 0
                      self.customView.timeCountLabel.text = "00:00"
                      self.CountTimer = nil
            }
    
        }
    
        func SPKRecordViewDidSelectRecord(sender: SPKRecordView, button: UIView) {
            sender.state = .Recording
            self.startRecordingVoice()
    
    
    
        }
    
        func SPKRecordViewDidStopRecord(sender : SPKRecordView, button: UIView) {
    
            sender.state = .None
            self.sendRecording()
            print("Done")
        }
    }
    

    then call a global variable

    let myrecording = SPKRecordView(frame: CGRect.zero)
    

    Call delegate method

     myrecording.delegate = self
            self.customView.recordButton.addSubview(rec)
    
                let hConsts = NSLayoutConstraint.constraints(withVisualFormat: "H:[bt(30)]-(5)-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["bt":rec])
                view.addConstraints(hConsts)
    
                let vConsts = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(5)-[bt(30)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["bt":rec])
                view.addConstraints(vConsts)
            rec.recordButton.addTarget(self, action: #selector(stopRecording(_:)), for: .touchDragExit)
    

    add touchDragExit function

    @objc func stopRecording(_ sender : UIButton)
    {
    
    
        self.audioRecorder.stop()
        self.recordingView.isHidden = true
    
        // Simply set the amplitude to whatever you need and the view will update itself.
    
    }