如何在IPhone sdk中使用Objective C创建一个像whatsapp一样的录音按钮,可以滑动取消



我想使用objective c创建WhatsApp在iPhone上推出一键式语音消息功能。

首先,这是一个非常基本的例子。所以无论谁想用这个,都需要做更多的事情。如果有人需要它在Swift 3.x

import UIKit
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: "record")!, 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 = "Slide to cancel <"
        delegate?.SPKRecordViewDidSelectRecord(sender: self, button: sender)
        
    }
    
    func userDidTapRecord(_ sender: UIGestureRecognizer) {
        
        print("Long Tap")
        
        let button = sender.view as! UIButton
        
        let location = sender.location(in: button)
        
        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)
            
            if !button.bounds.contains(translate) {
                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)
            
            if !button.frame.contains(translate) {
                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 ViewController : SPKRecordViewDelegate {
    
    func SPKRecordViewDidCancelRecord(sender: SPKRecordView, button: UIView) {
        
        sender.state = .None
        
        print("Cancelled")
    }
    
    func SPKRecordViewDidSelectRecord(sender: SPKRecordView, button: UIView) {
        
        sender.state = .Recording
        
        print("Began " + NSUUID().uuidString)
        
    }
    
    func SPKRecordViewDidStopRecord(sender : SPKRecordView, button: UIView) {
        
        sender.state = .None
        
        print("Done")
    }
}

用法:

import UIKit
let rec = SPKRecordView(frame: CGRect.zero)
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        rec.delegate = self
        view.addSubview(rec)
        
        let hConsts = NSLayoutConstraint.constraints(withVisualFormat: "H:[bt]-(100)-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["bt":rec])
        view.addConstraints(hConsts)
        
        let vConsts = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(100)-[bt]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["bt":rec])
        view.addConstraints(vConsts)
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

这类似于Whatsapp的记录行为,只是为了好玩,但它是用Swift 2.1编写的

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.animateWithDuration(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: CGRectZero)
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.constraintsWithVisualFormat("H:[recordButton]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["recordButton":recordButton])
    self.addConstraints(hConsts)
    let vConsts = NSLayoutConstraint.constraintsWithVisualFormat("V:|[recordButton]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["recordButton":recordButton])
    self.addConstraints(vConsts)
    recordButton.setImage(UIImage(named: "record")!, forState: .Normal)
    let longPress = UILongPressGestureRecognizer(target: self, action: "userDidTapRecord:")
    longPress.cancelsTouchesInView = false
    longPress.allowableMovement = 10
    longPress.minimumPressDuration = 0.2
    recordButton.addGestureRecognizer(longPress)
}
func setupLabel() {
    slideToCancel.translatesAutoresizingMaskIntoConstraints = false
    addSubview(slideToCancel)
    backgroundColor = UIColor.clearColor()
    let hConsts = NSLayoutConstraint.constraintsWithVisualFormat("H:|[slideToCancel][bt]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["slideToCancel":slideToCancel,"bt":recordButton])
    self.addConstraints(hConsts)
    let vConsts = NSLayoutConstraint.constraintsWithVisualFormat("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.blackColor()
}
override func intrinsicContentSize() -> CGSize {
    if state == .None {
        return recordButton.intrinsicContentSize()
    } else {
        return CGSizeMake(recordButton.intrinsicContentSize().width * 3, recordButton.intrinsicContentSize().height)
    }
}
func userDidTapRecordThenSwipe(sender: UIButton) {
    slideToCancel.text = nil
    delegate?.SPKRecordViewDidCancelRecord(self, button: sender)
}
func userDidStopRecording(sender: UIButton) {
    slideToCancel.text = nil
    delegate?.SPKRecordViewDidStopRecord(self, button: sender)
}
func userDidBeginRecord(sender : UIButton) {
    slideToCancel.text = "Slide to cancel <"
    delegate?.SPKRecordViewDidSelectRecord(self, button: sender)
}
func userDidTapRecord(gesture: UIGestureRecognizer) {
    let button = gesture.view as! UIButton
    let location = gesture.locationInView(button)
    var startLocation = CGPointZero
    switch gesture.state {
    case .Began:
            startLocation = location
            userDidBeginRecord(button)
    case .Changed:
        let translate = CGPoint(x: location.x - startLocation.x, y: location.y - startLocation.y)
        if !CGRectContainsPoint(button.bounds, translate) {
            if state == .Recording {
                userDidTapRecordThenSwipe(button)
            }
        }
    case .Ended:
        if state == .None { return }
        let translate = CGPoint(x: location.x - startLocation.x, y: location.y - startLocation.y)
        if !CGRectContainsPoint(button.frame, translate) {
            userDidStopRecording(button)
        }
    case .Failed, .Possible ,.Cancelled : if state == .Recording { userDidStopRecording(button) } else { userDidTapRecordThenSwipe(button)}
    }

}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}
extension ViewController : SPKRecordViewDelegate {
func SPKRecordViewDidCancelRecord(sender: SPKRecordView, button: UIView) {
    sender.state = .None
    print("Cancelled")
}
func SPKRecordViewDidSelectRecord(sender: SPKRecordView, button: UIView) {
    sender.state = .Recording
    print("Began " + NSUUID().UUIDString)
}
func SPKRecordViewDidStopRecord(sender : SPKRecordView, button: UIView) {
    sender.state = .None
    print("Done")
}
}

用法:

class HomeViewController: UIViewController {

let rec = SPKRecordView(frame: CGRectZero)
override func viewDidLoad() {
    super.viewDidLoad()
    rec.delegate = self
    view.addSubview(rec)
    let hConsts = NSLayoutConstraint.constraintsWithVisualFormat("H:[bt]-(100)-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["bt":rec])
    view.addConstraints(hConsts)
    let vConsts = NSLayoutConstraint.constraintsWithVisualFormat("V:|-(100)-[bt]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["bt":rec])
    view.addConstraints(vConsts)
}
}

最新更新