代码之家  ›  专栏  ›  技术社区  ›  King

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

  •  0
  • King  · 技术社区  · 7 年前

    我创建了一个幻灯片视图,添加了一个uipangesture,并创建了一个单独的uiview来处理这个幻灯片。我希望能够在需要的不同视图控制器中调用此SliderView,但当我尝试运行代码时,它崩溃了。我还希望传递一个完成处理程序来处理需要它的视图控制器中的事件。我试图通过创建一个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
                    })
                }
            }
        }
    
    }
    
    2 回复  |  直到 7 年前
        1
  •  1
  •   Sulthan    7 年前

    你在呼唤 swipeFunc 哪些访问 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
    }
    
        2
  •  1
  •   Sander Saelmans    7 年前

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

    例如:

    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)