使用数组堆栈并在UIViewControllers之间设置动画会产生意外的行为

时间:2018-12-12 02:43:36

标签: ios swift uiviewcontroller

使用Swift 4和Xcode 10.1

我的目标是在我对它们进行动画处理时,使用数组堆栈来跟踪我的UIViewController。 我已经大部分工作了,但是当我第二次将ViewController转换为视图时,它似乎与下面的当前视图控制器交换了位置。

基本设置(故事板)是一个UIViewController,它具有一个ContainerView(MainContainer)和4个单独的ViewController(VC1,VC2,VC3,VC4)。每个VC都有一个restoreId,以便我可以打印它并跟踪堆栈数组中的位置。

首先显示VC1,然后使用按钮测试每个VC的处理。

代码如下:

@IBOutlet weak var MainContainer: UIView!    
var vc1:UIViewController!
var vc2:UIViewController!
var vc3:UIViewController!
var vc4:UIViewController!
var vcStack = Stack<UIViewController>()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    vc1 = self.storyboard?.instantiateViewController(withIdentifier: "VC1")
    vc2 = self.storyboard?.instantiateViewController(withIdentifier: "VC2")
    vc3 = self.storyboard?.instantiateViewController(withIdentifier: "VC3")
    vc4 = self.storyboard?.instantiateViewController(withIdentifier: "VC4")

    vcStack.push(vc1)
    displayVC(content: vc1!)
}

func displayVC(content: UIViewController) {
    // Works to change VCs - no transition
    self.addChild(content)
    content.view.translatesAutoresizingMaskIntoConstraints = false
    self.MainContainer.addSubview(content.view)

    NSLayoutConstraint.activate([
        content.view.leftAnchor.constraint(equalTo: self.MainContainer.leftAnchor, constant: 0),
        content.view.topAnchor.constraint(equalTo: self.MainContainer.topAnchor, constant: 0),
        content.view.bottomAnchor.constraint(equalTo: self.MainContainer.bottomAnchor, constant: 0),
        content.view.rightAnchor.constraint(equalTo: self.MainContainer.rightAnchor, constant: 0)
        ])

    content.didMove(toParent: self)
}

func slideINTransition(newVC: UIViewController){
    print("slide IN stack newVC: \(newVC.restorationIdentifier ?? "novalue")")
    print("slide IN stack stack top: \(vcStack.top!.restorationIdentifier ?? "novalue")")
    newVC.view.frame = vcStack.top!.view.frame;
    vcStack.top!.view.superview?.insertSubview(newVC.view, aboveSubview: vcStack.top!.view)
    newVC.view.transform = CGAffineTransform(translationX: vcStack.top!.view.frame.size.width, y: 0)

    UIView.animate(withDuration: 0.5,
                   delay: 0.0,
                   options: UIView.AnimationOptions.curveEaseInOut,
                   animations: {
                    newVC.view.transform = CGAffineTransform(translationX: 0, y: 0)
                  },
                   completion:nil// { finished in
                    //self.vcStack.top!.present(newVC, animated: false, completion: nil) //throws an error when uncommented
                //}
                  )
    vcStack.push(newVC)
    for junk in vcStack.array{
        print("slide IN stack: \(junk.restorationIdentifier ?? "novalue")")
    }
}
@IBAction func But_Back_Pressed(_ sender: UIButton) {
    for junk in vcStack.array{
        print("-----back but stack: \(junk.restorationIdentifier ?? "novalue")")
    }
    slideOUTTransition()
}
func slideOUTTransition(){
    print("slideOUT count: \(vcStack.count)")
    if (vcStack.count > 1) {
        let visibleVC = vcStack.pop()
        visibleVC!.view.transform = CGAffineTransform(translationX: 0, y: 0)
        UIView.animate(withDuration: 0.5,
                       delay: 0.0,
                       options: UIView.AnimationOptions.curveEaseInOut,
                       animations: {
                        visibleVC!.view.transform = CGAffineTransform(translationX: visibleVC!.view.frame.size.width, y: 0)
                       },
                       completion: { finished in
                        visibleVC!.dismiss(animated: false, completion: nil)
                       }
                       )
        for junk in vcStack.array{
            print("slideOUT stack: \(junk.restorationIdentifier ?? "novalue")")
        }
        print("BACK pop count: \(vcStack.count)")
    }
}

@IBAction func But_VC1_Pressed(_ sender: UIButton) {
    if vcStack.hasElement(vc1){
        print("Trans vc1 exists - doing nothing")
    }else{
        print("Trans vc1 unique")
        slideINTransition(newVC: vc1)
    }
}
@IBAction func But_VC2_Pressed(_ sender: UIButton) {
    if vcStack.hasElement(vc2){
        print("Trans vc2 exists - doing nothing")
    }else{
        print("Trans vc2 unique")
        slideINTransition(newVC: vc2)
    }
}
@IBAction func But_VC3_Pressed(_ sender: UIButton) {
    if vcStack.hasElement(vc3){
        print("Trans vc3 exists - doing nothing")
    }else{
        print("Trans vc3 unique")
        slideINTransition(newVC: vc3)
    }
}
@IBAction func But_VC4_Pressed(_ sender: UIButton) {
    if vcStack.hasElement(vc4){
        print("Trans vc4 exists - doing nothing")
    }else{
        print("Trans vc4 unique")
        slideINTransition(newVC: vc4)
    }
}

public struct Stack<T> where T: Equatable {
    fileprivate var array = [T]()

    public var isEmpty: Bool {
        return array.isEmpty
    }

    public var count: Int {
        return array.count
    }

    public mutating func push(_ element: T) {
        array.append(element)
    }

    public mutating func pop() -> T? {
        return array.popLast()
    }

    public func hasElement(_ element: T) -> Bool {
        return array.contains(element)
    }

    public var top: T? {
        return array.last
    }
}

一个失败的简单测试:

通过单击VC2按钮添加VC2,它在VC1上从右向左滑动,并且VC2被压入堆栈。单击“后退”按钮以使VC2从左到右向后滑动,以再次显示VC1,并且VC2从堆栈中弹出。到目前为止,该方法有效-仅可见VC1。

但是,当我第二次单击VC2按钮时,它似乎与VC1交换位置。 VC1立即替换为VC2,然后VC1在顶部从左到右滑动。 动画之前,似乎已经交换了VC2和VC1。

还要注意-我可以将VC2,VC3和VC4相互推入,然后将它们推入堆栈,然后单击“上一步”将其从视图中删除,并且可以使用。但是,一旦再次推送任何vc,就会在下面的任何视图中进行交换。

我使用打印语句跟踪堆栈数组,它似乎正常工作。动画也可以正常工作,所以我在显示/添加VC的方式上一定做错了。...

有什么想法可以使每个VC动画化,然后将其删除,但又不能动画化?

1 个答案:

答案 0 :(得分:1)

我认为有很多事情可以使有关视图控制器的约束变得更好(没有违法!),但现在要解决您的问题,请执行以下操作:

与其在您的visibleVC!.dismiss(animated: false, completion: nil)的完成块中调用slideOUTTransition()(您没有提供任何内容,所以您不必消除任何内容),而是从超级视图中删除视图并重置其转换: / p>

// visibleVC!.dismiss(animated: false, completion: nil)
visibleVC!.view.removeFromSuperview()
visibleVC!.view.transform = .identity