我想允许通过 1.5 秒长按开始直播,但我的代码要求用户在整个直播过程中按住按钮
I want to allow a live stream to be started by a 1.5 second long tap, but my code requires users to hold down the button the entire stream
我需要允许用户通过按住 additionalCameraButton 约 1.5 秒来开始向他们的朋友直播视频。然而目前他们必须一直按住它,当他们将手指从 additionalCameraButton 上移开时,cameraView 将被取消。
我正在使用某人的旧代码,我刚刚从 Swift 2.2 转换为 Swift 3,我看到他们做了什么,但是当我稍微改变它以获得 minimumDuration longTap 手势,出现致命错误。
你们中的任何人会如何改变代码以允许 1.5 秒的长按,而不是必须无限期地按住它?在第 58 行,我有为 longTap 添加 minimumDuration 的代码,但是添加它会导致各种错误,因为松开按钮后,即使直播已经开始,cameraView 仍然被取消。
import UIKit
import AVFoundation
protocol CameraViewDelegate {
func startStopRecordingVideo(_ isStart: Bool)
func startStopStream(_ isStart: Bool)
func cancelCameraView()
func changeCamera()
func chooseVideo()
}
class CameraView: UIView, UIGestureRecognizerDelegate {
@IBOutlet weak var flashBtn: UIButton!
@IBOutlet weak var screenView: UIView!
@IBOutlet weak var shootBtn: UIButton!
@IBOutlet weak var changeCameraBtn: UIButton!
@IBOutlet weak var cancelBtn: UIButton!
@IBOutlet weak var alphaView: UIView!
@IBOutlet weak var shootBtnContainerView: UIView!
var delegate : CameraViewDelegate?
var isRecording : Bool = false
var isStreaming: Bool = false
var circleLayer: CAShapeLayer?
var timer: Timer?
//MARK: SYSTEMS METHODS
class func instanceFromNib() -> CameraView {
return UINib(nibName: "View", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! CameraView
}
override func awakeFromNib() {
layoutIfNeeded()
shootBtnContainerView.layer.cornerRadius = shootBtnContainerView.frame.size.width/2
shootBtn.layer.cornerRadius = shootBtn.frame.size.width/2
let tap = UITapGestureRecognizer(target: self, action: #selector(doubleTapped))
tap.numberOfTapsRequired = 2
shootBtn.addGestureRecognizer(tap)
let hideTap = UITapGestureRecognizer(target: self, action: #selector(hideTapped))
hideTap.delegate = self
alphaView.addGestureRecognizer(hideTap)
let hold = UILongPressGestureRecognizer(target: self, action: #selector(longTap))
shootBtn.addGestureRecognizer(hold)
//hold.minimumPressDuration = 1.5
if Defaults.sharedDefaults.userKnowAboutCamera {
alphaView.isHidden = true
}
let alert = UIAlertController(title: "Testing!", message: nil, preferredStyle: .alert)
let action = UIAlertAction(title: "Thank You", style: .default, handler: nil)
alert.addAction(action)
}
//MARK: - CIRcLE ANIMATION
func createCirclePath() {
let circlePath = UIBezierPath(arcCenter: shootBtnContainerView.center, radius: shootBtnContainerView.frame.size.width/2, startAngle: 0.0, endAngle: CGFloat(.pi * 2.0), clockwise: true)
circleLayer = CAShapeLayer()
circleLayer!.path = circlePath.cgPath
circleLayer!.fillColor = UIColor.clear.cgColor
circleLayer!.strokeColor = UIColor.red.cgColor
circleLayer!.lineWidth = 3.0;
circleLayer!.strokeEnd = 0.0
layer.addSublayer(circleLayer!)
}
func animateCircle(_ duration: TimeInterval) {
circleLayer?.removeFromSuperlayer()
createCirclePath()
circleLayer!.strokeEnd = 0.0
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.duration = duration
animation.fromValue = 0
animation.toValue = 1
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
circleLayer!.strokeEnd = 1.0
circleLayer!.add(animation, forKey: "animateCircle")
}
// SHOW HIDE ALPHA VIEW
func showHideAlphaView(_ isHide: Bool){
Defaults.sharedDefaults.userKnowAboutCamera = true
var alpha: Float = 0.0
if isHide { alpha = 0.0 } else { alpha = 0.6 }
UIView.animate(withDuration: 1.5, animations: {
self.alphaView.alpha = CGFloat(alpha)
}, completion: nil)
}
// ACTIONS
func hideTapped(){
showHideAlphaView(true)
}
func doubleTapped() {
delegate?.chooseVideo()
}
func longTap(_ sender: UILongPressGestureRecognizer) {
print("tapping")
if sender.state == .began {
SSContact.shared.isStreaming(public: true, to: nil, verification: { (error) in
if error != nil {
print(error!.localizedDescription)
}
}, live: { (live, views) in
print("Live: \(live) :: With \(views) Views!")
})
isRecording = !isRecording
delegate?.startStopRecordingVideo(isRecording)
isStreaming = !isStreaming
delegate?.startStopStream(isStreaming)
} else if sender.state == .ended {
SSContact.shared.stopStreaming()
isRecording = !isRecording
delegate?.startStopRecordingVideo(isRecording)
isStreaming = !isStreaming
delegate?.startStopStream(isStreaming)
delegate?.cancelCameraView()
}
}
func updateTimer() {
isRecording = !isRecording
delegate?.startStopRecordingVideo(isRecording)
timer?.invalidate()
}
@IBAction func shootVideo(_ sender: AnyObject) {
if !isRecording{
timer = Timer.scheduledTimer(timeInterval: 20.0, target: self, selector: #selector(CameraView.updateTimer), userInfo: nil, repeats: true)
animateCircle(20)
} else {
timer?.invalidate()
circleLayer?.removeAnimation(forKey: "animateCircle")
circleLayer!.strokeEnd = 0.0
}
isRecording = !isRecording
delegate?.startStopRecordingVideo(isRecording)
}
@IBAction func cancelPressed(_ sender: AnyObject) {
delegate?.cancelCameraView()
}
@IBAction func changeCameraPressed(_ sender: AnyObject) {
delegate?.changeCamera()
}
@IBAction func flashBtnPressed(_ sender: AnyObject) {
let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)!
if (device.hasTorch) {
do {
try device.lockForConfiguration()
if device.torchMode == .on {
device.torchMode = .off
flashBtn.setImage(UIImage(named: "Flash"), for: UIControlState())
} else {
flashBtn.setImage(UIImage(named: "NoFlash"), for: UIControlState())
do {
try device.setTorchModeOnWithLevel(1.0)
} catch {
print(error.localizedDescription)
}
}
device.unlockForConfiguration()
} catch {
print(error.localizedDescription)
}
}
}
@IBAction func loadVideoPressed(_ sender: AnyObject) {
}
}
你的 UILongPressGestureRegonizer
的目标是 longTap(_:)
。只要手势识别器触发事件,就会执行此方法。让我们看看你对这个方法的实现:
func longTap(_ sender: UILongPressGestureRecognizer) {
print("tapping")
if sender.state == .began {
// ...
delegate?.startStopStream(isStreaming)
} else if sender.state == .ended {
SSContact.shared.stopStreaming()
// ...
}
}
我用 // ...
替换了一些代码以专注于这里的重要内容。如您所见,一个 UILongPressGestureReconizer
可以有多个状态(另请参阅 API Reference)。在您的代码中,您正在处理其中两个:.began
和 .ended
。
一旦您的手势被识别(即用户已执行长按),手势识别器状态将为 .began
。在这个 if
分支中,您将开始您的摄像机录制以及您的直播。另一方面,在您的 .ended
分支中,您正在停止流。当手势结束时(即当用户抬起手指时,长按现在已经结束),状态将为 .ended
。
如果您希望在长按后继续播放,只需删除 .ended
分支即可。
看看 UILongPressGestureRecognizer
的 longTap
方法,你说 if sender.state == .ended
基本上停止流式传输,所以只要用户释放触摸它就会停止:
func longTap(_ sender: UILongPressGestureRecognizer) {
if sender.state == .began {
// Start the stream
} else if sender.state == .ended {
SSContact.shared.stopStreaming()
isRecording = !isRecording
delegate?.startStopRecordingVideo(isRecording)
isStreaming = !isStreaming
delegate?.startStopStream(isStreaming)
delegate?.cancelCameraView()
}
}
我建议也许有一种方法可以根据您的 isRecording
布尔值来管理启动和停止流,并更改声明 isRecording
的方式以使用 didSet
:
var isRecording: Bool = false {
didSet{
// Manage the stream based on how the variable is set
self.manageStream(start: isRecording)
}
}
func manageStream(start: Bool) {
if start {
// Start the stream
SSContact.shared.isStreaming(public: true, to: nil, verification: { (error) in
if error != nil {
print(error!.localizedDescription)
}
}, live: { (live, views) in
print("Live: \(live) :: With \(views) Views!")
})
isRecording = !isRecording
delegate?.startStopRecordingVideo(isRecording)
isStreaming = !isStreaming
delegate?.startStopStream(isStreaming)
}
else {
// Stop the stream
SSContact.shared.stopStreaming()
isRecording = !isRecording
delegate?.startStopRecordingVideo(isRecording)
isStreaming = !isStreaming
delegate?.startStopStream(isStreaming)
delegate?.cancelCameraView()
}
}
现在您可以使用 longPress 识别器开始和停止流式传输:
func longTap(_ sender: UILongPressGestureRecognizer) {
isRecording = !isRecording
}
您甚至可以更改按下的持续时间,比如您希望最短按下持续时间更短以关闭流而不是打开它:
func longTap(_ sender: UILongPressGestureRecognizer) {
isRecording = !isRecording
if isRecording {
// Make the minimum duration zero so they just need to tap to turn it off
sender.minimumPressDuration = 0
} else {
// Make the minimum duration back to 1.5 seconds so they have to hold to turn it on
sender.minimumPressDuration = 1.5
}
}
我需要允许用户通过按住 additionalCameraButton 约 1.5 秒来开始向他们的朋友直播视频。然而目前他们必须一直按住它,当他们将手指从 additionalCameraButton 上移开时,cameraView 将被取消。
我正在使用某人的旧代码,我刚刚从 Swift 2.2 转换为 Swift 3,我看到他们做了什么,但是当我稍微改变它以获得 minimumDuration longTap 手势,出现致命错误。
你们中的任何人会如何改变代码以允许 1.5 秒的长按,而不是必须无限期地按住它?在第 58 行,我有为 longTap 添加 minimumDuration 的代码,但是添加它会导致各种错误,因为松开按钮后,即使直播已经开始,cameraView 仍然被取消。
import UIKit
import AVFoundation
protocol CameraViewDelegate {
func startStopRecordingVideo(_ isStart: Bool)
func startStopStream(_ isStart: Bool)
func cancelCameraView()
func changeCamera()
func chooseVideo()
}
class CameraView: UIView, UIGestureRecognizerDelegate {
@IBOutlet weak var flashBtn: UIButton!
@IBOutlet weak var screenView: UIView!
@IBOutlet weak var shootBtn: UIButton!
@IBOutlet weak var changeCameraBtn: UIButton!
@IBOutlet weak var cancelBtn: UIButton!
@IBOutlet weak var alphaView: UIView!
@IBOutlet weak var shootBtnContainerView: UIView!
var delegate : CameraViewDelegate?
var isRecording : Bool = false
var isStreaming: Bool = false
var circleLayer: CAShapeLayer?
var timer: Timer?
//MARK: SYSTEMS METHODS
class func instanceFromNib() -> CameraView {
return UINib(nibName: "View", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! CameraView
}
override func awakeFromNib() {
layoutIfNeeded()
shootBtnContainerView.layer.cornerRadius = shootBtnContainerView.frame.size.width/2
shootBtn.layer.cornerRadius = shootBtn.frame.size.width/2
let tap = UITapGestureRecognizer(target: self, action: #selector(doubleTapped))
tap.numberOfTapsRequired = 2
shootBtn.addGestureRecognizer(tap)
let hideTap = UITapGestureRecognizer(target: self, action: #selector(hideTapped))
hideTap.delegate = self
alphaView.addGestureRecognizer(hideTap)
let hold = UILongPressGestureRecognizer(target: self, action: #selector(longTap))
shootBtn.addGestureRecognizer(hold)
//hold.minimumPressDuration = 1.5
if Defaults.sharedDefaults.userKnowAboutCamera {
alphaView.isHidden = true
}
let alert = UIAlertController(title: "Testing!", message: nil, preferredStyle: .alert)
let action = UIAlertAction(title: "Thank You", style: .default, handler: nil)
alert.addAction(action)
}
//MARK: - CIRcLE ANIMATION
func createCirclePath() {
let circlePath = UIBezierPath(arcCenter: shootBtnContainerView.center, radius: shootBtnContainerView.frame.size.width/2, startAngle: 0.0, endAngle: CGFloat(.pi * 2.0), clockwise: true)
circleLayer = CAShapeLayer()
circleLayer!.path = circlePath.cgPath
circleLayer!.fillColor = UIColor.clear.cgColor
circleLayer!.strokeColor = UIColor.red.cgColor
circleLayer!.lineWidth = 3.0;
circleLayer!.strokeEnd = 0.0
layer.addSublayer(circleLayer!)
}
func animateCircle(_ duration: TimeInterval) {
circleLayer?.removeFromSuperlayer()
createCirclePath()
circleLayer!.strokeEnd = 0.0
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.duration = duration
animation.fromValue = 0
animation.toValue = 1
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
circleLayer!.strokeEnd = 1.0
circleLayer!.add(animation, forKey: "animateCircle")
}
// SHOW HIDE ALPHA VIEW
func showHideAlphaView(_ isHide: Bool){
Defaults.sharedDefaults.userKnowAboutCamera = true
var alpha: Float = 0.0
if isHide { alpha = 0.0 } else { alpha = 0.6 }
UIView.animate(withDuration: 1.5, animations: {
self.alphaView.alpha = CGFloat(alpha)
}, completion: nil)
}
// ACTIONS
func hideTapped(){
showHideAlphaView(true)
}
func doubleTapped() {
delegate?.chooseVideo()
}
func longTap(_ sender: UILongPressGestureRecognizer) {
print("tapping")
if sender.state == .began {
SSContact.shared.isStreaming(public: true, to: nil, verification: { (error) in
if error != nil {
print(error!.localizedDescription)
}
}, live: { (live, views) in
print("Live: \(live) :: With \(views) Views!")
})
isRecording = !isRecording
delegate?.startStopRecordingVideo(isRecording)
isStreaming = !isStreaming
delegate?.startStopStream(isStreaming)
} else if sender.state == .ended {
SSContact.shared.stopStreaming()
isRecording = !isRecording
delegate?.startStopRecordingVideo(isRecording)
isStreaming = !isStreaming
delegate?.startStopStream(isStreaming)
delegate?.cancelCameraView()
}
}
func updateTimer() {
isRecording = !isRecording
delegate?.startStopRecordingVideo(isRecording)
timer?.invalidate()
}
@IBAction func shootVideo(_ sender: AnyObject) {
if !isRecording{
timer = Timer.scheduledTimer(timeInterval: 20.0, target: self, selector: #selector(CameraView.updateTimer), userInfo: nil, repeats: true)
animateCircle(20)
} else {
timer?.invalidate()
circleLayer?.removeAnimation(forKey: "animateCircle")
circleLayer!.strokeEnd = 0.0
}
isRecording = !isRecording
delegate?.startStopRecordingVideo(isRecording)
}
@IBAction func cancelPressed(_ sender: AnyObject) {
delegate?.cancelCameraView()
}
@IBAction func changeCameraPressed(_ sender: AnyObject) {
delegate?.changeCamera()
}
@IBAction func flashBtnPressed(_ sender: AnyObject) {
let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)!
if (device.hasTorch) {
do {
try device.lockForConfiguration()
if device.torchMode == .on {
device.torchMode = .off
flashBtn.setImage(UIImage(named: "Flash"), for: UIControlState())
} else {
flashBtn.setImage(UIImage(named: "NoFlash"), for: UIControlState())
do {
try device.setTorchModeOnWithLevel(1.0)
} catch {
print(error.localizedDescription)
}
}
device.unlockForConfiguration()
} catch {
print(error.localizedDescription)
}
}
}
@IBAction func loadVideoPressed(_ sender: AnyObject) {
}
}
你的 UILongPressGestureRegonizer
的目标是 longTap(_:)
。只要手势识别器触发事件,就会执行此方法。让我们看看你对这个方法的实现:
func longTap(_ sender: UILongPressGestureRecognizer) {
print("tapping")
if sender.state == .began {
// ...
delegate?.startStopStream(isStreaming)
} else if sender.state == .ended {
SSContact.shared.stopStreaming()
// ...
}
}
我用 // ...
替换了一些代码以专注于这里的重要内容。如您所见,一个 UILongPressGestureReconizer
可以有多个状态(另请参阅 API Reference)。在您的代码中,您正在处理其中两个:.began
和 .ended
。
一旦您的手势被识别(即用户已执行长按),手势识别器状态将为 .began
。在这个 if
分支中,您将开始您的摄像机录制以及您的直播。另一方面,在您的 .ended
分支中,您正在停止流。当手势结束时(即当用户抬起手指时,长按现在已经结束),状态将为 .ended
。
如果您希望在长按后继续播放,只需删除 .ended
分支即可。
看看 UILongPressGestureRecognizer
的 longTap
方法,你说 if sender.state == .ended
基本上停止流式传输,所以只要用户释放触摸它就会停止:
func longTap(_ sender: UILongPressGestureRecognizer) {
if sender.state == .began {
// Start the stream
} else if sender.state == .ended {
SSContact.shared.stopStreaming()
isRecording = !isRecording
delegate?.startStopRecordingVideo(isRecording)
isStreaming = !isStreaming
delegate?.startStopStream(isStreaming)
delegate?.cancelCameraView()
}
}
我建议也许有一种方法可以根据您的 isRecording
布尔值来管理启动和停止流,并更改声明 isRecording
的方式以使用 didSet
:
var isRecording: Bool = false {
didSet{
// Manage the stream based on how the variable is set
self.manageStream(start: isRecording)
}
}
func manageStream(start: Bool) {
if start {
// Start the stream
SSContact.shared.isStreaming(public: true, to: nil, verification: { (error) in
if error != nil {
print(error!.localizedDescription)
}
}, live: { (live, views) in
print("Live: \(live) :: With \(views) Views!")
})
isRecording = !isRecording
delegate?.startStopRecordingVideo(isRecording)
isStreaming = !isStreaming
delegate?.startStopStream(isStreaming)
}
else {
// Stop the stream
SSContact.shared.stopStreaming()
isRecording = !isRecording
delegate?.startStopRecordingVideo(isRecording)
isStreaming = !isStreaming
delegate?.startStopStream(isStreaming)
delegate?.cancelCameraView()
}
}
现在您可以使用 longPress 识别器开始和停止流式传输:
func longTap(_ sender: UILongPressGestureRecognizer) {
isRecording = !isRecording
}
您甚至可以更改按下的持续时间,比如您希望最短按下持续时间更短以关闭流而不是打开它:
func longTap(_ sender: UILongPressGestureRecognizer) {
isRecording = !isRecording
if isRecording {
// Make the minimum duration zero so they just need to tap to turn it off
sender.minimumPressDuration = 0
} else {
// Make the minimum duration back to 1.5 seconds so they have to hold to turn it on
sender.minimumPressDuration = 1.5
}
}