Creating reusable View in Swift and adding a completion handler

北城以北 提交于 2019-12-13 04:33:35

问题


I created a sliderView, and added a UIPanGesture and I created a seperate UIView to handle this slider. I want to be able to call this SliderView in different ViewControllers where I need it but when I try to run my code IT crashed.I also would want to pass a completion handler to handle events in the ViewCOntrollers where I would be needing it. I am trying to follow the DRY process by creating one UIView and using it in mutiple screen. Below is my code so far

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

}

回答1:


You are calling swipeFunc which accesses sliderImage before sliderImage is initialized.

You have to move swipeFunc() to the end of your init method.

Actually, there is no need to use implicitly unwrapped optionals. You can prevent the crashes by using a non-optional:

let sliderView: UIView = UIImageView(frame: CGRect.zero)
let sliderImage: UIImageView = UIImageView(frame: CGRect.zero)

Since you actually have two initializers, you should probably init everything in both:

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

Regarding a callback, simply declare a property:

class TripView: UIView {
    var onChange: (() -> Void)?
}

and on every change call:

onChange?()

In your controller you can then:

var tripView: TripView = ...
tripView.onChange = {
  // handle the event
}



回答2:


You can add a completion handler as an internal variable, or pass one in the initialiser.

e.g:

class TripView: UIView {
    typealias Callback = () -> ()
    var callback: Callback

    ...
}

Then where you want to trigger the callback, simply call:

callback()

Or you could define a delegate

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

class TripView: UIView {
    weak var tripViewDelegate: TripViewDelegate?
    // ...
}

And then call

tripViewDelegate?.didDoSomething(for: self)


来源:https://stackoverflow.com/questions/54634147/creating-reusable-view-in-swift-and-adding-a-completion-handler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!