2015-02-10 1 views
1

Я пытаюсь добавить это Hamburger button в качестве кнопки панели навигации в Swift. Ниже приведен код, я пытался ...Добавить кнопку гамбургера на панель навигации

@IBOutlet var button: HamburgerButton!   
self.button.addTarget(self, action: "toggle:", forControlEvents:.TouchUpInside) 
self.button.transform = CGAffineTransformMakeScale(2.0, 2.0) 

self.navigationItem.leftBarButtonItem = button; //ERROR: HamburgerButton is not convertible to UIBarButtonItem 
self.navigationItem.leftBarButtonItem?.image = UIImage(named: "menu.png"); 

Я даже пытался бросить его UIBarButtonItem как self.navigationItem.leftBarButtonItem = button as UIBarButtonItem;, но по-прежнему сталкивается с той же ошибки.

EDIT

Я сделал несколько изменений в классе HamburgerButton, но получить несколько ошибок, и я не мог отлаживать, что именно эта проблема.

public class HamburgerButton: UIBarButtonItem { //Replaced UIButton with UIBarButtonItem 

    public var color: UIColor = UIColor.whiteColor() { 
     didSet { 
      for shapeLayer in shapeLayers { 
       shapeLayer.strokeColor = color.CGColor 
      } 
     } 
    } 

    private let top: CAShapeLayer = CAShapeLayer() 
    private let middle: CAShapeLayer = CAShapeLayer() 
    private let bottom: CAShapeLayer = CAShapeLayer() 
    private let width: CGFloat = 18 //ERROR: Cannot override with a stored property (I suppose this is because we cannot change the dimensions of the UIBarButtonItem) 
    private let height: CGFloat = 16 //ERROR 
    private let topYPosition: CGFloat = 2 
    private let middleYPosition: CGFloat = 7 
    private let bottomYPosition: CGFloat = 12 

    override init(frame: CGRect) { //ERROR: Initializer does not override a designated initializer from its superclass (NO IDEA) 
     super.init(frame: frame) 
     commonInit() 
    } 

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

    private func commonInit() { 
     let path = UIBezierPath() 
     path.moveToPoint(CGPoint(x: 0, y: 0)) 
     path.addLineToPoint(CGPoint(x: width, y: 0)) 

     for shapeLayer in shapeLayers { 
      shapeLayer.path = path.CGPath 
      shapeLayer.lineWidth = 2 
      shapeLayer.strokeColor = color.CGColor 

      // Disables implicit animations. 
      shapeLayer.actions = [ 
       "transform": NSNull(), 
       "position": NSNull() 
      ] 

      let strokingPath = CGPathCreateCopyByStrokingPath(shapeLayer.path, nil, shapeLayer.lineWidth, kCGLineCapButt, kCGLineJoinMiter, shapeLayer.miterLimit) 
      // Otherwise bounds will be equal to CGRectZero. 
      shapeLayer.bounds = CGPathGetPathBoundingBox(strokingPath) 

      //layer.addSublayer(shapeLayer) 
     } 

     let widthMiddle = width/2 
     top.position = CGPoint(x: widthMiddle, y: topYPosition) 
     middle.position = CGPoint(x: widthMiddle, y: middleYPosition) 
     bottom.position = CGPoint(x: widthMiddle, y: bottomYPosition) 
    } 

    override public func intrinsicContentSize() -> CGSize { //ERROR: Method does not override any method from its superclass (NO IDEA) 
     return CGSize(width: width, height: height) 
    } 

    public var showsMenu: Bool = true { 
     didSet { 
      // There's many animations so it's easier to set up duration and timing function at once. 
      CATransaction.begin() 
      CATransaction.setAnimationDuration(0.4) 
      CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(controlPoints: 0.4, 0.0, 0.2, 1.0)) 

      let strokeStartNewValue: CGFloat = showsMenu ? 0.0 : 0.3 
      let positionPathControlPointY = bottomYPosition/2 
      let verticalOffsetInRotatedState: CGFloat = 0.75 


      let topRotation = CAKeyframeAnimation(keyPath: "transform") 
      topRotation.values = rotationValuesFromTransform(top.transform, 
       endValue: showsMenu ? CGFloat(-M_PI - M_PI_4) : CGFloat(M_PI + M_PI_4)) 
      // Kind of a workaround. Used because it was hard to animate positions of segments' such that their ends form the arrow's tip and don't cross each other. 
      topRotation.calculationMode = kCAAnimationCubic 
      topRotation.keyTimes = [0.0, 0.33, 0.73, 1.0] 
      top.ahk_applyKeyframeValuesAnimation(topRotation) 

      let topPosition = CAKeyframeAnimation(keyPath: "position") 
      let topPositionEndPoint = CGPoint(x: width/2, y: showsMenu ? topYPosition : bottomYPosition + verticalOffsetInRotatedState) 
      topPosition.path = quadBezierCurveFromPoint(top.position, 
       toPoint: topPositionEndPoint, 
       controlPoint: CGPoint(x: width, y: positionPathControlPointY)).CGPath 
      top.ahk_applyKeyframePathAnimation(topPosition, endValue: NSValue(CGPoint: topPositionEndPoint)) 

      top.strokeStart = strokeStartNewValue 


      let middleRotation = CAKeyframeAnimation(keyPath: "transform") 
      middleRotation.values = rotationValuesFromTransform(middle.transform, 
       endValue: showsMenu ? CGFloat(-M_PI) : CGFloat(M_PI)) 
      middle.ahk_applyKeyframeValuesAnimation(middleRotation) 

      middle.strokeEnd = showsMenu ? 1.0 : 0.85 


      let bottomRotation = CAKeyframeAnimation(keyPath: "transform") 
      bottomRotation.values = rotationValuesFromTransform(bottom.transform, 
       endValue: showsMenu ? CGFloat(-M_PI_2 - M_PI_4) : CGFloat(M_PI_2 + M_PI_4)) 
      bottomRotation.calculationMode = kCAAnimationCubic 
      bottomRotation.keyTimes = [0.0, 0.33, 0.63, 1.0] 
      bottom.ahk_applyKeyframeValuesAnimation(bottomRotation) 

      let bottomPosition = CAKeyframeAnimation(keyPath: "position") 
      let bottomPositionEndPoint = CGPoint(x: width/2, y: showsMenu ? bottomYPosition : topYPosition - verticalOffsetInRotatedState) 
      bottomPosition.path = quadBezierCurveFromPoint(bottom.position, 
       toPoint: bottomPositionEndPoint, 
       controlPoint: CGPoint(x: 0, y: positionPathControlPointY)).CGPath 
      bottom.ahk_applyKeyframePathAnimation(bottomPosition, endValue: NSValue(CGPoint: bottomPositionEndPoint)) 

      bottom.strokeStart = strokeStartNewValue 


      CATransaction.commit() 
     } 
    } 

    private var shapeLayers: [CAShapeLayer] { 
     return [top, middle, bottom] 
    } 
} 

extension CALayer { 
    func ahk_applyKeyframeValuesAnimation(animation: CAKeyframeAnimation) { 
     let copy = animation.copy() as CAKeyframeAnimation 

     assert(!copy.values.isEmpty) 

     self.addAnimation(copy, forKey: copy.keyPath) 
     self.setValue(copy.values[copy.values.count - 1], forKeyPath:copy.keyPath) 
    } 

    // Mark: TODO: endValue could be removed from the definition, because it's possible to get it from the path (see: CGPathApply). 
    func ahk_applyKeyframePathAnimation(animation: CAKeyframeAnimation, endValue: NSValue) { 
     let copy = animation.copy() as CAKeyframeAnimation 

     self.addAnimation(copy, forKey: copy.keyPath) 
     self.setValue(endValue, forKeyPath:copy.keyPath) 
    } 
} 

func rotationValuesFromTransform(transform: CATransform3D, #endValue: CGFloat) -> [NSValue] { 
    let frames = 4 

    // values at 0, 1/3, 2/3 and 1 
    return (0..<frames).map { num in 
     NSValue(CATransform3D: CATransform3DRotate(transform, endValue/CGFloat(frames - 1) * CGFloat(num), 0, 0, 1)) 
    } 
} 

func quadBezierCurveFromPoint(startPoint: CGPoint, #toPoint: CGPoint, #controlPoint: CGPoint) -> UIBezierPath { 
    let quadPath = UIBezierPath() 
    quadPath.moveToPoint(startPoint) 
    quadPath.addQuadCurveToPoint(toPoint, controlPoint: controlPoint) 
    return quadPath 
} 
+1

Является ли класс HamburgerButton UIBarButtonItem? – kellanburket

+0

@blacksquare Я только что заменил класс HamburgerButton 'UIBarButtonItem' и сделал несколько изменений, но он не работает. Я обновил свой пост, проверьте его. –

+0

С чем связано IBOutlet? – kellanburket

ответ

1

Вы должны связать UIBarButtonItem до NavBar, назначая customView к в BarButtonItem. Я добавил инициализатор, чтобы позаботиться об этом для вас.

init(frame: CGRect, target: AnyObject, action: Selector) { 
    var view = UIButton(frame: frame) 
    var width = 18 
    let path = UIBezierPath() 
    path.moveToPoint(CGPoint(x: 0, y: 0)) 
    path.addLineToPoint(CGPoint(x: width, y: 0)) 


    var shapeLayers: [CAShapeLayer] = [top, middle, bottom] 

    var color: UIColor = UIColor.blackColor() { 
     didSet { 
      for shapeLayer in shapeLayers { 
       shapeLayer.strokeColor = color.CGColor 
      } 
     } 
    } 

    for shapeLayer in shapeLayers { 
     shapeLayer.path = path.CGPath 
     shapeLayer.lineWidth = 2 
     shapeLayer.strokeColor = color.CGColor 

     // Disables implicit animations. 
     shapeLayer.actions = [ 
      "transform": NSNull(), 
      "position": NSNull() 
     ] 

     let strokingPath = CGPathCreateCopyByStrokingPath(shapeLayer.path, nil, shapeLayer.lineWidth, kCGLineCapButt, kCGLineJoinMiter, shapeLayer.miterLimit) 
     // Otherwise bounds will be equal to CGRectZero. 
     shapeLayer.bounds = CGPathGetPathBoundingBox(strokingPath) 

     //layer.addSublayer(shapeLayer) 
    } 

    let widthMiddle = CGFloat(width/2) 
    top.position = CGPoint(x: widthMiddle, y: topYPosition) 
    middle.position = CGPoint(x: widthMiddle, y: middleYPosition) 
    bottom.position = CGPoint(x: widthMiddle, y: bottomYPosition) 


    for layer in shapeLayers { 
     view.layer.addSublayer(layer) 
    } 
    view.addGestureRecognizer(UITapGestureRecognizer(target: target, action: action)) 
    super.init(customView: view) 
} 

Теперь вы можете добавить панель с контроллера зрения и назначить действие на него так:

@IBAction func doSomething(sender: AnyObject) { 
    println("Do Something") 
    menuButton!.showsMenu = true 
} 

override func viewDidLoad() { 
    super.viewDidLoad() 
    menuButton = HamburgerButton(frame: CGRectMake(0, 0, 18, 18), target: self, action: "doSomething:") 
    navigationItem.setRightBarButtonItem(menuButton!, animated: true) 
} 

Обратите внимание, что когда вы назначая customView вы не можете использовать UIBarButtonItem по умолчанию GestureRecognizer , поэтому вам придется добавить свой собственный.

Я не смотрел код анимации, который у вас есть в showMenu, поэтому вам, возможно, потребуется предпринять дополнительные шаги для его реализации.

+0

Инициализатор, который вы опубликовали, не работает. Ошибка, которую он бросает, - это ошибка: использование нереализованного инициализатора init() для класса. Что означает «просмотр» во второй строке вашего кода? –

+0

Реализовать инициализатор, как он говорит. 'override init() {super.init()}' – kellanburket

+0

Вид представляет собой экземпляр uibutton. – kellanburket