childViewController.view.frame in UIView present different value - ios

I use childViewController to separate view in project, but some strange issue happened, here is my code.
class ViewController: UIViewController {
var container = UIView()
var childVC = ChildViewController()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
addChildViewController(childVC)
childVC.didMove(toParentViewController: self)
addChildView()
setContainerFrame()
}
func setContainerFrame() {
container.frame = CGRect(x: 0, y: 100, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height - 100)
container.backgroundColor = .red
view.addSubview(container)
}
func addChildView() {
let frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
childVC.view.frame = frame
childVC.view.backgroundColor = .green
container.addSubview(childVC.view)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("childVC.view.frame: \(childVC.view.frame)")
}
}
class ChildViewController: UIViewController {
}
when I exchange the order invoking func addChildView() and func setContainerFrame() in ViewController's viewDidLoad(), xcode'console prints different frame log.

This is due to the autoresizingMask of the childVC.view. By default this is set to have flexible width and height. So if you set the frame of the container and then the frame of the childVC.view then you get the actual value you set but if you reverse it and set the frame of the childVC.view and then the container the frame of the childVC.view is automatically updated to have the same relative width and height.
For example if the frame size for the container was 100 x 100 and then you change it to 200 x 200 the frame size for childVC.view will be doubled.
To remove this set the childVC.view.autoresizingMask = [] so it remains as you set it.

The strange behavior occurs because in addChildView() function you are adding the child view controller's view as subview to container view but container view's frame is setting in the function setContainerFrame() which is not yet called. That means you are adding a subview to a view whose frame hasn't set already.

Related

How can I fill image in scroll view to fill screen?

I am playing around with scroll views, and I've run into an issue I'be stuck with. I have a view controller create in Storyboard. The view controller contains a scroll view which fills the entire superview.
I then added the images programmatically to the scroll view. The images do show within the scroll view and paging works just fine. Only problem is the scroll view is set ti fill superview but the image view that hold the images seems like it stops above where the navigation bar would be. How can I have the image view fill the whole view within the scroll view?
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var pagingView: UIPageControl!
var images = [UIImage]()
var frame = CGRect(x: 0, y: 0,width: 0,height: 0)
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
scrollView.isPagingEnabled = true
images = [UIImage(named: "Slide1")!, UIImage(named: "Slide2")!, UIImage(named: "Slide3")!, UIImage(named: "Slide4")!]
pagingView.numberOfPages = images.count
// This is where I think I'm having the height problem.
for i in 0..<images.count {
let imageView = UIImageView()
let x = self.view.frame.size.width * CGFloat(i)
imageView.frame = CGRect(x: x, y: 0, width: self.view.frame.width, height: self.view.frame.height)
imageView.contentMode = .scaleAspectFill
imageView.image = images[i]
scrollView.contentSize.width = scrollView.frame.size.width * CGFloat(i + 1)
scrollView.addSubview(imageView)
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = scrollView.contentOffset.x / scrollView.frame.size.width
pagingView.currentPage = Int(pageNumber)
}
After setting nav bar to hidden, here is the output
Scroll view background color is red
In this case you need to enable the parent view clipsToBounds. Set UIScrollview clipsToBounds property to True.
Programmatically scrollView.clipsToBounds = true
In UIStoryBoard - Click the view->Attributes Inspector
If you would like to see the whole screen, make sure to add the topConstraint of scrollView assigned superView and hide the navigationBar in viewWillAppear,
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(true, animated: animated)
}
Make sure to remove the status bar by
override var prefersStatusBarHidden: Bool {
return true
}
Update the Y position of Image.
imageView.frame = CGRect(x: x, y: **self.scrollView.frame.minY**, width: self.view.frame.width, height: self.view.frame.height)
Update the scrollView topConstraint by -20.

UIView unable to get transparent property

I am trying to add a subview to the window (for using it as side menu). It has a child view which is transparent view. However I am unable to get the transparent property when it runs in simulator.
I am using the following code:
override func viewWillAppear(_ animated: Bool) {
frame = CGRect(x: 0, y:0, width:0, height:0)
frame.size.height = UIScreen.main.bounds.height
frame.size.width = UIScreen.main.bounds.width
sideMenuView.frame = frame
sideMenuTransparentView.isOpaque = false
sideMenuTransparentView.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
UIApplication.shared.keyWindow?.addSubview(sideMenuView)
}
However I am seeing no effect of this to make the view as transparent. What's possibly wrong here and how should I proceed rectifying this?
The weird thing here is that when I replace the lines
sideMenuTransparentView.isOpaque = false
sideMenuTransparentView.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
with
sideMenuView.isOpaque = false
sideMenuView.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
I can see the effect. I am unable to understand what's going in here and how should I correct this.
You seem to have forgotten to add the transparent view to the main sideMenuView.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) // You need to call super when overriding
frame = CGRect(x: 0, y:0, width:0, height:0)
frame.size.height = UIScreen.main.bounds.height
frame.size.width = UIScreen.main.bounds.width
sideMenuView.frame = frame
sideMenuTransaparentView.frame = yourFrame // required frame
sideMenuTransparentView.isOpaque = false
sideMenuTransparentView.backgroundColor = UIColor.gray.withAlphaComponent(0.5) // 100% transparency
sideMenuView.addSubview(view: sideMenuTransparentView)
UIApplication.shared.keyWindow?.addSubview(sideMenuView)
}
Also, you forgot to call super.

Move UIView from ViewController to Window

Thanks for taking the time to read thus. So basically, I have a UIView in my UIViewController. I want a user to be able to press a button and then the UIView moves from my UIViewController to the my application's window so that the UIView will be above all UIViewControllers. The only thing I could think of doing was
class ViewController: UIViewController {
var window = UIApplication.shared.keyWindow!
var view = UIView()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(view)
}
func tappedAction() {
window.bringSubview(toFront: view)
}
}
but that didn't work. Does anyone have any ideas on how to accomplish this?
You cannot just bring the subview that's in your UIViewController to the front of your UIWindow.
You need to:
Remove the UIView from the UIViewController.
Add the UIView to the main UIWindow.
I chose to do this in this way:
import UIKit
class ViewController: UIViewController {
var customView: UIView!
// Load the main view of the UIViewController.
override func loadView() {
view = UIView()
}
override func viewDidLoad() {
super.viewDidLoad()
// Load the custom view that we will be transferring.
self.customView = UIView(frame: .init(x: 100, y: 250, width: 250, height: 250))
self.customView.backgroundColor = .red
view.addSubview(customView)
// Transfer the view. Call this method in your trigger function.
transfer(self.customView)
}
func transfer(_ view: UIView) {
// Remove the view from the UIViewController.
view.removeFromSuperview()
// Add the view to the UIWindow.
UIApplication.shared.windows.first!.addSubview(view)
}
}
You must set frame fro view at var view = UIView()
then you should add to window window.addSubview(view)
If your view is added on window then window.bringSubview(toFront: view) will work otherwise it will not.
If your view is added on window then you can use bringSubview(toFront:) like that:
Example:
let window = UIApplication.shared.keyWindow!
let view1 = UIView(frame: CGRect(x: window.frame.origin.x, y: window.frame.origin.y, width: window.frame.width, height: window.frame.height))
window.addSubview(view1);
view1.backgroundColor = UIColor.black
let view2 = UIView(frame: CGRect(x: 50, y: 50, width: 100, height: 50))
view2.backgroundColor = UIColor.white
window.addSubview(view2)
UIApplication.shared.keyWindow!.bringSubview(toFront: view1)
So you need to add your view in window:
window.addSubview(view)

Pull to Refresh plug-in : PullToBounce Wrapper UIScrollView

I am trying to use this plugin as refresh action : https://github.com/entotsu/PullToBounce
One, issue is I can't understand his explanation.
Explanation given on the github
tableView.frame = yourFrame --> tableView is equal to scrollView.frame in my situation
yourFrame --> I have no idea what it is. The main frame ? Another Frame I have to create ?
bodyView.addSubview(tableViewWrapper) --> bodyView ? Main Frame here ? or Another frame ?
Here is my code for the scrollView for now. Any help on how to implement this plugin using a scrollView made via the storyboard.
class ProfileViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
func makeMock() {
let headerView = UIView()
headerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: 64)
headerView.backgroundColor = UIColor.lightBlue
self.view.addSubview(headerView)
let headerLine = UIView()
headerLine.frame = CGRect(x: 0, y: 0, width: 120, height: 8)
headerLine.layer.cornerRadius = headerLine.frame.height/2
headerLine.backgroundColor = UIColor.whiteColor().colorWithAlphaComponent(0.8)
headerLine.center = CGPoint(x: headerView.frame.center.x, y: 20 + 44/2)
headerView.addSubview(headerLine)
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.blue
let bodyView = UIView()
bodyView.frame = scrollView.frame
bodyView.frame.y += 20 + 44
self.view.addSubview(bodyView)
let tableViewWrapper = PullToBounceWrapper(scrollView: scrollView)
bodyView.addSubview(tableViewWrapper)
tableViewWrapper.didPullToRefresh = {
NSTimer.schedule(delay: 2) { timer in
tableViewWrapper.stopLoadingAnimation()
}
}
makeMock()
}
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}
}
One thing, I notice is that there is a View on top of my scrollView that disable me to view it and scroll it. Help here needed please.
Regards,
Hary
Take a look at the Example of this library.
yourFrame is nothing but your tableview class. For example if your tableView Class is named SampleTableView, then it goes like
let tableView = SampleTableView(frame: self.view.frame, style: UITableViewStyle.Plain).
You have to use another class to set up your tableView.

Changing frame of UIView through IBOutlet from storyboard

#IBOutlet weak var outletView: UIView! //Referencing Outlet connected
override func viewDidLoad() {
super.viewDidLoad()
//not working
outletView.frame = CGRectMake(100, 100, 100, 100)
//working
var view = UIView();
view.frame = CGRectMake(0, 20, 100, 100);
self.view.addSubview(view);
}
How can I edit frame of #IBoutlet view as normal UIView instance?
I solved it to remove Use Size Classes on StoryBoard inspector.
When you set the frame in ViewDidload method , it first assigns the frame that you set inViewDidload and then the Storyboard Constraints are applied so your constraints are over-ridden.
In order to change the constraints apply the constraints in ViewDidAppear method and it will be reflected
override func viewDidAppear(animated: Bool)
{
outletView.frame = CGRect(x: 100, y: 100, width: 200, height: 400)
}

Resources