Ios 在Swift中创建可重用视图并添加完成处理程序

Ios 在Swift中创建可重用视图并添加完成处理程序,ios,swift,completionhandler,Ios,Swift,Completionhandler,我创建了一个sliderView,并添加了一个UIPanGesture,还创建了一个单独的UIView来处理这个滑块。我希望能够在需要的不同ViewController中调用此SliderView,但当我尝试运行代码时,它崩溃了。我还希望传递一个完成处理程序来处理ViewController中需要它的事件。我试图通过创建一个UIView并在多个屏幕中使用它来遵循干燥过程。下面是到目前为止我的代码 class TripView: UIView { var shouldSetupConst

我创建了一个sliderView,并添加了一个UIPanGesture,还创建了一个单独的UIView来处理这个滑块。我希望能够在需要的不同ViewController中调用此SliderView,但当我尝试运行代码时,它崩溃了。我还希望传递一个完成处理程序来处理ViewController中需要它的事件。我试图通过创建一个UIView并在多个屏幕中使用它来遵循干燥过程。下面是到目前为止我的代码

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
                })
            }
        }
    }

}
类TripView:UIView{
var shouldSetupConstraints=true
变量开始帧:CGRect?
var sliderView:UIView!
var sliderImage:UIImageView!
让screenSize=UIScreen.main.bounds
重写初始化(帧:CGRect){
super.init(frame:frame)
swipeFunc()
sliderView=UIImageView(帧:cRect.zero)
sliderView.backgroundColor=UIColor.green
sliderView.autoSetDimension(.height,toSize:screenSize.width/6)
self.addSubview(sliderView)
sliderImage=UIImageView(帧:cRect.zero)
sliderImage.backgroundColor=UIColor.clear
sliderImage.image=UIImage(名为:“icons8-double\u right\u filled.png”)
sliderImage.contentMode=.ScaleSpectFit
sliderImage.autoSetDimension(.width,toSize:screenSize.width/6)
sliderImage.autoSetDimension(.height,toSize:screenSize.width/6)
self.addSubview(幻灯片图像)
}
必需的初始化?(编码器aDecoder:NSCoder){
super.init(编码者:aDecoder)
}
重写func updateConstraints(){
如果(应设置约束){
sliderView.autoPinEdgesToSuperviewSafeArea(带:UIEdgeInsets.zero,不包括边缘:。底部)
sliderImage.AutoPineEdge(toSuperviewEdge:.左)
SlideImage.AutoPineEdge(.bottom,to:.bottom,of:sliderView,带偏移量:0.0)
shouldSetupConstraints=false
}
super.updateConstraints()
}
}
扩展TripView{
私有函数swipeFunc(){
让swipeGesture=UIPangestureRecognitor(目标:自我,操作:#选择器(确认擦除(发送方:))
sliderImage.AddGestureRecognitor(swipeGesture)
sliderImage.isUserInteractionEnabled=true
swipeGesture.delegate=自我身份?UIgestureRecognitizerDelegate
}
@objc func确认擦除(发送方:UIPangestureRecognitizer){
如果let sliderView=sender.view{
让translation=sender.translation(in:sliderView)
切换发送器状态{
案例.开始:
startingFrame=sliderImage.frame
失败
案例。更改:
如果让startFrame=startingFrame{
var movex=translation.x
如果movex<-startFrame.origin.x{movex=-startFrame.origin.x}
设xMax=sliderView.frame.width-startFrame.origin.x-startFrame.width
如果movex>xMax{
movex=xMax
//我想在这里传递一个完成处理程序。以便能够处理ViewController中的其他事件
}
var movey=translation.y
如果movey<-startFrame.origin.y{movey=-startFrame.origin.y}
设yMax=sliderView.frame.height-startFrame.origin.y-startFrame.height
如果movey>yMax{
movey=yMax
}
sliderView.transform=CGAffineTransform(translationX:movex,y:movey)
}
默认值://。结束和其他:
UIView.animate(持续时间:0.1,动画:{
sliderView.transform=CGAffineTransform.identity
})
}
}
}
}

您正在调用
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
}

您正在调用
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
}

您可以添加一个完成处理程序作为内部变量,或者在初始化器中传递一个

e、 g:

然后在要触发回调的地方,只需调用:

callback()
或者您可以定义一个委托

protocol TripViewDelegate {
    func didDoSomething(for view: TripView)
}

class TripView: UIView {
    weak var tripViewDelegate: TripViewDelegate?
    // ...
}
然后打电话

tripViewDelegate?.didDoSomething(for: self)

您可以添加一个完成处理程序作为内部变量,或者在初始化器中传递一个

e、 g:

然后在要触发回调的地方,只需调用:

callback()
或者您可以定义一个委托

protocol TripViewDelegate {
    func didDoSomething(for view: TripView)
}

class TripView: UIView {
    weak var tripViewDelegate: TripViewDelegate?
    // ...
}
然后打电话

tripViewDelegate?.didDoSomething(for: self)

它在哪里崩溃了?这里是
sliderImage.addgestureignizer(swipeGesture)
King,
sliderImage.addgestureignizer(swipeGesture)
中的崩溃是由于
sliderImage
nil
值造成的。初始化对象时是否使用了
TripView(frame:)
方法?它在哪里崩溃了?这里是
sliderImage.addgestureRecognitizer(swipeGesture)
King,在
sliderImage.addgestureRecognitizer(swipeGesture)
中崩溃是由于
sliderImage
nil
值造成的。你用的是