Xcode 9.3.1 Unknown class in Interface Builder File - ios

I have been trying to make an onboarding screen for my iOS game made using Sprite Kit. I am using the ramotion kit(https://github.com/Ramotion/paper-onboarding) for doing the same. I keep getting this error, Unknown class in interface builder and I have been stuck on this for ages. Here is my code for the GameViewController class:
import UIKit
import SpriteKit
import PaperOnboarding
protocol Controller {
func levelCompleted()
func levelFailed()
}
/* GameViewController is in charge of managing the game. This includes creating and
* changing levels, access to main menu, etc.
*/
var count = 0
class GameViewController: UIViewController, PaperOnboardingDataSource, PaperOnboardingDelegate
{
#IBOutlet var onboardingView: OnboardingView!
#IBOutlet var getStartedButton: UIButton!
#IBAction func playButtonPressed(_ sender: Any)
{
let controller = storyboard!.instantiateViewController(withIdentifier: "actualGame")
initialiseSKScene()
}
var currentLevel: Level? = nil
var config: GameConfiguration?
var skView: SKView?
override func viewDidLoad()
{
super.viewDidLoad()
onboardingView.dataSource = self
onboardingView.delegate = self
}
func initialiseSKScene()
{
let skView = initialiseSKView()
do
{
config = try GameConfiguration(file: "level_json_sample", size: skView.bounds.size)
}
catch let error
{
print("Level cannot be loaded!")
print(error)
}
let teethArray = config!.getTeethByLevel(id: 1)
let objectArray = config!.getObjectsByLevel(id: 1)
print(objectArray[0])
// Use the JSON file to open level 1
currentLevel = Level(size: skView.bounds.size, bgFile: "background2.png",
teethArray: teethArray, otherArray: objectArray, c: self as! Controller)
currentLevel?.scaleMode = SKSceneScaleMode.resizeFill
skView.presentScene(currentLevel)
}
func onboardingItemsCount() -> Int
{
return 3
}
func onboardingItem(at index: Int) -> OnboardingItemInfo
{
let onBoardItem1 = OnboardingItemInfo(informationImage: UIImage(named: "rocket")!,
title: "A Great Rocket Start",
description: "Caramels cheesecake bonbon bonbon topping. Candy halvah cotton candy chocolate bar cake. Fruitcake liquorice candy canes marshmallow topping powder.",
pageIcon: UIImage(named: "rocket")!,
color: UIColor(red: 217/255, green: 72/255, blue: 89/255, alpha: 1),
titleColor: UIColor.white,
descriptionColor: UIColor.white,
titleFont: UIFont(name: "AvenirNext-Bold", size: 24)!,
descriptionFont: UIFont(name: "AvenirNext-Regular", size: 18)!)
let onBoardItem2 = OnboardingItemInfo(informationImage: UIImage(named: "brush")!,
title: "Design your Experience",
description: "Caramels cheesecake bonbon bonbon topping. Candy halvah cotton candy chocolate bar cake. Fruitcake liquorice candy canes marshmallow topping powder.",
pageIcon: UIImage(named: "brush")!,
color: UIColor(red: 106/255, green: 166/255, blue: 211/255, alpha: 1),
titleColor: UIColor.white,
descriptionColor: UIColor.white,
titleFont: UIFont(name: "AvenirNext-Bold", size: 24)!,
descriptionFont: UIFont(name: "AvenirNext-Regular", size: 18)!)
let onBoardItem3 = OnboardingItemInfo(informationImage: UIImage(named: "notification")!,
title: "Stay Up To Date",
description: "Get notified of important updates.",
pageIcon: UIImage(named: "notification")!,
color: UIColor(red: 168/255, green: 200/255, blue: 78/255, alpha: 1),
titleColor: UIColor.white,
descriptionColor: UIColor.white,
titleFont: UIFont(name: "AvenirNext-Bold", size: 24)!,
descriptionFont: UIFont(name: "AvenirNext-Regular", size: 18)!)
return [onBoardItem1,onBoardItem2,onBoardItem3][index]
}
/* Initialises the SKView where we display the game */
private func initialiseSKView() -> SKView
{
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsPhysics = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
skView.isMultipleTouchEnabled = false
return skView
}
/* This method is called by the currentLevel when it is completed */
func levelCompleted() {
// check if there exists a higher level than currentLevel.id
// change to next level or present winning screen
let reveal = SKTransition.flipHorizontal(withDuration: 0.5)
let gameOverScene = GameOverScene(size: skView!.bounds.size, won: false)
skView?.presentScene(gameOverScene, transition: reveal)
}
func onboardingConfigurationItem(_: OnboardingContentViewItem, index _: Int)
{
}
func onboardingWillTransitonToIndex(_ index: Int)
{
if index == 1
{
if self.getStartedButton.alpha == 1
{
UIView.animate(withDuration: 0.2, animations:
{
self.getStartedButton.alpha = 0
})
}
}
}
func onboardingDidTransitonToIndex(_ index: Int)
{
if index == 2
{
UIView.animate(withDuration: 0.4, animations:
{
self.getStartedButton.alpha = 1
})
}
}
/* This method is called by the currentLevel when it is failed */
func levelFailed() {
// present losing screen
let reveal = SKTransition.flipHorizontal(withDuration: 0.5)
let gameOverScene = GameOverScene(size: skView!.bounds.size, won: false)
skView?.presentScene(gameOverScene, transition: reveal)
}
}
I get the Unknown class in interface builder error and this line in ViewDidLoad() shows:
"Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value"
onboardingView.dataSource = self
I have checked all my outlets and classes in interface builder as well and all of them are proper!
Would really appreciate any help!

Related

Why can't the method be called?

I just cloned a project from GitHub, and I added the relevant folder to my project. When I run my project, the animation effect can be displayed normally, but the images on the animation can't be displayed. I have tried re-cloning the complete code, but it still does the same. I'm sure that all the codes and images are completely cloned.
I added a breakpoint, realizing that the func circleMenu is never called.
Can someone please explain this, or at least tell me what I need to write to get it correct?
Here is my code:
import UIKit
import CircleMenu
extension UIColor {
static func color(_ red: Int, green: Int, blue: Int, alpha: Float) -> UIColor {
return UIColor(
red: 1.0 / 255.0 * CGFloat(red),
green: 1.0 / 255.0 * CGFloat(green),
blue: 1.0 / 255.0 * CGFloat(blue),
alpha: CGFloat(alpha))
}
}
class FirstViewController: UIViewController, CircleMenuDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate{
#IBAction func to2(_ sender: UIButton) {
let sb = UIStoryboard(name:"Main",bundle: Bundle.main)
let view2 = sb.instantiateViewController(withIdentifier: "view2")
layerTransition(animTye: .cube, subType: .ramdom, curve: .EaseInEaseOut, duration: 0.4, layer: (self.view.window?.layer)!)
self.present(view2,animated: true,completion: nil)
}
// let secondView = ViewController()
#IBAction func toView2(_ sender: UIButton) {
let sb = UIStoryboard(name:"Main",bundle: Bundle.main)
let secondViewController = sb.instantiateViewController(withIdentifier: "SecondViewController")
layerTransition(animTye: .cube, subType: .ramdom, curve: .EaseInEaseOut, duration: 0.4, layer: (self.view.window?.layer)!)
self.present(secondViewController,animated: true,completion: nil)
}
var imagePickerController:UIImagePickerController!
enum TransitionAnimType : Int {
case fade = 0,
push,
reveal,
moveIn,
cube,
suckEffect,
oglFlip,
rippleEffect,
pageCurl,
pageUnCurl,
cameraIrisHollowOpen,
cameraIrisHollowClose,
curlDown,
curlUp,
flipFromLeft,
flipFromRight,
ramdom
}
enum TransitionSubType : Int {
case top = 0,
left,
bottom,
right,
ramdom
}
enum TransitionCurve : Int {
case Default = 0,
EaseIn,
EaseOut,
EaseInEaseOut,
Linear,
Ramdom
}
private func animationType(animType: TransitionAnimType) -> String {
let animTypeArray = ["fade", "push", "reveal", "moveIn", "cube", "suckEffect", "oglFlip", "rippleEffect", "pageCurl", "pageUnCurl", "cameraIrisHollowOpen", "cameraIrisHollowClose", "curlDown", "curlUp", "flipFromLeft", "flipFromRight", "ramdom"]
return objectFromDataSource(array: animTypeArray, index: animType.rawValue, isRamdom: (TransitionAnimType.ramdom == animType)) as! String
}
private func animationSubType(subType: TransitionSubType) -> String {
let animSubTypeArray = [CATransitionSubtype.fromTop, CATransitionSubtype.fromLeft, CATransitionSubtype.fromBottom, CATransitionSubtype.fromRight]
return objectFromDataSource(array: animSubTypeArray, index: subType.rawValue, isRamdom: (TransitionSubType.ramdom == subType)) as! String
}
private func animationCurve(curve: TransitionCurve) -> String {
let animCurveArray = [CAMediaTimingFunctionName.default, CAMediaTimingFunctionName.easeIn, CAMediaTimingFunctionName.easeOut, CAMediaTimingFunctionName.easeInEaseOut, CAMediaTimingFunctionName.linear]
return objectFromDataSource(array: animCurveArray, index: curve.rawValue, isRamdom: (TransitionCurve.Ramdom == curve)) as! String
}
private func objectFromDataSource(array: Array<Any>, index: Int, isRamdom: Bool) -> AnyObject {
let count = array.count
let i = isRamdom ? Int(arc4random_uniform(UInt32(count))) : index
return array[i] as AnyObject
}
func layerTransition(animTye: TransitionAnimType, subType: TransitionSubType, curve: TransitionCurve, duration: CGFloat, layer: CALayer) {
let key = "transition"
if layer.animation(forKey: key) != nil {
layer.removeAnimation(forKey: key)
}
let transition = CATransition()
transition.duration = CFTimeInterval(duration)
transition.type = CATransitionType(rawValue: animationType(animType: animTye))
transition.subtype = CATransitionSubtype(rawValue: animationSubType(subType: subType))
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName(rawValue: animationCurve(curve: curve)))
transition.isRemovedOnCompletion = true
layer.add(transition, forKey: key)
}
// let colors = [UIColor.redColor(), UIColor.grayColor(), UIColor.greenColor(), UIColor.purpleColor()]
let items: [(icon: String, color: UIColor)] = [
("icon_home", UIColor(red: 0.19, green: 0.57, blue: 1, alpha: 1)),
("icon_search", UIColor(red: 0.22, green: 0.74, blue: 0, alpha: 1)),
("notifications-btn", UIColor(red: 0.96, green: 0.23, blue: 0.21, alpha: 1)),
("settings-btn", UIColor(red: 0.51, green: 0.15, blue: 1, alpha: 1)),
("nearby-btn", UIColor(red: 1, green: 0.39, blue: 0, alpha: 1))
]
// #IBInspectable var buttonsCount: Int = 3
// #IBInspectable var duration: Double = 2 // circle animation duration
// #IBInspectable var distance: Float = 100 // distance between center button and buttons
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
}
// MARK: <CircleMenuDelegate>
func circleMenu(_: CircleMenu, willDisplay button: UIButton, atIndex: Int) {
button.backgroundColor = items[atIndex].color
button.setImage(UIImage(named: items[atIndex].icon), for: .normal)
let image = UIImage(named:items[atIndex].icon)
// set highlited image
let highlightedImage = UIImage(named: items[atIndex].icon)?.withRenderingMode(.alwaysTemplate)
button.setImage(highlightedImage, for: .highlighted)
button.tintColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.3)
}
func circleMenu(_: CircleMenu, buttonWillSelected _: UIButton, atIndex: Int) {
print("button will selected: \(atIndex)")
}
func circleMenu(_: CircleMenu, buttonDidSelected _: UIButton, atIndex: Int) {
// let sb = UIStoryboard(name:"Main",bundle: Bundle.main)
// let secondView = sb.instantiateViewController(withIdentifier: "secondView")
print("button did selected: \(atIndex)")
if(atIndex == 0)
{
if(UIImagePickerController.isSourceTypeAvailable(.camera))
{
self.imagePickerController = UIImagePickerController()
self.imagePickerController.delegate = self
self.imagePickerController.allowsEditing = true
self.imagePickerController.sourceType = UIImagePickerController.SourceType.camera
layerTransition(animTye: .cameraIrisHollowOpen, subType: .ramdom, curve: .EaseInEaseOut, duration: 0.4, layer: (self.view.window?.layer)!)
self.present(self.imagePickerController,animated: true,completion: nil)
}
}
}
}
At this moment you only declare your delegate. Make sure you also set the delegate otherwise your delegate methodes wouldn't be called.

Forwarding events with hitTest() or point(inside, with event) from view added to keyWindow

I've got a small, reusable UIView widget that can be added to any view anywhere, and may or may not always be in the same place or have the same frame. It looks something like this:
class WidgetView: UIView {
// some stuff, not very exciting
}
In my widget view, there's a situation where I need to create a popup menu with an overlay underneath it. it looks like this:
class WidgetView: UIView {
// some stuff, not very exciting
var overlay: UIView!
commonInit() {
guard let keyWindow = UIApplication.shared.keyWindow else { return }
overlay = UIView(frame: keyWindow.frame)
overlay.alpha = 0
keyWindow.addSubview(overlay)
// Set some constraints here
someControls = CustomControlsView( ... a smaller controls view ... )
overlay.addSubview(someControls)
// Set some more constraints here!
}
showOverlay() {
overlay.alpha = 1
}
hideOverlay() {
overlay.alpha = 0
}
}
Where this gets complicated, is I'm cutting the shape of the originating WidgetView out of the overlay, so that its controls are still visible underneath. This works fine:
class CutoutView: UIView {
var holes: [CGRect]?
convenience init(holes: [CGRect], backgroundColor: UIColor?) {
self.init()
self.holes = holes
self.backgroundColor = backgroundColor ?? UIColor.black.withAlphaComponent(0.5)
isOpaque = false
}
override func draw(_ rect: CGRect) {
backgroundColor?.setFill()
UIRectFill(rect)
guard let rectsArray = holes else {
return
}
for holeRect in rectsArray {
let holeRectIntersection = rect.intersection(holeRect)
UIColor.clear.setFill()
UIRectFill(holeRectIntersection)
}
}
}
... except the problem:
Touches aren't forwarded through the cutout hole. So I thought I'd be clever, and use this extension to determine whether the pixels at the touch point are transparent or not, but I can't even get that far, because hitTest() and point(inside, with event) don't respond to touches outside of the WidgetView's frame.
The way I can see it, there are four (potential) ways to solve this, but I can't get any of them working.
Find some magical (🦄) way to to make hitTest or point(inside) respond anywhere in the keyWindow, or at least the overlayView's frame
Add a UITapGestureRecognizer to the overlayView and forward the appropriate touches to the originating view controller (this partially works — the tap gesture responds, but I don't know where to go from there)
Use a delegate/protocol implementation to tell the original WidgetView to respond to touches
Add the overlay and its subviews to a different parent view altogether that isn't the keyWindow?
Below the fold, here is a complete executable setup, which relies on a new single view project with storyboard. It relies on SnapKit constraints, for which you can use the following podfile:
podfile
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
use_frameworks!
target 'YourTarget' do
pod 'SnapKit', '~> 4.2.0'
end
ViewController.swift
import UIKit
import SnapKit
class ViewController: UIViewController {
public var utilityToolbar: UtilityToolbar!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .darkGray
setup()
}
func setup() {
let button1 = UtilityToolbar.Button(title: "One", buttonPressed: nil)
let button2 = UtilityToolbar.Button(title: "Two", buttonPressed: nil)
let button3 = UtilityToolbar.Button(title: "Three", buttonPressed: nil)
let button4 = UtilityToolbar.Button(title: "Four", buttonPressed: nil)
let button5 = UtilityToolbar.Button(title: "Five", buttonPressed: nil)
let menuItems: [UtilityToolbar.Button] = [button1, button2, button3, button4, button5]
menuItems.forEach({
$0.setTitleColor(#colorLiteral(red: 0.1963312924, green: 0.2092989385, blue: 0.2291107476, alpha: 1), for: .normal)
})
utilityToolbar = UtilityToolbar(title: "One", menuItems: menuItems)
utilityToolbar.titleButton.setTitleColor(#colorLiteral(red: 0.1963312924, green: 0.2092989385, blue: 0.2291107476, alpha: 1), for: .normal)
utilityToolbar.backgroundColor = .white
utilityToolbar.dropdownContainer.backgroundColor = .white
view.addSubview(utilityToolbar)
utilityToolbar.snp.makeConstraints { (make) in
make.left.right.equalToSuperview()
make.top.equalToSuperview().offset(250)
make.height.equalTo(50.0)
}
}
}
CutoutView.swift
import UIKit
class CutoutView: UIView {
var holes: [CGRect]?
convenience init(holes: [CGRect], backgroundColor: UIColor?) {
self.init()
self.holes = holes
self.backgroundColor = backgroundColor ?? UIColor.black.withAlphaComponent(0.5)
isOpaque = false
}
override func draw(_ rect: CGRect) {
backgroundColor?.setFill()
UIRectFill(rect)
guard let rectsArray = holes else { return }
for holeRect in rectsArray {
let holeRectIntersection = rect.intersection(holeRect)
UIColor.clear.setFill()
UIRectFill(holeRectIntersection)
}
}
}
UtilityToolbar.swift
import Foundation import UIKit import SnapKit
class UtilityToolbar: UIView {
class Button: UIButton {
var functionIdentifier: String?
var buttonPressed: (() -> Void)?
fileprivate var owner: UtilityToolbar?
convenience init(title: String, buttonPressed: (() -> Void)?) {
self.init(type: .custom)
self.setTitle(title, for: .normal)
self.functionIdentifier = title.lowercased()
self.buttonPressed = buttonPressed
}
}
enum MenuState {
case open
case closed
}
enum TitleStyle {
case label
case dropdown
}
private(set) public var menuState: MenuState = .closed
var itemHeight: CGFloat = 50.0
var spacing: CGFloat = 6.0 { didSet { dropdownStackView.spacing = spacing } }
var duration: TimeInterval = 0.15
var dropdownContainer: UIView!
var titleButton: UIButton = UIButton()
#IBOutlet weak fileprivate var toolbarStackView: UIStackView!
private var stackViewBottomConstraint: Constraint!
private var dropdownStackView: UIStackView!
private var overlayView: CutoutView!
private var menuItems: [Button] = []
private var expandedHeight: CGFloat { get { return CGFloat(menuItems.count - 1) * itemHeight + (spacing * 2) } }
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
convenience init(title: String, menuItems: [Button]) {
self.init()
self.titleButton.setTitle(title, for: .normal)
self.menuItems = menuItems
commonInit()
}
private func commonInit() {
self.addSubview(titleButton)
titleButton.addTarget(self, action: #selector(titleButtonPressed(_:)), for: .touchUpInside)
titleButton.snp.makeConstraints { $0.edges.equalToSuperview() }
dropdownContainer = UIView()
dropdownStackView = UIStackView()
dropdownStackView.axis = .vertical
dropdownStackView.distribution = .fillEqually
dropdownStackView.alignment = .fill
dropdownStackView.spacing = spacing
dropdownStackView.alpha = 0
dropdownStackView.translatesAutoresizingMaskIntoConstraints = true
menuItems.forEach({
$0.owner = self
$0.addTarget(self, action: #selector(menuButtonPressed(_:)), for: .touchUpInside)
})
}
override func layoutSubviews() {
super.layoutSubviews()
// Block if the view isn't fully ready, or if the containerView has already been added to the window
guard
let keyWindow = UIApplication.shared.keyWindow,
self.globalFrame != .zero,
dropdownContainer.superview == nil else { return }
overlayView = CutoutView(frame: keyWindow.frame)
overlayView.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0.5)
overlayView.alpha = 0
overlayView.holes = [self.globalFrame!]
keyWindow.addSubview(overlayView)
keyWindow.addSubview(dropdownContainer)
dropdownContainer.snp.makeConstraints { (make) in
make.left.right.equalToSuperview()
make.top.equalToSuperview().offset((self.globalFrame?.origin.y ?? 0) + self.frame.height)
make.height.equalTo(0)
}
dropdownContainer.addSubview(dropdownStackView)
dropdownStackView.snp.makeConstraints({ (make) in
make.left.right.equalToSuperview().inset(spacing).priority(.required)
make.top.equalToSuperview().priority(.medium)
stackViewBottomConstraint = make.bottom.equalToSuperview().priority(.medium).constraint
})
}
public func openMenu() {
titleButton.isSelected = true
dropdownStackView.addArrangedSubviews(menuItems.filter { $0.titleLabel?.text != titleButton.titleLabel?.text })
dropdownContainer.layoutIfNeeded()
dropdownContainer.snp.updateConstraints { (make) in
make.height.equalTo(self.expandedHeight)
}
stackViewBottomConstraint.update(inset: spacing)
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: .curveEaseOut, animations: {
self.overlayView.alpha = 1
self.dropdownStackView.alpha = 1
self.dropdownContainer.superview?.layoutIfNeeded()
}) { (done) in
self.menuState = .open
}
}
public func closeMenu() {
titleButton.isSelected = false
dropdownContainer.snp.updateConstraints { (make) in
make.height.equalTo(0)
}
stackViewBottomConstraint.update(inset: 0)
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: .curveEaseOut, animations: {
self.overlayView.alpha = 0
self.dropdownStackView.alpha = 0
self.dropdownContainer.superview?.layoutIfNeeded()
}) { (done) in
self.menuState = .closed
self.dropdownStackView.removeAllArrangedSubviews()
}
}
#objc private func titleButtonPressed(_ sender: Button) {
switch menuState {
case .open:
closeMenu()
case .closed:
openMenu()
}
}
#objc private func menuButtonPressed(_ sender: Button) {
closeMenu()
}
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
// Nothing of interest is happening here unless the touch is inside the containerView
print(UIColor.colorOfPoint(point: point, in: overlayView).cgColor.alpha > 0)
if UIColor.colorOfPoint(point: point, in: overlayView).cgColor.alpha > 0 {
return true
}
return super.point(inside: point, with: event)
} }
Extensions.swift
import UIKit
extension UIWindow {
static var topController: UIViewController? {
get {
guard var topController = UIApplication.shared.keyWindow?.rootViewController else { return nil }
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
return topController
}
}
}
public extension UIView {
var globalPoint: CGPoint? {
return self.superview?.convert(self.frame.origin, to: nil)
}
var globalFrame: CGRect? {
return self.superview?.convert(self.frame, to: nil)
}
}
extension UIColor {
static func colorOfPoint(point:CGPoint, in view: UIView) -> UIColor {
var pixel: [CUnsignedChar] = [0, 0, 0, 0]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
let context = CGContext(data: &pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
context!.translateBy(x: -point.x, y: -point.y)
view.layer.render(in: context!)
let red: CGFloat = CGFloat(pixel[0]) / 255.0
let green: CGFloat = CGFloat(pixel[1]) / 255.0
let blue: CGFloat = CGFloat(pixel[2]) / 255.0
let alpha: CGFloat = CGFloat(pixel[3]) / 255.0
let color = UIColor(red:red, green: green, blue:blue, alpha:alpha)
return color
}
}
extension UIStackView {
func addArrangedSubviews(_ views: [UIView?]) {
views.filter({$0 != nil}).forEach({ self.addArrangedSubview($0!)})
}
func removeAllArrangedSubviews() {
let removedSubviews = arrangedSubviews.reduce([]) { (allSubviews, subview) -> [UIView] in
self.removeArrangedSubview(subview)
return allSubviews + [subview]
}
// Deactivate all constraints
NSLayoutConstraint.deactivate(removedSubviews.flatMap({ $0.constraints }))
// Remove the views from self
removedSubviews.forEach({ $0.removeFromSuperview() })
}
}
Silly me, I need to put the hitTest on the overlay view (CutoutView) not the calling view.
class CutoutView: UIView {
// ...
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard UIColor.colorOfPoint(point: point, in: self).cgColor.alpha > 0 else { return nil }
return super.hitTest(point, with: event)
}
}

Globally apply a gradient to the navigation bar and handle orientation changes

I need to apply a gradient globally to my status and navigation bars and have it adjust properly to orientation changes. Because I want this to be global, I'm trying to use UIAppearance. Surprisingly, UIAppearance doesn't make this very easy.
It looks great in Portrait, but the gradient is too tall when in Landscape so you can't see the whole thing:
Here's my code to this point:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let navigationBarAppearance = UINavigationBar.appearance()
navigationBarAppearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
navigationBarAppearance.isTranslucent = false
navigationBarAppearance.tintColor = UIColor.white
let status_height = UIApplication.shared.statusBarFrame.size.height
let gradientLayer = CAGradientLayer(frame: CGRect(x: 0, y: 0, width: 64, height: status_height + 44), colors: [UIColor.init(hex: "005382"), UIColor.init(hex: "00294B")])
let layerImage = gradientLayer.createGradientImage()
navigationBarAppearance.barTintColor = UIColor(patternImage: layerImage ?? UIImage())
}
and I'm using this extension:
extension CAGradientLayer {
convenience init(frame: CGRect, colors: [UIColor]) {
self.init()
self.frame = frame
self.colors = []
for color in colors {
self.colors?.append(color.cgColor)
}
startPoint = CGPoint(x: 0, y: 0)
endPoint = CGPoint(x: 0, y: 1)
}
func createGradientImage() -> UIImage? {
var image: UIImage? = nil
UIGraphicsBeginImageContext(bounds.size)
if let context = UIGraphicsGetCurrentContext() {
render(in: context)
image = UIGraphicsGetImageFromCurrentImageContext()
}
UIGraphicsEndImageContext()
return image
}
}
I know I could check the orientation and then change the gradient accordingly but I'd need to do that on every view controller so that would defeat the purpose of using UIAppearance and being able to do it in one place.
Most of the SO threads I've found provide solutions for making the top bar's gradient at the view controller level, but not the global level.
EDIT:
Tried answer from #Pan Surakami on my UITabBarController but I still have white navigation bars:
Here's my storybaord setup:
And code:
class MenuTabBarController: UITabBarController {
var notificationsVM = NotificationsVModel()
var hasNewAlerts: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
setTabs()
styleUI()
notificationsVM.fetchData { (success, newNotifications) in
if success {
self.hasNewAlerts = newNotifications.count > 0 ? true : false
DispatchQueue.main.async {
if let tabBarItems = self.tabBar.items {
for (_, each) in tabBarItems.enumerated() {
if each.tag == 999 { //only update the alerts tabBarItem tag == '999'
self.updateAlertBadgeIcon(self.hasNewAlerts, each)
}
}
}
}
}
}
}
fileprivate func setTabs() {
let tab1 = GradientNavigationController(rootViewController: FeedViewController())
let tab2 = GradientNavigationController(rootViewController: NotificationsTableViewController())
let tab3 = GradientNavigationController(rootViewController: SearchViewController())
let tab4 = GradientNavigationController(rootViewController: ComposeDiscussionViewController())
UITabBarController().setViewControllers([tab1, tab2, tab3, tab4], animated: false)
}
func updateAlertBadgeIcon(_ hasAlerts: Bool, _ item: UITabBarItem) {
if hasAlerts {
item.image = UIImage(named: "alert-unselected-hasAlerts")?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
item.selectedImage = UIImage(named: "alert-selected-hasAlerts")?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
} else {
hasNewAlerts = false
item.image = UIImage(named: "alert-unselected-noAlerts")?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
item.selectedImage = UIImage(named: "alert-selected-noAlerts")?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
}
}
// UITabBarDelegate
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
if item.tag == 999 { //alerts tabBarItem tag == '999'
updateAlertBadgeIcon(hasNewAlerts, item)
}
if item.tag == 0 { //Feed Item clicked
if let feedNav = children[0] as? UINavigationController, let feedVC = feedNav.viewControllers[0] as? FeedViewController {
feedVC.tableView.reloadData()
}
}
}
func styleUI() {
UITabBar.appearance().backgroundImage = UIImage.colorForNavBar(color:.lightGrey4)
UITabBar.appearance().shadowImage = UIImage.colorForNavBar(color:.clear)
tabBar.layer.shadowOffset = CGSize.zero
tabBar.layer.shadowRadius = 2.0
tabBar.layer.shadowColor = UIColor.black.cgColor
tabBar.layer.shadowOpacity = 0.30
UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor : UIColor.grey2,
NSAttributedString.Key.font: UIFont(name: "AvenirNext-DemiBold", size: 12) as Any],
for: .normal)
UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor : UIColor.darkSapphire,
NSAttributedString.Key.font: UIFont(name: "AvenirNext-DemiBold", size: 12) as Any],
for: .selected)
}
}
One way to implement it is to subclass UINavigationController.
Create a new subclass.
class GradientNavigationController: UINavigationController {}
Override traitCollectionDidChange method.
class GradientNavigationController: UINavigationController {
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
let status_height = UIApplication.shared.statusBarFrame.size.height
let gradientLayer = CAGradientLayer(frame: CGRect(x: 0, y: 0, width: 64, height: status_height + 44), colors: [[UIColor.init(hex: "005382"), UIColor.init(hex: "00294B")])
let layerImage = gradientLayer.createGradientImage()
self.navigationBar.barTintColor = UIColor(patternImage: layerImage ?? UIImage())
}
}
Use this subclass instead of UINavigationController. Either change custom subclass on storiboards or use it in code.
EDIT:
Your UITabBarController is configured by the storyboard. So setTabs() used this way has no sense. It just creates another copy of UITabBarController and then removes it. I showed it just as an example of embedding controllers.
Remove the method setTabs().
Open each storyboard which is linked to your tabs.
(I cannot see how they are actually configured they are behind storyboard references.)
Make sure that an initial controller is GradientNavigationController.
enter image description here

UITabbar Image Not Updating

i want to update image of uitabbar programmatically but it's not updating when i update the image
looks duplicate ???
here is the answer i already tried but no success
UITabBarItem does not update image
UITabBar not showing selected item images in ios 7
how to programmatically change the tabbarItem's image
https://www.appcoda.com/ios-programming-how-to-customize-tab-bar-background-appearance/
Changing tab bar item image and text color iOS
okay now here is my code for customTabbar
// CustomTabBarViewController.swift
// CustomTabBar
import UIKit
class CustomTabBarViewController: UITabBarController, CustomTabBarDataSource, CustomTabBarDelegate, UITabBarControllerDelegate , UISearchBarDelegate, UISearchDisplayDelegate {
var searchController: UISearchController!
let searchBar = UISearchBar()
var btnBarBadge : MJBadgeBarButton!
var btnBar : MJBadgeBarButton!
// #IBOutlet weak var menuButton: UIBarButtonItem!
// MARK: Properties
var meals = [CatModel]()
func onBagdeButtonClick() {
print("button Clicked \(self.btnBarBadge.badgeValue)")
}
func onBarCodeButtonClick() {
self.title = Localization("Categories")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let subContentsVC = storyboard.instantiateViewController(withIdentifier: "Stores") as! Stores
self.navigationController?.pushViewController(subContentsVC, animated: true)
}
func buttonClicked(_ sender: AnyObject?) {
var countt = Int(Constants.cartCount)
if(countt == nil){
countt = 0
}
if(countt!<1){
let alert = UIAlertController(title: Localization("Warning"), message:Localization("YourCartisEmpty"), preferredStyle: .alert)
alert.addAction(UIAlertAction(title: Localization("Ok"), style: .default) { _ in })
self.present(alert, animated: true){}
}else{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let subContentsVC = storyboard.instantiateViewController(withIdentifier: "Cart") as! Cart
self.navigationController?.pushViewController(subContentsVC, animated: true)
}
}
func searchBarSearchButtonClicked( _ searchBar: UISearchBar)
{
print(searchBar.text ?? "this is value")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let subContentsVC = storyboard.instantiateViewController(withIdentifier: "SearchProduct") as! SearchProduct
subContentsVC.stringPassed = searchBar.text!
self.navigationController?.pushViewController(subContentsVC, animated: true)
}
func actOnSpecialNotificationon() {
searchBar.placeholder = Localization("Search")
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.tabBar.isHidden = true
self.selectedIndex = 1
self.delegate = self
searchBar.sizeToFit()
searchBar.delegate = self
self.title = Localization("Categories")
searchBar.placeholder = Localization("Search")
searchBar.tintColor = .black
navigationItem.titleView = searchBar
NotificationCenter.default.addObserver(self, selector: #selector(CustomTabBarViewController.actOnSpecialNotificationon), name: NSNotification.Name(rawValue: mySpecialNotificationKey), object: nil)
let customTabBar = CustomTabBar(frame: self.tabBar.frame)
customTabBar.datasource = self
customTabBar.delegate = self
customTabBar.setup()
self.view.addSubview(customTabBar)
let customButton = UIButton(type: UIButtonType.custom)
customButton.frame = CGRect(x: 0, y: 0, width: 5.0, height: 35.0)
customButton.addTarget(self, action: #selector(self.onBagdeButtonClick), for: .touchUpInside)
customButton.setImage(UIImage(named: "Cart"), for: .normal)
let barcodeButton = UIButton(type: UIButtonType.custom)
barcodeButton.frame = CGRect(x: 0, y: 0, width: 35.0, height: 35.0)
barcodeButton.addTarget(self, action: #selector(self.onBarCodeButtonClick), for: .touchUpInside)
barcodeButton.setImage(UIImage(named: "edit_location"), for: .normal)
self.btnBarBadge = MJBadgeBarButton()
self.btnBar = MJBadgeBarButton()
self.btnBarBadge.setup(customButton: customButton)
self.btnBarBadge.removeBadge()
self.btnBar.setup(customButton: barcodeButton)
self.btnBar.removeBadge()
self.btnBarBadge.badgeValue = "0"
self.btnBarBadge.badgeOriginX = 2.0
self.btnBarBadge.badgeOriginY = -4
self.navigationItem.rightBarButtonItem = self.btnBarBadge
self.navigationItem.rightBarButtonItems = [self.btnBarBadge,self.btnBar]
customButton.addTarget(self, action: #selector(CustomTabBarViewController.buttonClicked(_:)), for: .touchUpInside)
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.setNavigationBarItem()
self.btnBarBadge.badgeValue = Constants.cartCount
}
// MARK: - CustomTabBarDataSource
func tabBarItemsInCustomTabBar(_ tabBarView: CustomTabBar) -> [UITabBarItem] {
return tabBar.items!
}
// MARK: - CustomTabBarDelegate
func didSelectViewController(_ tabBarView: CustomTabBar, atIndex index: Int) {
if(index == 0){
self.openLeftMenu()
}else{
self.selectedIndex = index
}
for loop in 0..<(self.tabBar.items?.count)!{
let barbutton = self.tabBar.items![loop]
if(index == loop){
barbutton.image = self.updateImageColor(origImage: barbutton.image!, color: .green)
}else{
barbutton.image = self.updateImageColor(origImage: barbutton.image!, color: .lightGray)
}
}
}
func updateImageColor(origImage:UIImage,color:UIColor)->UIImage{
let tintedImage = origImage.withRenderingMode(.alwaysOriginal)
let imageview = UIImageView(image: tintedImage)
imageview.tintColor = color
return imageview.image!
}
// MARK: - UITabBarControllerDelegate
func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return CustomTabAnimatedTransitioning()
}
}
here is the code for CustomTabBar.swift
//
// CustomTabBar.swift
// CustomTabBar
//
import UIKit
protocol CustomTabBarDataSource {
func tabBarItemsInCustomTabBar(_ tabBarView: CustomTabBar) -> [UITabBarItem]
}
protocol CustomTabBarDelegate {
func didSelectViewController(_ tabBarView: CustomTabBar, atIndex index: Int)
}
class CustomTabBar: UIView {
var datasource: CustomTabBarDataSource!
var delegate: CustomTabBarDelegate!
var tabBarItems: [UITabBarItem]!
var customTabBarItems: [CustomTabBarItem]!
var tabBarButtons: [UIButton]!
var initialTabBarItemIndex: Int!
var selectedTabBarItemIndex: Int!
var slideMaskDelay: Double!
var slideAnimationDuration: Double!
var tabBarItemWidth: CGFloat!
var leftMask: UIView!
var rightMask: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.white
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup() {
// get tab bar items from default tab bar
tabBarItems = datasource.tabBarItemsInCustomTabBar(self)
customTabBarItems = []
tabBarButtons = []
initialTabBarItemIndex = 1
selectedTabBarItemIndex = initialTabBarItemIndex
slideAnimationDuration = 0.6
slideMaskDelay = slideAnimationDuration / 2
let containers = createTabBarItemContainers()
createTabBarItemSelectionOverlay(containers)
createTabBarItemSelectionOverlayMask(containers)
createTabBarItems(containers)
}
func createTabBarItemSelectionOverlay(_ containers: [CGRect]) {
let activeColor = UIColor(red: 109/255, green: 187/255, blue: 16/255, alpha: 1.0)
let overlayColors = [activeColor, activeColor, activeColor, activeColor,activeColor]
for index in 0..<tabBarItems.count {
let container = containers[index]
let view = UIView(frame: container)
let selectedItemOverlay = UIView(frame: CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height))
selectedItemOverlay.backgroundColor = overlayColors[index] //.clear
view.addSubview(selectedItemOverlay)
tabBarItems[index].selectedImage = updateImageColor(origImage: tabBarItems[index].image!, color: .green)
self.addSubview(view)
}
}
func updateImageColor(origImage:UIImage,color:UIColor)->UIImage{
let tintedImage = origImage.withRenderingMode(.alwaysTemplate)
let imageview = UIImageView(image: tintedImage)
imageview.tintColor = color
return imageview.image!
}
func createTabBarItemSelectionOverlayMask(_ containers: [CGRect]) {
tabBarItemWidth = self.frame.width / CGFloat(tabBarItems.count)
let leftOverlaySlidingMultiplier = CGFloat(initialTabBarItemIndex) * tabBarItemWidth
let rightOverlaySlidingMultiplier = CGFloat(initialTabBarItemIndex + 1) * tabBarItemWidth
leftMask = UIView(frame: CGRect(x: 0, y: 0, width: leftOverlaySlidingMultiplier, height: self.frame.height))
leftMask.backgroundColor = UIColor.white
rightMask = UIView(frame: CGRect(x: rightOverlaySlidingMultiplier, y: 0, width: tabBarItemWidth * CGFloat(tabBarItems.count - 1), height: self.frame.height))
rightMask.backgroundColor = UIColor.white
self.addSubview(leftMask)
self.addSubview(rightMask)
}
func createTabBarItems(_ containers: [CGRect]) {
var index = 0
for item in tabBarItems {
let container = containers[index]
let customTabBarItem = CustomTabBarItem(frame: container)
customTabBarItem.setup(item)
self.addSubview(customTabBarItem)
customTabBarItems.append(customTabBarItem)
let button = UIButton(frame: CGRect(x: 0, y: 0, width: container.width, height: container.height))
button.addTarget(self, action: #selector(CustomTabBar.barItemTapped(_:)), for: UIControlEvents.touchUpInside)
customTabBarItem.addSubview(button)
tabBarButtons.append(button)
index += 1
}
self.customTabBarItems[initialTabBarItemIndex].iconView.tintColor = .green //UIColor.white
}
func createTabBarItemContainers() -> [CGRect] {
var containerArray = [CGRect]()
// create container for each tab bar item
for index in 0..<tabBarItems.count {
let tabBarContainer = createTabBarContainer(index)
containerArray.append(tabBarContainer)
}
return containerArray
}
func createTabBarContainer(_ index: Int) -> CGRect {
let tabBarContainerWidth = self.frame.width / CGFloat(tabBarItems.count)
let tabBarContainerRect = CGRect(x: tabBarContainerWidth * CGFloat(index), y: 0, width: tabBarContainerWidth, height: self.frame.height)
return tabBarContainerRect
}
func animateTabBarSelection(from: Int, to: Int) {
let overlaySlidingMultiplier = CGFloat(to - from) * tabBarItemWidth
let leftMaskDelay: Double
let rightMaskDelay: Double
if overlaySlidingMultiplier > 0 {
leftMaskDelay = slideMaskDelay
rightMaskDelay = 0
}
else {
leftMaskDelay = 0
rightMaskDelay = slideMaskDelay
}
UIView.animate(withDuration: slideAnimationDuration - leftMaskDelay, delay: leftMaskDelay, options: UIViewAnimationOptions(), animations: {
self.leftMask.frame.size.width += overlaySlidingMultiplier
}, completion: nil)
UIView.animate(withDuration: slideAnimationDuration - rightMaskDelay, delay: rightMaskDelay, options: UIViewAnimationOptions(), animations: {
self.rightMask.frame.origin.x += overlaySlidingMultiplier
self.rightMask.frame.size.width += -overlaySlidingMultiplier
self.customTabBarItems[from].iconView.tintColor = UIColor.black
self.customTabBarItems[to].iconView.tintColor = UIColor.white
}, completion: nil)
}
func barItemTapped(_ sender : UIButton) {
let index = tabBarButtons.index(of: sender)!
//tabBarItems[index].selectedImage = nil
//tabBarItems[index].image = nil
// tabBarItems[index].image = UIImage(named: "Home_Tab");
animateTabBarSelection(from: selectedTabBarItemIndex, to: index)
selectedTabBarItemIndex = index
delegate.didSelectViewController(self, atIndex: index)
}
}
when i try changing image nothing happen
tabBarItems[index].image = UIImage(named: "Home_Tab")
tabBarItems[index].image = UIImage(named: "Home_Tab")?.withRenderingMode(.alwaysOriginal)
Same for selected image
it works when i set image in createTabBarItemSelectionOverlay method
i tried removing image and setting it again but no success
also tried to set image with .alwaysOriginal render mode no luck
please help where am i doing wrong ??
Thank you...little help will be appriciated

ViewController does not conform to protocol on Swift

I'm having an issue with calling a delegate in my class. I have a SideBarTableController and SideBar.swift file.It was working fine until I logged off and back in. Here is the code. It keeps telling me that 'ViewController' does not conform to protocol 'SideBarDelegate'. I'm new to programming so sorry in advance if this is vague. Anything will help thanks!
import UIKit
import iAd
class ViewController: UIViewController, SideBarDelegate { -----This is where the error is happening
#IBOutlet var menuTab: UIButton! // Menu Tab
#IBOutlet var businessButton: UIButton! // Business Button
#IBOutlet var adBanner: ADBannerView! // Banner Ad
#IBOutlet var imageView: UIImageView! // Main Image in middle
var topHeader: UIImageView! // Utility header
var sideBar:SideBar = SideBar() // Side Bar
override func viewDidLoad() {
super.viewDidLoad()
// Function for menu
// menuTab.addTarget(self, action: "buttonPressed", forControlEvents: UIControlEvents.TouchUpInside)
func menuTab(sender: UIButton){
sideBar = SideBar(sourceView: self.view, menuItems: ["Home", "Business Directory", "Classifieds", "Featured News", "Jobs", "Restaurants", "Sports"])
sideBar.delegate = self }
// Gives the screen dimensions
let screenSize: CGRect = UIScreen.mainScreen().bounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height
// Side bar action and text
sideBar = SideBar(sourceView: self.view, menuItems: ["Home", "Business Directory", "Classifieds", "Featured News", "Jobs", "Restaurants", "Sports"])
sideBar.delegate = self
// Utility Background
var topHeader = UIView(frame: CGRectMake(0, 0, screenWidth, 17))
topHeader.backgroundColor = UIColor(white: 0.0, alpha: 1.0)
self.view.addSubview(topHeader)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// Side Bar funcion
func sideBarDidSelectButtonAtIndex(index: Int) {
if index == 0{
imageView.backgroundColor = UIColor.redColor()
imageView.image = nil
} else if index == 1{
imageView.backgroundColor = UIColor.clearColor()
imageView.image = UIImage(named: "image2")
}
}
// Status bar style (white)
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return UIStatusBarStyle.LightContent
}
}
Here is where I called the SideBarDelegate
import UIKit
#objc protocol SideBarDelegate{
func sideBarDidSelectButtonAtIndex(index:Int)
func sideBarWillClose()
func sideBarWillOpen()
}
class SideBar: NSObject, SideBarTableViewControllerDelegate {
let barWidth:CGFloat = 176.0
let sideBarTableViewTopInset:CGFloat = 64.0
let sideBarContainerView:UIView = UIView()
let sideBarTableViewController:SideBarTableViewController = SideBarTableViewController()
let originView:UIView!
var animator:UIDynamicAnimator!
var delegate:SideBarDelegate?
var isSideBarOpen:Bool = false
override init() {
super.init()
}
init(sourceView:UIView, menuItems:Array<String>){
super.init()
originView = sourceView
sideBarTableViewController.tableData = menuItems
setupSideBar()
animator = UIDynamicAnimator(referenceView: originView)
let showGestureRecognizer:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "handleSwipe:")
showGestureRecognizer.direction = UISwipeGestureRecognizerDirection.Right
originView.addGestureRecognizer(showGestureRecognizer)
let hideGestureRecognizer:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "handleSwipe:")
hideGestureRecognizer.direction = UISwipeGestureRecognizerDirection.Left
originView.addGestureRecognizer(hideGestureRecognizer)
}
func setupSideBar(){
sideBarContainerView.frame = CGRectMake(-barWidth - 1, originView.frame.origin.y, barWidth, originView.frame.size.height)
sideBarContainerView.backgroundColor = UIColor.clearColor()
sideBarContainerView.clipsToBounds = false
originView.addSubview(sideBarContainerView)
let blurView:UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.Light))
blurView.frame = sideBarContainerView.bounds
sideBarContainerView.addSubview(blurView)
sideBarTableViewController.delegate = self
sideBarTableViewController.tableView.frame = sideBarContainerView.bounds
sideBarTableViewController.tableView.clipsToBounds = false
sideBarTableViewController.tableView.separatorStyle = UITableViewCellSeparatorStyle.None
sideBarTableViewController.tableView.backgroundColor = UIColor.clearColor()
sideBarTableViewController.tableView.scrollsToTop = false
sideBarTableViewController.tableView.contentInset = UIEdgeInsetsMake(sideBarTableViewTopInset, 0, 0, 0)
sideBarTableViewController.tableView.reloadData()
sideBarContainerView.addSubview(sideBarTableViewController.tableView)
}
func handleSwipe(recognizer:UISwipeGestureRecognizer){
if recognizer.direction == UISwipeGestureRecognizerDirection.Left{
showSideBar(false)
delegate?.sideBarWillClose()
}else{
showSideBar(true)
delegate?.sideBarWillOpen()
}
}
func showSideBar(shouldOpen:Bool){
animator.removeAllBehaviors()
isSideBarOpen = shouldOpen
let gravityX:CGFloat = (shouldOpen) ? 0.5 : -0.5
let magnitude:CGFloat = (shouldOpen) ? 20 : -20
let boundaryX:CGFloat = (shouldOpen) ? barWidth : -barWidth - 1
let gravityBehavior:UIGravityBehavior = UIGravityBehavior(items: [sideBarContainerView])
gravityBehavior.gravityDirection = CGVectorMake(gravityX, 0)
animator.addBehavior(gravityBehavior)
let collisionBehavior:UICollisionBehavior = UICollisionBehavior(items: [sideBarContainerView])
collisionBehavior.addBoundaryWithIdentifier("sideBarBoundary", fromPoint: CGPointMake(boundaryX, 20), toPoint: CGPointMake(boundaryX, originView.frame.size.height))
animator.addBehavior(collisionBehavior)
let pushBehavior:UIPushBehavior = UIPushBehavior(items: [sideBarContainerView], mode: UIPushBehaviorMode.Instantaneous)
pushBehavior.magnitude = magnitude
animator.addBehavior(pushBehavior)
let sideBarBehavior:UIDynamicItemBehavior = UIDynamicItemBehavior(items: [sideBarContainerView])
sideBarBehavior.elasticity = 0.3
animator.addBehavior(sideBarBehavior)
}
func sideBarControlDidSelectRow(indexPath: NSIndexPath) {
delegate?.sideBarDidSelectButtonAtIndex(indexPath.row)
}
}
Your SideBarDelegate protocol specifies some methods that must be implemented in order to conform to that protocol. So look at the definition of that protocol, identify what methods are defined therein, and then implement them in your ViewController class.
It's possible you missed one of the functions defined in that protocol, or perhaps you mistyped something in the definition of sideBarDidSelectButtonAtIndex. We cannot say without seeing the definition of this protocol.
Update:
You subsequently supplied the definition of your protocol. It defines two additional functions that you have not implemented in your view controller:
func sideBarWillClose()
func sideBarWillOpen()
You also must implement these two functions in your view controller (even if you put nothing into them).

Resources