jjzjj

ios - UIView 拆分过渡

coder 2024-01-14 原文

我很可能只是使用了错误的术语,但我一直在寻找是否有一个 iOS UIView 转换拆分一个 View (蓝色)和任何 subview 控件以显示另一个 View (红色) ) 及其控件。我发现有几篇文章提到了 2011 年的类似内容,但最近没有提及,所以想知道现在我们已经升级到 iOS 8 是否添加了任何新内容。任何指点将不胜感激。

最佳答案

如果您尝试进行这样的分割过渡,我已经为 View Controller 过渡创建了一个动画 Controller 。如果你看代码,你会发现可以有两种不同的方式进行中转,从中间打开from view或者toview出现并折叠在from view的顶部。

这是下面代码如何工作的小 gif;

class AnimationController: NSObject, UIViewControllerAnimatedTransitioning {

    let presenting: Bool

    init(presenting: Bool) {
        self.presenting = presenting
    }

    func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
        return 1.0
    }

    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
         animateOutImagesWithContext(transitionContext)
        //animateInImagesWithContext(transitionContext)
    }

    func snapshotView(view: UIView!) -> UIImage {
        UIGraphicsBeginImageContext(view.bounds.size)
        view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
        let snapshotImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return snapshotImage
    }

    func animateOutImagesWithContext(transitionContext:UIViewControllerContextTransitioning) {

        let containerView = transitionContext.containerView()

        let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
        let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)

        let fromView = fromViewController!.view
        let toView = toViewController!.view

        containerView.addSubview(toView)

        let snapshotImage = snapshotView(fromView)

        fromView.removeFromSuperview()

        let imageViews = animatingOutImageViews(snapshotImage)

        containerView.addSubview(imageViews.firstImageView)
        containerView.addSubview(imageViews.secondImageView)

      UIView.animateWithDuration(transitionDuration(transitionContext), animations: { () -> Void in
            let firstImageView = imageViews.firstImageView
            let secondImageView = imageViews.secondImageView

            if self.presenting {

                firstImageView.frame = CGRectOffset(firstImageView.frame, -CGRectGetWidth(firstImageView.frame), 0)
                secondImageView.frame = CGRectOffset(secondImageView.frame, CGRectGetWidth(secondImageView.frame), 0)                 
            } else {
                firstImageView.frame = CGRectOffset(firstImageView.frame, 0, -CGRectGetHeight(firstImageView.frame))
                secondImageView.frame = CGRectOffset(secondImageView.frame, 0, CGRectGetHeight(secondImageView.frame))

            }
            }) { (completed: Bool) -> Void in
                imageViews.firstImageView.removeFromSuperview()
                imageViews.secondImageView.removeFromSuperview()
            transitionContext.completeTransition(true)
        }

    }

    func animateInImagesWithContext(transitionContext:UIViewControllerContextTransitioning) {
        let containerView = transitionContext.containerView()

        let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
        let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)

        let fromView = fromViewController!.view
        let toView = toViewController!.view

        containerView.insertSubview(toView, belowSubview: fromView)

        let snapshotImage = snapshotView(toView)

        let imageViews = animatingInImageViews(snapshotImage)

        containerView.addSubview(imageViews.firstImageView)
        containerView.addSubview(imageViews.secondImageView)

      UIView.animateWithDuration(transitionDuration(transitionContext), animations: { () -> Void in
            let firstImageView = imageViews.firstImageView
            let secondImageView = imageViews.secondImageView

            if self.presenting {

                firstImageView.frame = CGRectOffset(firstImageView.frame, 0, CGRectGetHeight(firstImageView.frame))
                secondImageView.frame = CGRectOffset(secondImageView.frame, 0, -CGRectGetHeight(secondImageView.frame))

            } else {
                firstImageView.frame = CGRectOffset(firstImageView.frame, CGRectGetWidth(firstImageView.frame), 0)
                secondImageView.frame = CGRectOffset(secondImageView.frame, -CGRectGetWidth(secondImageView.frame),0)

            }
            }) { (completed: Bool) -> Void in
                fromView.removeFromSuperview()
                imageViews.firstImageView.removeFromSuperview()
                imageViews.secondImageView.removeFromSuperview()
                transitionContext.completeTransition(true)
        }           
    }

    func animatingOutImageViews(snapshotImage: UIImage)  -> (firstImageView: UIImageView!, secondImageView: UIImageView!)
    {
        let imageSize = snapshotImage.size

        var firstPartFrame: CGRect
        var secondPartFrame: CGRect

        if presenting {
            firstPartFrame = CGRectMake(0, 0, imageSize.width * 0.5, imageSize.height)
            secondPartFrame = CGRectOffset(firstPartFrame, CGRectGetWidth(firstPartFrame), 0)
        } else {
            firstPartFrame = CGRectMake(0, 0, imageSize.width, imageSize.height * 0.5)
            secondPartFrame = CGRectOffset(firstPartFrame, 0, CGRectGetHeight(firstPartFrame))
        }

        let firstImage = getImage(snapshotImage, insideRect: firstPartFrame)
        let secondImage = getImage(snapshotImage, insideRect: secondPartFrame)

        let firstImageView = UIImageView(frame: firstPartFrame)
        firstImageView.image = firstImage
        let secondImageView = UIImageView(frame: secondPartFrame)
        secondImageView.image = secondImage

        return (firstImageView, secondImageView)
    }

    func animatingInImageViews(snapshotImage: UIImage)  -> (firstImageView: UIImageView!, secondImageView: UIImageView!)
    {
        let imageSize = snapshotImage.size

        var firstPartFrame: CGRect
        var secondPartFrame: CGRect

        if presenting {
            firstPartFrame = CGRectMake(0, 0, imageSize.width, imageSize.height * 0.5)
            secondPartFrame = CGRectOffset(firstPartFrame, 0, CGRectGetHeight(firstPartFrame))
        } else {
            firstPartFrame = CGRectMake(0, 0, imageSize.width * 0.5, imageSize.height)
            secondPartFrame = CGRectOffset(firstPartFrame, CGRectGetWidth(firstPartFrame), 0)
        }

        let firstImage = getImage(snapshotImage, insideRect: firstPartFrame)
        let secondImage = getImage(snapshotImage, insideRect: secondPartFrame)

        let firstImageView = UIImageView(image: firstImage)
        let secondImageView = UIImageView(image: secondImage)

        if presenting {
            firstImageView.frame = CGRectOffset(firstPartFrame, 0, -CGRectGetHeight(firstPartFrame))
            secondImageView.frame = CGRectOffset(secondPartFrame, 0, CGRectGetHeight(secondPartFrame))
        } else {
            firstImageView.frame = CGRectOffset(firstPartFrame, -CGRectGetWidth(firstPartFrame), 0)
            secondImageView.frame = CGRectOffset(secondPartFrame, CGRectGetWidth(secondPartFrame), 0)
        }

        return (firstImageView, secondImageView)
    }

    func getImage(image: UIImage, insideRect rect:CGRect) -> UIImage {
        let image = CGImageCreateWithImageInRect(image.CGImage, rect)!
        return UIImage(CGImage: image)!
    }
}

class SecondViewController: UIViewController, UIViewControllerTransitioningDelegate {

    required init(coder aDecoder: NSCoder) {

        fatalError("init(coder:) has not been implemented")
    }

    init() {
        super.init(nibName: nil, bundle: nil)
        self.transitioningDelegate = self
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        let view1 = UIView(frame: CGRectZero)
        view1.backgroundColor = UIColor.purpleColor()
        view1.setTranslatesAutoresizingMaskIntoConstraints(false)

        let view2 = UIView(frame: CGRectZero)
        view2.backgroundColor = UIColor.cyanColor()
        view2.setTranslatesAutoresizingMaskIntoConstraints(false)

        view.addSubview(view1)
        view.addSubview(view2)

        let views = [
            "view1": view1,
            "view2": view2
        ]

        let vFormat = "V:|[view1][view2(==view1)]|"
        let hFormat = "H:|[view1]|"

        let hConstraints = NSLayoutConstraint.constraintsWithVisualFormat(hFormat,
            options: .allZeros,
            metrics: nil,
            views: views)
        let vConstraints = NSLayoutConstraint.constraintsWithVisualFormat(vFormat,
            options: .AlignAllLeft | .AlignAllRight,
            metrics: nil,
            views: views)

        view.addConstraints(hConstraints)
        view.addConstraints(vConstraints)

        let tapGestureRecognizer = UITapGestureRecognizer(target: self,
            action: "tapped")
        view.addGestureRecognizer(tapGestureRecognizer)
    }

    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return AnimationController(presenting: true)
    }

    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return AnimationController(presenting: false)
    }

    func tapped() {
        let nextViewController = NextViewController()
        dismissViewControllerAnimated(true, completion: nil)
    } 
}


class FirstViewController: UIViewController {

    override func viewDidLoad() {

        super.viewDidLoad()
        let view1 = UIView(frame: CGRectZero)
        view1.backgroundColor = UIColor.redColor()
        view1.setTranslatesAutoresizingMaskIntoConstraints(false)

        let view2 = UIView(frame: CGRectZero)
        view2.backgroundColor = UIColor.greenColor()
        view2.setTranslatesAutoresizingMaskIntoConstraints(false)

        view.addSubview(view1)
        view.addSubview(view2)

        let views = [
            "view1": view1,
            "view2": view2
        ]

        let hFormat = "H:|[view1][view2(==view1)]|"
        let vFormat = "V:|[view1]|"

        let hConstraints = NSLayoutConstraint.constraintsWithVisualFormat(hFormat,
            options: .AlignAllTop | .AlignAllBottom,
            metrics: nil,
            views: views)
        let vConstraints = NSLayoutConstraint.constraintsWithVisualFormat(vFormat,
                options: .allZeros,
                metrics: nil,
                views: views)

        view.addConstraints(hConstraints)
        view.addConstraints(vConstraints)

        let tapGestureRecognizer = UITapGestureRecognizer(target: self,
            action: "tapped")
        view.addGestureRecognizer(tapGestureRecognizer)

    }

    func tapped() {
        let secondViewController = SecondViewController()
        presentViewController(secondViewController, animated: true, completion: nil)
    }
}

代码可能会稍长一些,但必须易于理解。如果需要,请稍微调整一下。

关于ios - UIView 拆分过渡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30462159/

有关ios - UIView 拆分过渡的更多相关文章

  1. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  2. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  3. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  4. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  5. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  6. ruby - 拆分字符串并分配给不同的变量 - 2

    我从ui中得到日期范围为-approved_between"=>"2013-03-17-2013-03-18"我需要拆分此approved_start_date="2013-03-17"和approved_end_date="2013-03-18"...我希望使用它在mysql中查询,因为mysql中的日期格式是created_at:2012-07-2810:35:01.我正在做的是:approved=approved_between.split("")approved_start_date=approved[0]approved_end_date=approved[2]很确定这不是处

  7. ruby-on-rails - Ruby on Rails 将列表拆分或切片为列 - 2

    @locations=Location.all#currentlistingall@locations=Location.slice(5)orLocation.split(5)使用Ruby,我试图将我的列表分成4列,每列限制为5个;然而,切片或拆分似乎都不起作用。知道我可能做错了什么吗?任何帮助是极大的赞赏。 最佳答案 您可能想使用in_groups_of:http://railscasts.com/episodes/28-in-groups-of这是RyanBates在railscast中的示例用法:

  8. ruby - 格式化数字以每隔三位数拆分一次 - 2

    我想在格式化数字时每隔三个字符放置一个空格。根据这个规范:it"shouldformatanamount"dospaces_on(1202003).should=="1202003"end我想出了这段代码来完成这项工作defspaces_onamountthousands=amount/1000remainder=amount%1000ifthousands==0"#{remainder}"elsezero_padded_remainder='%03.f'%remainder"#{spaces_onthousands}#{zero_padded_remainder}"endend所以我

  9. ruby - 如何拆分数组? - 2

    给定一个数组:arr=[['a','1'],['b','2'],['c','3']]将它分成两个数组的最佳方法是什么?例如我想从上面的数组中得到以下两个数组:first=['a','b','c']second=['1','2','3']我可以使用collect来做到这一点吗? 最佳答案 好吧,我只是偶然发现了arr.transposearr=[['a','1'],['b','2'],['c','3']].transposefirst=arr[0]second=arr[1]与上面的答案arr.zip、arr.map、foreach相比

  10. ruby - 如何通过 "\r\n"拆分 Ruby 字符串? - 2

    给定一个字符串:s="Good\r\nDay\r\n\r\n\r\nStack\r\n\r\nOverflow\r\n"我愿意:用(\r\n)+拆分,即我想得到:["Good","Day","Stack","Overflow"]我尝试了s.split(/(\r\n)+/)但它没有给我预期的结果。为什么?我怎样才能得到预期的结果?获取数组中\r\n的个数,即预期结果为:[1,3,2]你会怎么做?我使用Ruby1.9.2。 最佳答案 差不多了,试试这个:s.split/[\r\n]+/s.scan(/[\r\n]+/).map{|e|e

随机推荐