ios - 模块化滑出容器 ViewController

标签 ios swift storyboard uikit

在关注精彩Ray Wenderlich tutorial ,我在我的应用程序中成功创建了一个滑出容器 View 。

我想将此 ContainerViewController 合并到我的应用程序的另一个位置,因此想将其模块化,以免将代码复制并粘贴到另一个 ViewController,但是我不知道该怎么做。

这是教程中的代码:

import UIKit
enum SlideOutState {
    case LeftPanelClosed
    case LeftPanelExpanded
}

class StudentContainerViewController: UIViewController {

    var centerNavigationController: UINavigationController!
    var centerViewController: SearchClassesTableViewController! // <--- Need to change this
    var currentState: SlideOutState = .LeftPanelClosed
    var leftViewController: StudentSettingsTableViewController? // <--- And this bad boy
    let centerPanelExpandedOffset: CGFloat = 60

    override func viewDidLoad() {
        super.viewDidLoad()
        centerViewController = UIStoryboard.centerViewController()
        centerViewController.delegate = self

        centerNavigationController = UINavigationController(rootViewController: centerViewController)
        view.addSubview(centerNavigationController.view)
        addChildViewController(centerNavigationController)

        centerNavigationController.didMove(toParentViewController: self)

        let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
        centerNavigationController.view.addGestureRecognizer(panGestureRecognizer)
    }
}

private extension UIStoryboard {
    class func mainStoryboard() -> UIStoryboard { return UIStoryboard(name: "Main", bundle: Bundle.main ) }

    class func leftViewController() -> StudentSettingsTableViewController? {
        return mainStoryboard().instantiateViewController(withIdentifier: "StudentSettingsTableViewController") as? StudentSettingsTableViewController
    }

    class func centerViewController() -> SearchClassesTableViewController? {
        return mainStoryboard().instantiateViewController(withIdentifier: "SearchClassesTableViewController") as? SearchClassesTableViewController
    }
}

extension StudentContainerViewController: CenterViewControllerDelegate {
    func toggleLeftPanel(){
        let notAlreadyExpanded = (currentState != .LeftPanelExpanded)
        if notAlreadyExpanded {
            addLeftPanelViewController()
        }
        animateLeftPanel(shouldExpand: notAlreadyExpanded)
    }

    func addLeftPanelViewController(){
        if leftViewController == nil {
            leftViewController = UIStoryboard.leftViewController()
            addChildSidePanelController(sidePanelController: leftViewController!)
        }
    }

    func addChildSidePanelController(sidePanelController: StudentSettingsTableViewController) {
        view.insertSubview(sidePanelController.view, at: 0)
        addChildViewController(sidePanelController)
        sidePanelController.didMove(toParentViewController: self)
    }

    func animateLeftPanel(shouldExpand: Bool){
        if shouldExpand {
            currentState = .LeftPanelExpanded
            animateCenterPanelXPosition(targetPosition: centerNavigationController.view.frame.width - centerPanelExpandedOffset)
        } else {
            animateCenterPanelXPosition(targetPosition: 0) {finished in
                self.currentState = .LeftPanelClosed
                self.leftViewController?.view.removeFromSuperview()
                self.leftViewController = nil
            }
        }
    }

    func animateCenterPanelXPosition(targetPosition: CGFloat, completion: ((Bool) -> Void)! = nil) {
        UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {
            self.centerNavigationController.view.frame.origin.x = targetPosition
        }, completion: completion)
    }

    func showShadowForCenterViewController(shouldShowShadow: Bool) {
        if shouldShowShadow {
            centerNavigationController.view.layer.shadowOpacity = 0.8
        } else {
            centerNavigationController.view.layer.shadowOpacity = 0.0
        }
    }
}

// MARK: Gesture Recognizer

extension StudentContainerViewController {
    func handlePanGesture(_ recognizer: UIPanGestureRecognizer) -> Void {
        let gestureIsDraggingFromLeftToRight = recognizer.velocity(in: view).x > 0

        switch recognizer.state {
        case .began:
            if currentState == .LeftPanelClosed {
                if gestureIsDraggingFromLeftToRight {
                    addLeftPanelViewController()
                }
                showShadowForCenterViewController(shouldShowShadow: true)
            }
        case .changed:
            if gestureIsDraggingFromLeftToRight || currentState == .LeftPanelExpanded {
                recognizer.view!.center.x = recognizer.view!.center.x + recognizer.translation(in: view).x
                recognizer.setTranslation(CGPoint.zero, in: view)
            }
        case .ended:
            if leftViewController != nil {
                let hasMovedMoreThanHalfway = recognizer.view!.center.x > view.bounds.size.width
                animateLeftPanel(shouldExpand: hasMovedMoreThanHalfway)
            }
        default:
            break
        }
    }
}

我需要能够交换 centerleftViewController 属性。我创建了一个父类(super class),然后在子类的 viewDidLoad 中设置了 centerleftViewControllers(见下文),但是这没有用该应用程序在 UIStoryboard 的扩展中中断,在 mainStoryBoard 类 func 中(也在下面显示)

父类(super class):

class SlideOutContainerViewController: UIViewController {

    var centerNavigationController: UINavigationController!
    var centerViewController: UIViewController?
    var currentState: SlideOutState = .LeftPanelClosed
    var leftViewController: UIViewController?
    let centerPanelExpandedOffset: CGFloat = 60


...same code as above...
}

和子类:

class StudentSlideOutContainerViewController: SlideOutContainerViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    centerViewController = SearchClassesTableViewController()
    leftViewController = StudentSettingsTableViewController()

        centerViewController = UIStoryboard.centerViewController() as! SearchClassesTableViewController
//        centerViewController.delegate = self

    centerNavigationController = UINavigationController(rootViewController: centerViewController!)
    view.addSubview(centerNavigationController.view)
    addChildViewController(centerNavigationController)

    centerNavigationController.didMove(toParentViewController: self)

    let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
    centerNavigationController.view.addGestureRecognizer(panGestureRecognizer)

    }
}

这是堆栈跟踪:

img1

EXC_BAD_ACCESS 换行符:

img2

我知道问题很多,而且解决问题的机会不大,但 StackOverflow 经常有神奇的方法....

最佳答案

你的问题是你的 Storyboard 协议(protocol)的实现,你正在递归地调用 leftViewControllercenterViewController 这两种方法,要求在 Storyboard中实例化名称,但正在调用 centerViewController 又是递归循环

我认为您需要将这些属性定义为类属性,或者在您的协议(protocol)中定义一个返回静态字符串值的方法,以避免递归调用

希望对你有帮助

关于ios - 模块化滑出容器 ViewController,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45666440/

相关文章:

objective-c - UIPickerView 在 ActionSheet 上的奇怪行为

ios - 应用程序创建了 Stripe 客户,但由于 "no such customer"而无法获取临时 key

ios - 如何在 Swift 2.2 中编写这些函数?

ios - UIScrollView 内部的 UICollectionView

ios - 如何在 iOS 中强制 UISearchBar 文本为大写

ios - ARC带 block 和保留周期

ios - 将字典发送到核心数据

ios - Swift Socket.io连接后立即发送的事件未执行

wpf - 使用XAML完成Storyboard时将元素的可见性设置为“折叠”

ios - 在 iOS 5 Storyboard 中,如何将新场景从 Popover 推送到原始 View Controller ?