在 Swift 中创建可重用视图并添加完成处理程序
Posted
技术标签:
【中文标题】在 Swift 中创建可重用视图并添加完成处理程序【英文标题】:Creating reusable View in Swift and adding a completion handler 【发布时间】:2019-02-11 15:43:09 【问题描述】:我创建了一个 sliderView,并添加了一个 UIPanGesture,我创建了一个单独的 UIView 来处理这个滑块。我希望能够在需要它的不同 ViewController 中调用此 SliderView,但是当我尝试运行我的代码时它崩溃了。我还想传递一个完成处理程序来处理我需要它的 ViewCONtrollers 中的事件。我试图通过创建一个 UIView 并在多个屏幕中使用它来遵循 DRY 过程。以下是我目前的代码
class TripView: UIView
var shouldSetupConstraints = true
var startingFrame: CGRect?
var sliderView: UIView!
var sliderImage: UIImageView!
let screenSize = UIScreen.main.bounds
override init(frame: CGRect)
super.init(frame: frame)
swipeFunc()
sliderView = UIImageView(frame: CGRect.zero)
sliderView.backgroundColor = UIColor.green
sliderView.autoSetDimension(.height, toSize: screenSize.width / 6)
self.addSubview(sliderView)
sliderImage = UIImageView(frame: CGRect.zero)
sliderImage.backgroundColor = UIColor.clear
sliderImage.image = UIImage(named: "icons8-double_right_filled.png")
sliderImage.contentMode = .scaleAspectFit
sliderImage.autoSetDimension(.width, toSize: screenSize.width / 6)
sliderImage.autoSetDimension(.height, toSize: screenSize.width / 6)
self.addSubview(sliderImage)
required init?(coder aDecoder: NSCoder)
super.init(coder: aDecoder)
override func updateConstraints()
if(shouldSetupConstraints)
sliderView.autoPinEdgesToSuperviewSafeArea(with: UIEdgeInsets.zero, excludingEdge: .bottom)
sliderImage.autoPinEdge(toSuperviewEdge: .left)
sliderImage.autoPinEdge(.bottom, to: .bottom, of: sliderView, withOffset: 0.0)
shouldSetupConstraints = false
super.updateConstraints()
extension TripView
private func swipeFunc()
let swipeGesture = UIPanGestureRecognizer(target: self, action: #selector(acknowledgeSwiped(sender:)))
sliderImage.addGestureRecognizer(swipeGesture)
sliderImage.isUserInteractionEnabled = true
swipeGesture.delegate = self as? UIGestureRecognizerDelegate
@objc func acknowledgeSwiped(sender: UIPanGestureRecognizer)
if let sliderView = sender.view
let translation = sender.translation(in: sliderView)
switch sender.state
case .began:
startingFrame = sliderImage.frame
fallthrough
case .changed:
if let startFrame = startingFrame
var movex = translation.x
if movex < -startFrame.origin.x movex = -startFrame.origin.x
let xMax = sliderView.frame.width - startFrame.origin.x - startFrame.width
if movex > xMax
movex = xMax
// I WANT TO PASS A COMPLETION HANDLER HERE. TO BE ABLE TO HANDLE OTHER EVENTS IN VIEWCONTROLLERS
var movey = translation.y
if movey < -startFrame.origin.y movey = -startFrame.origin.y
let yMax = sliderView.frame.height - startFrame.origin.y - startFrame.height
if movey > yMax
movey = yMax
sliderView.transform = CGAffineTransform(translationX: movex, y: movey)
default: // .ended and others:
UIView.animate(withDuration: 0.1, animations:
sliderView.transform = CGAffineTransform.identity
)
【问题讨论】:
它在哪里崩溃了? 这里sliderImage.addGestureRecognizer(swipeGesture)
King,sliderImage.addGestureRecognizer(swipeGesture)
中的崩溃是由于 sliderImage
的 nil
值造成的。你在初始化对象时使用TripView(frame:)
方法吗?
【参考方案1】:
您可以将完成处理程序添加为内部变量,或在初始化程序中传递一个。
例如:
class TripView: UIView
typealias Callback = () -> ()
var callback: Callback
...
然后你想在哪里触发回调,只需调用:
callback()
或者你可以定义一个委托
protocol TripViewDelegate
func didDoSomething(for view: TripView)
class TripView: UIView
weak var tripViewDelegate: TripViewDelegate?
// ...
然后调用
tripViewDelegate?.didDoSomething(for: self)
【讨论】:
委托人不清楚。我在问题中指定了将要执行的操作放在另一个视图控制器中的位置 您的视图控制器应该符合TripViewDelegate
,然后您可以将您的视图控制器指定为TripView
的代理。有什么不清楚的地方?【参考方案2】:
您正在调用swipeFunc
,它在sliderImage
初始化之前访问sliderImage
。
您必须将 swipeFunc()
移动到您的 init
方法的末尾。
实际上,没有必要使用隐式展开的可选项。您可以使用非可选参数来防止崩溃:
let sliderView: UIView = UIImageView(frame: CGRect.zero)
let sliderImage: UIImageView = UIImageView(frame: CGRect.zero)
因为你实际上有两个初始化器,你可能应该在两个初始化器中都初始化:
let sliderView: UIView = UIImageView(frame: CGRect.zero)
let sliderImage: UIImageView = UIImageView(frame: CGRect.zero)
override init(frame: CGRect)
super.init(frame: frame)
commonInit()
required init?(coder aDecoder: NSCoder)
super.init(coder: aDecoder)
commonInit()
private func commonInit()
sliderView.backgroundColor = UIColor.green
sliderView.autoSetDimension(.height, toSize: screenSize.width / 6)
self.addSubview(sliderView)
sliderImage.backgroundColor = UIColor.clear
sliderImage.image = UIImage(named: "icons8-double_right_filled.png")
sliderImage.contentMode = .scaleAspectFit
sliderImage.autoSetDimension(.width, toSize: screenSize.width / 6)
sliderImage.autoSetDimension(.height, toSize: screenSize.width / 6)
self.addSubview(sliderImage)
swipeFunc()
关于回调,只需声明一个属性:
class TripView: UIView
var onChange: (() -> Void)?
在每次更改调用时:
onChange?()
然后你可以在你的控制器中:
var tripView: TripView = ...
tripView.onChange =
// handle the event
【讨论】:
@King 你也可以提到一些他不处理编码器初始化的情况。 @RobertDresler 是的,我注意到了,但我猜他并不真正支持。 @RobertDresler 我不太了解你 不是向前擦拭,而是向上移动并向下返回 @king 很抱歉,我无法解决您代码中的所有问题。这就是为什么问题必须非常具体的原因。以上是关于在 Swift 中创建可重用视图并添加完成处理程序的主要内容,如果未能解决你的问题,请参考以下文章