I Have two viewControllers. One is home page, other is detail page. if I make them window's root view controller they look like this:
This is My Home Page
This is my details page
but when I make my home page my root view controller and push my detail view controller to present, it looks like this :
So here is my detailviewController. It has one scrollview and uistackview. no storyboard used.
let scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()
let scrollViewContainer: UIStackView = {
let view = UIStackView()
view.axis = .vertical
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
and this is the constraints:
view.addSubview(scrollView)
scrollView.addSubview(scrollViewContainer)
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
scrollViewContainer.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
scrollViewContainer.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
scrollViewContainer.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
scrollViewContainer.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
// this is important for scrolling
scrollViewContainer.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
I think it is iOS 13 related problem.
EDIT: If I make animated to false when pushing detailvc, everything is normal.
If the problem is really in constraints, try to set scrollView - widthAnchor equal to view width and centerXAnchor equal to view center X.
It seems to me wrong to set the following at the same time:
scrollViewContainer.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
scrollViewContainer.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
and
scrollViewContainer.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
I suggest leaving the last constraint and also align the scrollViewContainer in the centerX relative to the view.
I hope it will help you.
Related
So I have a scrollView, inside that scrollView is a stackView that contains every views in the screen.
The problem is my stackView has many hide-able views so I need to adjust my containsVieww's height base on my stackView's height
my psuedo code should be like this :
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print(stackView.bounds.height)
// do logic to change contentView size here
}
func setupView(){
scrollView.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
scrollView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
scrollView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
scrollView.backgroundColor = .white
scrollView.contentSize = CGSize(width: view.frame.width, height: view.frame.height)
scrollView.addSubview(stackView)
stackView.setArrangedSubView(views: [label1, label 2, label 3, label 4, ..., label n]
[label1, label 2, label 3].isHidden = true
}
func onHitButton(){
if isHidden {
[label1, label 2, label 3].isHidden = false
isHidden = false
} else {
[label1, label 2, label 3].isHidden = true
isHidden = true
}
print(stackView.bounds.height) // still return the ex height
}
Here is the problem:
On first init, my [label1,2,3].isHidden = true, my stackViewHeight is 500
When my onHitButton is called, my [label1,2,3].isHidden = false, my stackViewHeight is still 500 but the screen displays correctly, those labels are visible now and my stackView is stretched. And of course my scrollView is not displays correctly.
Then I hit my onHitButton again, those labels are hidden, my stackView is shrink on screen but the stackViewHeight returned 850?
It's supposed to be the other way around.
I also tried to print the height on another button call and it return the right height? Seem like viewDidLayoutSubviews called too early.
To sum it up: stackView return the height before it resize it self
Use auto-layout to constrain the stack view to the scroll view's Content Layout Guide:
scrollView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
// reference to scrollView's Content Layout Guide
let cGuide = scrollView.contentLayoutGuide
// reference to scrollView's Frame Layout Guide
let fGuide = scrollView.frameLayoutGuide
NSLayoutConstraint.activate([
// constrain stackView to scrollView's Content Layout Guide
stackView.topAnchor.constraint(equalTo: cGuide.topAnchor),
stackView.leadingAnchor.constraint(equalTo: cGuide.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: cGuide.trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: cGuide.bottomAnchor),
// constrain stackView's Width to scrollView's Frame Layout Guide
stackView.widthAnchor.constraint(equalTo: fGuide.widthAnchor),
])
This will completely avoid the need to ever set .contentSize -- it will all be handled by auto-layout.
Hi I am learning how to make newsfeeds and although things are going well I would like some help in terms of the layout of the feed itself. The feed clips to the safe areas of the simulator but I want to move the top section down about half way down the screen. I have made the table view using a XIB and created the table view programatically. How would one be able to shift the top section down? Here is the code:
HomeViewScene = UITableView(frame: view.bounds, style: .plain)
HomeViewScene.backgroundColor = Colors.white
view.addsubview(tableview)
let cellNib = UINib(nibName: "PosterCell", bundle: nil)
HomeViewScene.register(cellNib, forCellReuseIdentifier: "postCell")
var layoutguide:UILayoutGuide
layoutguide = view.safeAreaLayoutGuide
HomeViewScene.leadingAnchor.constraint(equalTo: layoutguide.leadingAnchor).isActive = true
HomeViewScene.topAnchor.constraint(equalTo: layoutguide.topAnchor).isActive = true
HomeViewScene.trailingAnchor.constraint(equalTo: layoutguide.trailingAnchor).isActive = true
HomeViewScene.bottomAnchor.constraint(equalTo: layoutguide.bottomAnchor).isActive = true
It looks to me like you're pretty close. The 2 main things I would suggest are:
1) You need to set translatesAutoresizingMaskIntoConstraints to false if you want your constraints to actually take effect.
2) If you want your table view under your other view, you need to set your table view's top anchor to be equal to your other view's bottom anchor.
Specifically, this is how I would change the code you posted to solve your problem:
HomeViewScene = UITableView(frame: view.bounds, style: .plain)
HomeViewScene.backgroundColor = Colors.white
view.addsubview(tableview)
let cellNib = UINib(nibName: "PosterCell", bundle: nil)
HomeViewScene.register(cellNib, forCellReuseIdentifier: "postCell")
var layoutguide:UILayoutGuide
layoutguide = view.safeAreaLayoutGuide
HomeViewScene.translatesAutoresizingMaskIntoConstraints = false //Add this line
HomeViewScene.leadingAnchor.constraint(equalTo: layoutguide.leadingAnchor).isActive = true
HomeViewScene.topAnchor.constraint(equalTo: otherView.topAnchor).isActive = true //You need to make sure the TOP of the table view is positioned right at the BOTTOM of the other view
HomeViewScene.trailingAnchor.constraint(equalTo: layoutguide.trailingAnchor).isActive = true
HomeViewScene.bottomAnchor.constraint(equalTo: layoutguide.bottomAnchor).isActive = true
Remember that if you change constraints on a view programmatically, you must set translatesAutoresizingMaskIntoConstraints to false otherwise you will see no change to that view's position.
I added a Tableview Controller in storyboard, The problem is that it's overlapping the bottom safe area on iPhone X. I also have a view at the bottom which is above the safeAreaLayoutGuide. I tried to use auto layout and anchor it to view.safeAreaLayoutGuide.bottomAnchor, but this doesn't work. Any help would be appreciated. This is what I've tried, with other options but no help.
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo:view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo:view.safeAreaLayoutGuide.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo:view.safeAreaLayoutGuide.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true }
I've searched through S/OF and can't find a fix for the TableView being behind my TabBar.
I set up my TableView like this;
func setUpTableView() {
messagesTableView.frame = view.frame
messagesTableView.backgroundColor = .white
view.addSubview(messagesTableView)
messagesTableView.tableFooterView = UIView()
messagesTableView.delegate = self
messagesTableView.dataSource = self
messagesTableView.register(UITableViewCell.self, forCellReuseIdentifier: messagesCellIdentifier)
edgesForExtendedLayout = []
extendedLayoutIncludesOpaqueBars = false
messagesTableView.contentInsetAdjustmentBehavior = .never
}
Then I setUpTableView() in viewDidLoad().
According to all sources
edgesForExtendedLayout = []
extendedLayoutIncludesOpaqueBars = false
messagesTableView.contentInsetAdjustmentBehavior = .never
Should satisfy the content insets and not allow the TableView to scroll behind the TabBar.
Please note my TabBars' translucency is set to false inside TabBarController.
tabBar.isTranslucent = false
As always any help appreciated.
Adding Illustration
When scrolling to the bottom is not showing the complete TableView content as the TabBar covers the last few indexes.
Did you try this in viewDidAppear ?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
}
Edit
Remove
messagesTableView.frame = view.frame
and add autoLayout to your messagesTableView
messagesTableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
messagesTableView.topAnchor.constraint(equalTo: topAnchor),
messagesTableView.leftAnchor.constraint(equalTo: leftAnchor),
messagesTableView.bottomAnchor.constraint(equalTo: bottomAnchor),
messagesTableView.rightAnchor.constraint(equalTo: rightAnchor)
])
I am facing an issue where I can see a black portion in my UIViewController where I have a UISearchController, UICollectionView and UISegmentControl because of my poor design.
I have added a UISearchController in navigationbar using following code:
func setupSearchBar(){
navigationItem.searchController = taskSearchController
taskSearchController.searchBar.tintColor = .white
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedStringKey.foregroundColor.rawValue: UIColor.lightGray]
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).attributedPlaceholder = NSAttributedString(string: "Search Text", attributes: [NSAttributedStringKey.foregroundColor: UIColor.lightGray])
if let textfield = taskSearchController.searchBar.value(forKey: "searchField") as? UITextField {
if let backgroundview = textfield.subviews.first {
backgroundview.backgroundColor = UIColor.init(white: 1, alpha: 1)
backgroundview.layer.cornerRadius = 10
backgroundview.clipsToBounds = true
}
}
taskSearchController.hidesNavigationBarDuringPresentation = true
//navigationItem.hidesSearchBarWhenScrolling = false
//taskSearchController.searchBar.scopeButtonTitles = ["ASSIGNED TASK","CREATED TASK"]
}
after adding UISearchController I am adding a UISegmentControl and a UICollectionView using following code:
func setupView(){
//self.view.addSubview(coverView)
self.view.addSubview(taskSegment)
taskSegment.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
taskSegment.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
taskSegment.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
taskSegment.heightAnchor.constraint(equalToConstant: 30).isActive = true
self.view.addSubview(collectionView)
collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
collectionView.topAnchor.constraint(equalTo: taskSegment.bottomAnchor, constant: 10).isActive = true
collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 5).isActive = true
}
This my initial view which is fine.
This is how it looks when UISearchController is focused
Here you can see when navigationBar hides and UISearchController placed at top at that time my UISegment and UIcollectionView remains at same position so I want to move it according to change in UISearchController.
Can anyone tell me what should I do?
Thank You in advance.
It hides the navigation bar because hideNavigationBarDuringPresentation is set to true. This is intended behavior.
You either need to disable this so that the view constraints dont change during presentation or you need to amend your constraints so that the view would adjust to the height change of the navigation bar. You should be able to do this quite easily by setting a top constraint to the Safe area of the main view.