【问题标题】:I took a github project where he added a button programatically, but I added it with the interface builder but it doesn't work我参加了一个 github 项目,他在其中以编程方式添加了一个按钮,但我使用界面生成器添加了它,但它不起作用
【发布时间】:2017-07-02 19:46:15
【问题描述】:

有人可以帮我解决那个 github 项目如何用一些代码在我的项目中实现

这段代码是我使用 IB builder 创建按钮并为按钮创建插座并将其类更改为自定义类并添加切换功能和 .TouchUpInside 行的代码 我得到一个错误

致命错误:在展开可选值时意外发现 nil 2017-07-03 00:51:21.630176+0530 ala[867:183071] 致命错误:在展开可选值时意外发现 nil (lldb)

当我点击按钮并且在其默认状态下它甚至不可见时

import UIKit

class serchViewController: UIViewController {
@IBOutlet weak var menuView: UIView!
@IBOutlet weak var menuBtn: HamburgerButton!

override func viewDidLoad() {
    super.viewDidLoad()
    let screenSize: CGRect = UIScreen.main.bounds
    menuView.frame = CGRect (x: 0, y: 0, width: screenSize.width/4, height: screenSize.height)
    self.menuBtn.addTarget(self, action: #selector(serchViewController.toggle(_:)), for: .touchUpInside)

    // Do any additional setup after loading the view.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func toggle(_ sender: AnyObject!) {
    self.menuBtn.showsMenu = !self.menuBtn.showsMenu
}


}

这是原始代码 导入 UIKit

class ViewController: UIViewController {
var button: HamburgerButton! = nil

override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = UIColor(red: 38.0 / 255, green: 151.0 / 255, blue: 68.0 / 255, alpha: 1)

    self.button = HamburgerButton(frame: CGRect(x: 133, y: 133, width: 54, height: 54))
    self.button.addTarget(self, action: #selector(ViewController.toggle(_:)), for:.touchUpInside)

    self.view.addSubview(button)
}

override var preferredStatusBarStyle : UIStatusBarStyle  {
    return .lightContent
}

func toggle(_ sender: AnyObject!) {
    self.button.showsMenu = !self.button.showsMenu
}
}

错误文件代码如下

import CoreGraphics
import QuartzCore
import UIKit

class HamburgerButton : UIButton {
let shortStroke: CGPath = {
    let path = CGMutablePath()
    path.move(to: CGPoint(x: 2, y: 2))
    path.addLine(to: CGPoint(x: 28, y:2))

    return path
}()

let outline: CGPath = {
    let path = CGMutablePath()
    path.move(to: CGPoint(x: 10, y: 27))
    path.addCurve(to: CGPoint(x: 40, y: 27), control1: CGPoint(x: 12, y: 27), control2: CGPoint(x: 28.02, y: 27))
    path.addCurve(to: CGPoint(x: 27, y: 02), control1: CGPoint(x: 55.92, y: 27), control2: CGPoint(x: 50.47, y: 2))
    path.addCurve(to: CGPoint(x: 2, y: 27), control1: CGPoint(x: 13.16, y: 2), control2: CGPoint(x: 2, y: 13.16))
    path.addCurve(to: CGPoint(x: 27, y: 52), control1: CGPoint(x: 2, y: 40.84), control2: CGPoint(x: 13.16, y: 52))
    path.addCurve(to: CGPoint(x: 52, y: 27), control1: CGPoint(x: 40.84, y: 52), control2: CGPoint(x: 52, y: 40.84))
    path.addCurve(to: CGPoint(x: 27, y: 2), control1: CGPoint(x: 52, y: 13.16), control2: CGPoint(x: 42.39, y: 2))
    path.addCurve(to: CGPoint(x: 2, y: 27), control1: CGPoint(x: 13.16, y: 2), control2: CGPoint(x: 2, y: 13.16))

    return path
}()

let menuStrokeStart: CGFloat = 0.325
let menuStrokeEnd: CGFloat = 0.9

let hamburgerStrokeStart: CGFloat = 0.028
let hamburgerStrokeEnd: CGFloat = 0.111

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

override init(frame: CGRect) {
    super.init(frame: frame)

    self.top.path = shortStroke
    self.middle.path = outline
    self.bottom.path = shortStroke

    for layer in [ self.top, self.middle, self.bottom ] {
        layer?.fillColor = nil
        layer?.strokeColor = UIColor.blue.cgColor
        layer?.lineWidth = 4
        layer?.miterLimit = 4
        layer?.lineCap = kCALineCapRound
        layer?.masksToBounds = true

        let strokingPath = CGPath(__byStroking: (layer?.path!)!, transform: nil, lineWidth: 4, lineCap: .round, lineJoin: .miter, miterLimit: 4)

        layer?.bounds = (strokingPath?.boundingBoxOfPath)!

        layer?.actions = [
            "strokeStart": NSNull(),
            "strokeEnd": NSNull(),
            "transform": NSNull()
        ]

        self.layer.addSublayer(layer!)
    }

    self.top.anchorPoint = CGPoint(x: 28.0 / 30.0, y: 0.5)
    self.top.position = CGPoint(x: 40, y: 18)

    self.middle.position = CGPoint(x: 27, y: 27)
    self.middle.strokeStart = hamburgerStrokeStart
    self.middle.strokeEnd = hamburgerStrokeEnd

    self.bottom.anchorPoint = CGPoint(x: 28.0 / 30.0, y: 0.5)
    self.bottom.position = CGPoint(x: 40, y: 36)
    }

    var showsMenu: Bool = false {
    didSet {
        let strokeStart = CABasicAnimation(keyPath: "strokeStart")
        let strokeEnd = CABasicAnimation(keyPath: "strokeEnd")

        if self.showsMenu {
            strokeStart.toValue = menuStrokeStart
            strokeStart.duration = 0.5
            strokeStart.timingFunction = CAMediaTimingFunction(controlPoints: 0.25, -0.4, 0.5, 1)

            strokeEnd.toValue = menuStrokeEnd
            strokeEnd.duration = 0.6
            strokeEnd.timingFunction = CAMediaTimingFunction(controlPoints: 0.25, -0.4, 0.5, 1)
        } else {
            strokeStart.toValue = hamburgerStrokeStart
            strokeStart.duration = 0.5
            strokeStart.timingFunction = CAMediaTimingFunction(controlPoints: 0.25, 0, 0.5, 1.2)
            strokeStart.beginTime = CACurrentMediaTime() + 0.1
            strokeStart.fillMode = kCAFillModeBackwards

            strokeEnd.toValue = hamburgerStrokeEnd
            strokeEnd.duration = 0.6
            strokeEnd.timingFunction = CAMediaTimingFunction(controlPoints: 0.25, 0.3, 0.5, 0.9)
        }

        self.middle.ocb_applyAnimation(strokeStart)
        self.middle.ocb_applyAnimation(strokeEnd)

        let topTransform = CABasicAnimation(keyPath: "transform")
        topTransform.timingFunction = CAMediaTimingFunction(controlPoints: 0.5, -0.8, 0.5, 1.85)
        topTransform.duration = 0.4
        topTransform.fillMode = kCAFillModeBackwards

        let bottomTransform = topTransform.copy() as! CABasicAnimation

        if self.showsMenu {
            let translation = CATransform3DMakeTranslation(-4, 0, 0)

            topTransform.toValue = NSValue(caTransform3D: CATransform3DRotate(translation, -0.7853975, 0, 0, 1))
            topTransform.beginTime = CACurrentMediaTime() + 0.25

            bottomTransform.toValue = NSValue(caTransform3D: CATransform3DRotate(translation, 0.7853975, 0, 0, 1))
            bottomTransform.beginTime = CACurrentMediaTime() + 0.25
        } else {
            topTransform.toValue = NSValue(caTransform3D: CATransform3DIdentity)
            topTransform.beginTime = CACurrentMediaTime() + 0.05

            bottomTransform.toValue = NSValue(caTransform3D: CATransform3DIdentity)
            bottomTransform.beginTime = CACurrentMediaTime() + 0.05
        }

        self.top.ocb_applyAnimation(topTransform)
        self.bottom.ocb_applyAnimation(bottomTransform)
       }
    }

    var top: CAShapeLayer! = CAShapeLayer()
    var bottom: CAShapeLayer! = CAShapeLayer()
    var middle: CAShapeLayer! = CAShapeLayer()
  }

  extension CALayer {
func ocb_applyAnimation(_ animation: CABasicAnimation) {
    let copy = animation.copy() as! CABasicAnimation

    if copy.fromValue == nil {
        copy.fromValue = self.presentation()!.value(forKeyPath: copy.keyPath!)
    }

    self.add(copy, forKey: copy.keyPath)
    self.setValue(copy.toValue, forKeyPath:copy.keyPath!)
}
}

Project GitHub link

error screenshot

IB builder screenshot

【问题讨论】:

  • IBOutlet 是否连接到情节提要?此外,无需以编程方式将目标添加到情节提要按钮,您可以直接从情节提要中添加它。 1. 在界面生成器中选择按钮 2. 在 Right Inspector 窗口中单击 Connections Inspector 3. 然后从 TouchUpInside 拖动到您的 viewController。
  • 我试过这样做,但它没有以这种方式连接@HarrySingh
  • @HarrySingh 为什么我会收到这个错误?
  • @ChetanRajagiri “它没有以那种方式连接”你是什么意思?
  • @J.Doe 当我将 TouchUpInside 拉到我的按钮上时,它不会突出显示,也不会尝试为我的按钮添加该事件

标签: ios swift xcode swift3 xcode8


【解决方案1】:

链接项目上有一个open pull request,以使其可从界面生成器中使用。为什么不尝试使用那个 fork 而不是原来的 repo?

目前无法正常工作的原因是init(frame:) 方法中正在进行大量设置。当您从情节提要创建对象时,不会调用该方法,而是使用init(coder:)。在上面的代码中,该方法是空的,因此没有完成任何设置。

通常,您会将通用设置代码放在单独的方法中,并从两个初始化程序中调用它。这不是 PR 作者所采用的方法,但你总是可以制作自己的 fork。

举个例子:

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

override init(frame: CGRect) {
    super.init(frame: frame)

    self.top.path = shortStroke
    self.middle.path = outline
    self.bottom.path = shortStroke
    // plus all the other code in here...
}

会变成:

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    self.commonSetUp()
}

override init(frame: CGRect) {
    super.init(frame: frame)
    self.commonSetUp()
}

private func commonSetUp() {
    self.top.path = shortStroke
    self.middle.path = outline
    self.bottom.path = shortStroke
    // plus all the other code in here...
}

【讨论】:

  • 那个分叉也有很多错误,IB designables 构建失败...你能建议我一个很好的项目来实现汉堡图标转换
  • 我不能不,但是您可以尝试从 init 方法中提取设置代码,并确保按照我的建议,使用 coder 从 init 调用它。应该不会太难。
  • 你能用代码解释一下吗,因为我是开发新手@jrturton
【解决方案2】:

您可以尝试将#selector(serchViewController.toggle(_:)) 更改为#selector(toggle(_:))。看起来它正在查找 nil,因为您试图将其指向 class func。您在方法中说过您的目标是self,它应该指向current 中的method instance

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 2018-02-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多