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:
thanks
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.
}