How to disable drag space between two collections views in ios - ios

I am using two collectionViews A and B one below the other. (I am using A to display headers and B containing the set of data below the header collection view A).
Now when I scroll the Collection view B to top and reach the end point I get a gap between A and B, which is not the expected output behaviour. What should I do to make A drag along with B without any space while scrolling.
TLDR - I've added a gif showing the issue.
func configureHeaderCollectionView() {
headerCollectionView.backgroundColor = UIColor.systemBackground
view.addSubview(headerCollectionView)
headerCollectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
headerCollectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
headerCollectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
headerCollectionView.heightAnchor.constraint(equalToConstant: 50).isActive = true
headerCollectionView.delegate = self
headerCollectionView.dataSource = self
headerCollectionView.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: "header")
}
func configureCollectionView() {
collectionView.backgroundColor = UIColor.systemBackground
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: headerCollectionView.bottomAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: CustomCollectionViewCell.identifier)
}
I am calling these two functions in viewDidLoad to setup the collection views.

I had the same problem but with a simpler GUI.
Try to disable scrolling of collectionView. This will not disable scrolling of cells, headers and footer.
collectionView.isScrollEnabled = false

Related

How to get UITableView to be positioned within the safe area

I am trying to get my UITableView to be positioned within the safe area but it doesn't seem to be working and I do not know why. I trying to do this programatically.
class MenuTableViewController: UITableViewController{
var margin: UILayoutGuide!
var tableDataSource: [userFolderObject]!
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
setup()
}
private func setup(){
margin = view.layoutMarginsGuide
tableDataSource = MockData.UITableDateSource
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: margin.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: margin.bottomAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo: margin.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: margin.trailingAnchor).isActive = true
/* I have also tried the below code
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
*/
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let label = UILabel()
label.backgroundColor = UIColor.lightGray
if section == 0{
label.text = "Search PubMed"
}else{
label.text = "My Folders"
}
return label
}
}
First, remove all of your setup code that attempts to mess with the margins of the table view. That is all done for you by default in a UITableViewController.
Since your issue is only with the layout of your custom section header views, you need to fix how you have implemented those views.
Like cells, you should use reusable header/footer views and your header/footer view should extend UITableViewHeaderFooterView. This will ensure proper margins by defaults and it already provides a standard textLabel you can set. No need to create your own UILabel.
As shown in the documentation for UITableViewHeaderFooterView you should register a class. Then in viewForHeader you should dequeque the header view and then set its textLabel as needed.
If you don't actually need anything but a plain old section label, then don't implement viewForHeader. Instead, implement titleForHeader. Much simpler.

Typing on search bar breaks layout

I have a tableView:
tableView = UITableView()
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
let constraints = [tableView.topAnchor.constraint(equalTo: view.topAnchor), tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.heightAnchor.constraint(equalToConstant: view.frame.height * 0.6)]
NSLayoutConstraint.activate(constraints)
And my searchController looks like:
func setupSearchController() {
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search for a candy"
navigationItem.searchController = searchController
definesPresentationContext = true
}
When it loads for the first time everything is fine. But when I tap on the search bar to type there, my search bar moves to the top, navigation bar becomes smaller and it breaks my layout and white space appears between tableView and searchBar:
How can I improve my constraints to move up and down my tableView when the navigation bar sizes are changed?
You have to change your top constraint of the tableview.
Try replacing this 2 constraint
tableView.topAnchor.constraint(equalTo: searchController.searchBar.bottomAnchor),
tableView.topAnchor.constraint(equalTo: view.topAnchor)
With this
tableView.topAnchor.constraint(equalTo: view.topAnchor)
The automatic content inset adjustment will do the rest.
Note also that in your table view constraints list you doesn't have a leading/horizontal position constraint. I suggest to add also this constraint
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor)

Empty TableView when embedded as a child view controller into a container view [duplicate]

This question already has an answer here:
How to add a UITableView as a subview to a UIView in xib?
(1 answer)
Closed 4 years ago.
I have a TableViewController as a child view controller of a container view. For some reason, the table view controller does not show any of its rows. It shows its background color, but the information is absent.
Is this natural?
Here is the code:
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(topBar)
topBar.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
topBar.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
topBar.heightAnchor.constraint(equalToConstant: 80).isActive = true
topBar.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
view.addSubview(containerView)
containerView.topAnchor.constraint(equalTo: topBar.bottomAnchor).isActive = true
containerView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
containerView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
topBar.addSubview(subjects)
subjects.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
subjects.topAnchor.constraint(equalTo: view.topAnchor, constant: 30).isActive = true
topBar.addSubview(backButton)
backButton.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
backButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 30).isActive = true
let subjectsView = SubjectsTableViewController().view!
subjectsView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(subjectsView)
subjectsView.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
subjectsView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
subjectsView.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true
subjectsView.rightAnchor.constraint(equalTo: containerView.rightAnchor).isActive = true
}
You added SubjectsTableViewController.view as a subview. This is not enough. You should also add SubjectsTableViewController as a child of you view controller. Otherwise, there is not a pointer pointing to SubjectsTableViewController causing it deinit.
let child = SubjectsTableViewController()
addChildViewController(child)
stackView.addArrangedSubview(child.view)
child.didMove(toParentViewController: self)
You cannot simply rip a view controller's view away from that view controller and shove it into another view. There is a carefully prescribed dance that you must do to make one view controller the child of another, and you are not doing the dance. Therefore your SubjectsTableViewController comes into existence in one line and goes right back out of existence in the next line, leaving no view controller for the poor old table view to talk to. It no longer has any functionality. It is, as you say, empty.

MSMessagesAppViewController messes up UITableViewController scrolling

When my MSMessagesAppViewController changes the presentationStyle from compact to expanded and back to compact, my UITableView is messed up regarding its scrolling.
I am using AutoLayout to setup a UITableView inside of a View called contentView.
// Inside MSMessagesAppViewController
func createTableView() {
let tableViewController = MyTableViewController()
self.addChildViewController(tableViewController)
tableViewController.tableView.backgroundColor = UIColor.clear
tableViewController.tableView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(tableViewController.tableView)
NSLayoutConstraint.activate([
tableViewController.tableView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0),
tableViewController.tableView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 0),
tableViewController.tableView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 0),
tableViewController.tableView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0)
])
}
After expanding and collapsing the MSMessagesAppViewController, I can suddenly scroll past my last cell in the tableView...
Everything is working perfectly fine in the initial state. I noticed, that the scrollbar is visible on startup, but is not present after the size change...
This is how I setup my tableView in the controller:
// Inside MyTableViewController
func setupTableView() {
tableView.dataSource = self
tableView.register(QuickStandardTableViewCell.self, forCellReuseIdentifier: "standardCell")
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 64
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.separatorColor = .clear
tableView.sectionHeaderHeight = UITableViewAutomaticDimension;
tableView.estimatedSectionHeaderHeight = 8.0
self.extendedLayoutIncludesOpaqueBars = false
}
What I checked:
The contentView frame changes correctly
The tableView frame changes correctly
The contentInset does not change
The contentSize does not change
Does anybody know what I am missing?
Thanks in advance!
Try using a UIViewController with a UITableView inside instead of using UITableViewController.
I had the same problem with an UICollectionViewController and switching to UIViewController solved this problem.

How to turn off adjusting large titles by UITableView in iOS 11?

There's this large titles feature in iOS 11 that shows large title when the UITableViewController's table is scrolled to top, and gets collapsed to standard small title when the user scrolls the table away from top. This is standard behavior. I need the navigation controller to behave a bit differently - I need to always show the large title. How to achieve this?
Following code does not help, it still collapses when scrolled.
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.largeTitleDisplayMode = .always
I've achieved it unintentionally when embedded UITableViewController inside UIViewController.
I'm not sure whether it is an Apple's bug or intended behavior.
So stack is as simple as UINavigationController -> UIViewController(used as container) -> UITableViewController
Here is sample of view controller with embedded UITableViewController fullscreen
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var vc = UITableViewController(style: .plain)
var array: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
vc.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(vc.view)
view.addConstraint(view.leadingAnchor.constraint(equalTo: vc.view.leadingAnchor))
view.addConstraint(view.rightAnchor.constraint(equalTo: vc.view.rightAnchor))
view.addConstraint(view.safeAreaLayoutGuide.topAnchor.constraint(equalTo: vc.view.topAnchor))
view.addConstraint(view.bottomAnchor.constraint(equalTo: vc.view.bottomAnchor))
vc.tableView.delegate = self
vc.tableView.dataSource = self
array = "0123456789".characters.map(String.init)
vc.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "identifier")
title = "Title"
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath)
cell.textLabel?.text = array[indexPath.row]
return cell
}
}
Here is the result
Hope it helps.
P.S. Surprisingly, my current problem is that I don't know how to get collapsing behavior with such architecture :)
What I did was to add another view between navigationBar and TableView with a height of 1.
let tableViewSeperator: UIView = {
let view = UIView()
// remove the color, so it wont be visible.
view.backgroundColor = UIColor.systemBlue
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
One thing which is important is add this seperator view as a subview of your viewcontroller's view before tableView, otherwise it won't work
view.addSubview(tableViewSeperator)
view.addSubview(tableView)
or if you want to save one line of code, you can also do it like this.
[tableViewSeperator, tableView].forEach({view.addSubview($0)})
Then set its constraints like this.
tableViewSeperator.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
tableViewSeperator.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true
tableViewSeperator.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
tableViewSeperator.heightAnchor.constraint(equalToConstant: 1).isActive = true
The last thing is change the tableView TopAnchor to be the BottomAnchor of sperator View.
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true
tableView.topAnchor.constraint(equalTo: tableViewSeperator.bottomAnchor, constant: 0).isActive = true
tableView.bottomAnchor.constraint(equalTo: createItemBtn.topAnchor, constant: 0).isActive = true
Now when you scroll the the NavigationBar will stay as Large.
You need to add UIView(it's can be width=0, height=0) before add UITableView.
example
Then this code will work
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.largeTitleDisplayMode = .always

Resources