How to include an ImageView into a Custom Segue? - ios

I'm attempting to create a custom segue where the order of the animation goes
1st UIViewController -> ImageView -> 2nd UIViewController
The code I have works, but for some reason the ImageView is black. I've tried using various images and literal image sources, but it's still black.
Here's some pictures for a better understanding-
1 (As the first UIViewController is replaced by the ImageView)
2 (As the ImageView is replaced by the second UIViewController)
/**
This segue transitions by dragging the destination UIViewController in from the right and replacing the old UIViewController by pushing it off to the left. This Segue also contains an ImageView that is between the two UIViewControllers.
*/
class CustomSegue2: UIStoryboardSegue {
override func perform() {
// Assign the source and destination views to local variables.
let firstView = self.source.view as UIView!
let secondView = UIImageView()
let thirdView = self.destination.view as UIView!
// Get the screen width and height.
let width = UIScreen.main.bounds.size.width
let height = UIScreen.main.bounds.size.height
// Set properties of secondView
secondView.frame = CGRect(x: width, y: 0, width: width, height: height)
secondView.contentMode = UIViewContentMode.scaleToFill
secondView.image = #imageLiteral(resourceName: "orangeRedGradient_MESH_tealGreenGradient")
// Specify the initial position of the destination view.
let rect = CGRect(x: width + width, y: 0.0, width: width, height: height)
thirdView?.frame = rect
// Access the app's key window and insert the destination view above the current
let window = UIApplication.shared.keyWindow
window?.insertSubview(thirdView!, aboveSubview: firstView!)
// Animation the transition.
UIView.animate(withDuration: 10, animations: { () -> Void in
firstView?.frame = firstView!.frame.offsetBy(dx: -width-width, dy: 0.0)
secondView.frame = secondView.frame.offsetBy(dx: -width-width, dy: 0.0)
thirdView?.frame = thirdView!.frame.offsetBy(dx: -width-width, dy: 0.0)
}) { (Finished) -> Void in
self.source.present(self.destination, animated: false, completion: nil)
}
}
}

secondView never appears because at no time do you insert it into the interface.
(I would describe your code overall as completely wrong-headed — if you want a custom transition, you should be writing proper custom transition animation code. But that answers the question of why the image view is "black" — it isn't black, it is completely absent.)

Related

Adding a subview inside of a UIStoryboardSegue

I'm writing an app where I need to use a fairly "complex" UIStoryboardSegue. The designer gave me the following:
Now the basic idea behind the segue is simple, sliding up the source.view, then sliding up one more view before eventually sliding the destination.view. However, my question is the following:
How do I insert a second view in-between the source.view and the destination.view from a subclass of UIStoryboardSegue ? Obviously I can't just do addSubview, since there is no view to add to. Is there another place to add a view in a UIStoryboardSegue, so I can still create this segue?
Thanks.
If this is what you want
You can achieve it very easily,
Step 1:
Create a subclass of UIStoryboardSegue and override perform
import UIKit
class SpecialEffectSegue: UIStoryboardSegue {
override func perform() {
let firstVCView = self.source.view as UIView!
let secondVCView = self.destination.view as UIView!
let intermediateView = UIView()
intermediateView.backgroundColor = UIColor.red
// Get the screen width and height.
let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
// Specify the initial position of the destination view.
secondVCView?.frame = CGRect(x: 0.0, y: screenHeight, width: screenWidth, height: screenHeight)
intermediateView.frame = CGRect(x: 0.0, y: screenHeight, width: screenWidth, height: screenHeight)
// Access the app's key window and insert the destination view above the current (source) one.
let window = UIApplication.shared.keyWindow
window?.insertSubview(intermediateView, aboveSubview: firstVCView!)
window?.insertSubview(secondVCView!, aboveSubview: secondVCView!)
UIView.animate(withDuration: 0.4, animations: { () -> Void in
firstVCView?.frame = ((firstVCView?.frame)?.offsetBy(dx: 0.0, dy: -screenHeight))!
intermediateView.frame = (intermediateView.frame.offsetBy(dx: 0.0, dy: -screenHeight))
}) { (Finished) -> Void in
UIView.animate(withDuration: 0.4, animations: { () -> Void in
secondVCView?.frame = (secondVCView?.frame.offsetBy(dx: 0.0, dy: -screenHeight))!
}) { (Finished) -> Void in
self.source.present(self.destination, animated: false, completion: {
intermediateView.removeFromSuperview()
})
}
}
}
}
Though code looks huge and complicated what is happening in it is pretty simple.
Get the source and destination viewController's view using
let firstVCView = self.source.view as UIView!
let secondVCView = self.destination.view as UIView!
Because you need a intermediate view which is red in color here you create one more view
let intermediateView = UIView()
intermediateView.backgroundColor = UIColor.red
Now get the UIScreen width and heght so that you can configure these views frame so that it looks good as per your need
let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
// Specify the initial position of the destination view.
secondVCView?.frame = CGRect(x: 0.0, y: screenHeight, width: screenWidth, height: screenHeight)
intermediateView.frame = CGRect(x: 0.0, y: screenHeight, width: screenWidth, height: screenHeight)
Note that the I set the frame of SecondVC and intermediateView such that they are below screen bounds and Ill animate them to come up in UIView.animate block
Now obviously because animations are happening on key window of your app access the key window
let window = UIApplication.shared.keyWindow
Now insert the subviews to window as per your need.
window?.insertSubview(intermediateView, aboveSubview: firstVCView!)
window?.insertSubview(secondVCView!, aboveSubview: secondVCView!)
So after this I have views stacked up as FirstVCView -> IntermediateView -> SecondVCView
Now we have pretty much what we need isnt it. Now animate it using UIView.animate
UIView.animate(withDuration: 0.4, animations: { () -> Void in
firstVCView?.frame = ((firstVCView?.frame)?.offsetBy(dx: 0.0, dy: -screenHeight))!
intermediateView.frame = (intermediateView.frame.offsetBy(dx: 0.0, dy: -screenHeight))
}) { (Finished) -> Void in
UIView.animate(withDuration: 0.4, animations: { () -> Void in
secondVCView?.frame = (secondVCView?.frame.offsetBy(dx: 0.0, dy: -screenHeight))!
}) { (Finished) -> Void in
self.source.present(self.destination, animated: false, completion: {
intermediateView.removeFromSuperview()
})
}
}
Important thing to notice is intermediateView.removeFromSuperview() in completion block.
Now I have decided to present destination using self.source.present( if you need to push destination VC with your funky animation say
self.source.navigationController?.pushViewController(destination, animated: false)
Thats all :)
Now open your storyboard, drag a segue from one your FirstVC to SecondVC and select the segue class as SpecialEffectSegue thats it now enjoy
Hope it helps :)

UIViewController hidden behind UINavigationController but should be placed below

I'm working on a app where I've got a NavigationBar at the top and added a UIViewController as an RootViewController.
Now my plan was to add a new Subview to this UIViewController. The new Subview extended also of UIViewController. I added de view (Gray Rect) of the controller to the UIViewController but it is placed behind the NavigationBar. I don't want that.. So I searched for a solution and found something interesting..:
When I just add a UIView() (Green Rect) to the UIViewController, the placing of the view works perfectly, as I would love see it from the other UIViewController-View.
My code looks like following:
class DashboardController: UIViewController {
var ccview:ContactCircleController!
override func viewDidLoad() {
super.viewDidLoad()
edgesForExtendedLayout = []
self.view.backgroundColor = .white
let test = UIView()
test.backgroundColor = .green
test.frame = CGRect(x: self.view.frame.width - 200, y: 0, width: self.view.frame.width / 2, height: self.view.frame.width / 2)
self.view.addSubview(test)
setup()
}
func setup(){
ccview = ContactCircleController()
ccview.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width / 2, height: self.view.frame.width / 2)
ccview.edgesForExtendedLayout = UIRectEdge.top
self.view.addSubview(ccview.view)
}}
I've already unchecked the "Extend Edges" - toggle of the navigationcontroller on the storyboard. I also added edgesForExtendedLayout = [] to the UIViewController and for the UIView it worked fine. But for the view of another UIViewController... it didn't worked.
Thank you!
If you use Debug View Hierarchy, you will see that your gray ccview.view is not behind the navigation bar, but rather it is not keeping the height of self.view.frame.width / 2.
This is because the .view of a UIViewController instantiated from Storyboard has by default an .autoresizingMask = [], whereas the .view of a UIViewController instantiated without a storyboard has a default .autoresizingMask = [.flexibleWidth, .flexibleHeight].
You can correct this by changing setup() to:
func setup(){
ccview = ContactCircleController()
ccview.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width / 2, height: self.view.frame.width / 2)
// remove this line
//ccview.edgesForExtendedLayout = UIRectEdge.top
// add this line
ccview.view.autoresizingMask = []
self.view.addSubview(ccview.view)
}

UIStoryboardSegue: view is not displayed during animation

When my custom segue's animation is being performed, destination view appears black. After animation ends, view appears and looks good.
Here are the screenshots:
Animation scene:
View after segue/animation finished:
Here is the custom segue class:
class SegueToPreview: UIStoryboardSegue {
override func perform() {
// Assign the source and destination views to local variables.
var firstVCView = self.sourceViewController.view as UIView!
var secondVCView = self.destinationViewController.view as UIView!
// Get the screen width and height.
let screenWidth = UIScreen.mainScreen().bounds.size.width
let screenHeight = UIScreen.mainScreen().bounds.size.height
// Specify the initial position of the destination view.
secondVCView.frame = CGRectMake(0.0, screenHeight, screenWidth, screenHeight)
// Access the app's key window and insert the destination view above the current (source) one.
let window = UIApplication.sharedApplication().keyWindow
window?.insertSubview(secondVCView, aboveSubview: firstVCView)
// Animate the transition.
UIView.animateWithDuration(0.2, animations: { () -> Void in
firstVCView.frame = CGRectOffset(firstVCView.frame, -screenWidth, 0.0)
secondVCView.frame = CGRectOffset(secondVCView.frame, -screenWidth, 0.0)
}) { (Finished) -> Void in
self.sourceViewController.presentViewController(self.destinationViewController as! UIViewController,
animated: false,
completion: nil)
}
}
While unwind segue works just fine, showing both views.
I suppose that the view is not loaded while the animation is being performed, but have no idea how to fix that.
Your initial position for the destination vc's view is setup incorrectly (assuming that you want the view to move in from the right); you have it positioned below the screen, instead of to the right of the screen,
secondVCView.frame = CGRectMake(0.0, screenHeight, screenWidth, screenHeight)
This should be,
secondVCView.frame = CGRectMake(screenWidth, 0, screenWidth, screenHeight)

Swift. Flip animation. FromView is not displayed

I've wrote this code to create a simple flip animation:
func frontView (view:UIView) ->UIView {
var frontView: UIView
frontView = UIView()
frontView.frame = view.frame
frontView.center = CGPoint(x: 0, y: 0)
return frontView
}
func backView (view:UIView) ->UIView {
var backView: UIView
backView = UIView()
backView.frame = view.frame
backView.backgroundColor = UIColor.redColor()
backView.center = CGPoint(x: view.frame.width/2, y: 0)
view.addSubview(backView)
return backView
}
func flipViewAnimation (viewToAnimate: UIView) {
var animationOption = self.animationOption
var duration = self.duration
UIView.transitionFromView(backView(viewToAnimate), toView: frontView(viewToAnimate), duration: duration, options: animationOption, completion: nil)
//
}
As a viewToAnimate I use views with labels and imageViews inside, which I've created in AutoLayout. The result I'm trying to achieve more or less should look like this. First I see views filled with color, then they flip and show the content inside (labels and ImageViews).
But it works in a different way. Views appear already with content (labels and ImageViews) then just flip and again show the same content.
I've created each view programmatically and it works very well for me now.

Adding a small UIView to an SKScene

I have a Swift + SpriteKit game in development, in which I would like to insert a small UITableViewController into a small (100 x 200) UIView, and then add that view to my SKScene. I am using this code:
class BugsScene: SKScene {
override func didMoveToView(view: SKView) {
anchorPoint = CGPoint(x: 0.5, y: 0.5)
NSUserDefaults.standardUserDefaults().setObject("bugs", forKey: "lastSceneViewed")
let bugsTableView: BugsTVC = BugsTVC()
let nav = UINavigationController(rootViewController: bugsTableView)
let smallerRect = CGRectMake(0, 0, 100, 200)
let smallerView = UIView(frame: smallerRect)
smallerView.addSubview(nav.view)
self.view.addSubview(smallerView)
}
}
However, in landscape mode (my app only supports landscape left and landscape right, NO portrait), the tableview occupies the entire height of the landscape mode, and has the width of an iPad in portrait.
How do I add a small UIView to a bigger scene in swift/spritekit?
LearnCocos2D definitely deserves credit for this, so if he ever posts an answer I will accept it. Essentially, I was failing to set the frame for the navigation controller's view. Here is my method for adding the smaller view to the scene:
override func didMoveToView(view: SKView) {
anchorPoint = CGPoint(x: 0.5, y: 0.5)
self.name = "Bugs Scene"
backgroundColor = bugsColor
let smallerRect = CGRectMake(400, 24, 600, 720)
let navRect = CGRectMake(0, 0, 600, 720)
let bugsTableView: BugsTVC = BugsTVC()
nav = UINavigationController(rootViewController: bugsTableView)
nav.view.frame = navRect
smallerView = UIView(frame: smallerRect)
smallerView.backgroundColor = UIColor.clearColor()
bugsTableView.view.frame = smallerRect
smallerView.frame = smallerRect
smallerView.addSubview(nav.view)
self.view.addSubview(smallerView)
}
It could probably be refined some but this is working for me. Now if I can only figure out how to remove the view when I transition to another scene!

Resources