I'm trying to create a footer in a table view using Swift. A single footer that's always at the bottom of the screen. I set up a .swift file called TableViewFooter.swift that creates a class called TableViewFooter, a subclass of UITableViewHeaderFooterView. TableViewFooter has 2 labels, a button, and a progress view. In my TableViewController I put the code:
let nib = UINib(nibName: "TableViewFooter", bundle: nil)
tableView.registerNib(nib, forHeaderFooterViewReuseIdentifier: "TableViewFooter")
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let currSection = fetchedResultsController.sections?[section]
let title = currSection!.name
let cell = self.tableView.dequeueReusableHeaderFooterViewWithIdentifier("TableViewFooter")
let header = cell as! TableViewFooter
header.titleLabel.text = title
return cell
}
I'm getting an "Expected declaration" error after the tableView.registerNib line, a "Use of unresolved identifier 'fetchedResultsController'" error after the let currSection line, and a "Use of unresolved identifier 'header'" error after the header.titleLabel.text line. I'm new at this, but I'm using a Swift file, not a nib, so shouldn't I be putting something else instead? The only tutorials I found are using nibs or the cryptic Apple reference. Any help would be greatly appreciated!
It sounds like you want one of two things:
A UITableView footer. This is a view at the bottom of your UIScrollView, meaning that it only shows when you scroll to the bottom of the table. You can modify this, by accessing the tableViewFooter property of your UITableView, in your view controller, which I assume is your delegate and dataSource.
Or, a view that always remains at the bottom of your screen. This is not a table view footer, but a view that you will add to the main view of your view controller. To do this, add a custom UIView at the bottom of your view, making sure that it does not overlap with your table view (otherwise, the user won't be able to get to the bottom cell), and make sure that the scrollView property of your table view is large enough to contain all of its cells.
Related
I have a xib that is a UIView, with class MyUIView. I'd like to re-use this view as a Table View Cell, but I'm not sure how I would do that.
I know I have to register the xib for my table view, like:
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "MyUIView", bundle: nil), forCellReuseIdentifier: "MyUIView")
}
But other than that, I'm not not sure how to upcast it to a Table View Cell. What modifications do I need to make to the regular Table View/Table View Cell process to use my UIView xib as the cell?
Add a UIView control to your table view cell. Then set its class to MyUIView.
I have a view controller with a tableview containing a list of chats, a search controller enbeded in the navigation item (iOS 11 feature)
let searchController = UISearchController(searchResultsController: nil)
searchController.dimsBackgroundDuringPresentation = false
navigationItem.searchController = searchController
definesPresentationContext = true
When the user taps a chat in the table view the app pushes a new view controller with another table view containing messages for that chat. That works like it is supposed to:
The problem is that when the user activates the search controller, find some chat and taps it, the pushed view controller containing table view with the chat messages does some really strange animation with the table view that should not happen:
I load the data before the actual navigation and bind it to the table view in viewDidLoad using just reload() on the table view. The problematic table view uses auto layout and custom cells.
The problem is very similar to UITableView has unwanted animation when reloadData is called but for me it only happens when the iOS 11 search controller is active.
Edit: If I remove tableView.rowHeight = UITableViewAutomaticDimension and use a fixed height using func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat the problem is still there
If you just hide the searchBar before pushing a new viewController then it may fix your problem.
You need to create a global variable for searchBarCancelButton and find the cancel button from its subviews when you search something
let buttons = searchController.searchBar.subviews.first?.subviews.filter { (view) -> Bool in
return NSStringFromClass(view.classForCoder) == "UINavigationButton"
} as? [UIButton]
searchBarCancelButton = buttons?.first
then you can manually cancel it.
self.searchBarCancelButton?.sendActions(for: .touchUpInside)
Personally, I would simply hide the searchView controller before presenting the new view controller.
( Using UIView.animates with a completion handler for example )
I would not try to investigate further because since iOS11, there is an esoteric problem in the safe area management. A bug ? :)
Even the launch screens layouts are not correctly handled.
So many majors logos miss their middle part at launch !
You can try to call cell.layoutIfNeeded() right after dequeuing and setting a content of the cell
iOS 11 completely revamped the safe area API, including scroll view inset adjustment behaviors, which can cause unwanted animation when ignored. Therefore, disable automatic content inset adjustment for the scroll view with the unwanted animation:
if #available(iOS 11.0, *) {
tableView.contentInsetAdjustmentBehavior = .never
} else {
// < iOS 11 logic
}
Do not invoke reloadData() method in your viewDidLoad or viewWillAppear. Instead of this reload your tableView with empty data in viewDidLoad so your tableView will show nothing and then in your viewDidAppear invoke reloadData() method to load all of your chats. This will restrict your tableView from loading with unwanted animation.
var shouldShowEmpty = true
func viewDidLoad() {
super.viewDidLoad()
tableView.reloadData()
}
func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
shouldShowEmpty = false
tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if shouldShowEmpty {
return 0
}
return yourArray.count
}
As per attachment, It looks like due to auto layout, cell's element's height was zero (UILabel or UIImageView) and then suddenly when table view reloads it gets the data inside the cell which increase its height(automatic dimension or whatever) which cause this animation.
Try to push it without animation or try to set fix cell's element's height and width and check is it still showing this animation.
Did you check without invoking UISearchBar, If you select on any cell same animation is happening ?? or did you try to remove UISearchbar and select on the cell and check the animation part ?
Please share your code so we can see more clearly.
I have had a similar problem, and I believe that solution is the same. The keyboard is causing the problem, to be more correct, keyboardWillHideNotification trigger. You have text field at the bottom, that probably listens to notifications for keyboard show/hide, where layoutIfNeeded() is triggered if you animate bottom constraint so that your keyboard doesn't overlap your text field. So when you finish your search in the search text field, keyboardWillHideNotification gets triggered at an unwanted time. I solved my issue by calling:
resignFirstResponder()
for the text field that causes this event. In my case, that was after pressing the button, in your, I believe it's in didSelect tableView cell in the search table view.
If you are still active at this issue, please let me know if you manage to solve it. I broke my head trying to solve this issue, which apparently is so simple and straightforward.
In VC2 Try a delay function before reloading table
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
tableView.reloadData
}
or else
In VC1 in didSelect resign first responder of search controller before pushing to VC2
or
In VC1 in didSelect resign first responder of search controller and set a delay before pushing to VC2.
I have a childViewController on a UICollectionViewController. I have so my childViewController appears on the screen. But when I register a cell collectionView?.register(MyCustomCell.self, forCellWithReuseIdentifier: CellId) and use numberOfItemsInSection and cellForItemAt. The problem is that the cells wont appear, I have checked the code so it´s right. Can it be something with the childViewController?
Generally it's not preferred to add any child view or viewController to UICollectionViewController or UITableViewController as you will see un-expected results as both of them inherits from scrollview and make the added content scroll able or scattered any place, if you have then better create a custom viewController with a collectionView and the childViewController
I got a table View and collection view on the each cell.
When I tapped the cell, following code will be invoked in cell's didSelectRowAt:IndexPath method.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
navigationController?.pushViewController(anotherViewController(), animated: true)
}
The anotherViewController is an empty view controller on storyboard for now. It only print "I'm coming" in viewDidLoad().
Here is the problem:
When I touched the cell, the push animation seems got stuck, pleas check the following GIF.
I'm really confused in what's happend.
Feel free to give any Advice.
The following Image shows the view hierarchy.
Cells on the table view.
Collection view and other components on the cell's content view.
At the end, image views on the collection view's content view.
The solution for me was to explicitly set the background color of the new view controller, even if it's black.
I had the same issue and since I'm not using storyboard, this was the solution for me.
I suspect the problem rests in the anotherViewController() reference. I was even able to reproduce the problem when I pushed to a UIViewController instance:
navigationController?.pushViewController(UIViewController(), animated: true)
But when I instantiate a scene from a storyboard, that worked fine. Obviously, you need a scene with the appropriate storyboard identifier:
let controller = storyboard!.instantiateViewController(withIdentifier: "Details")
navigationController?.pushViewController(controller, animated: true)
Or, if I defined segue between the two view controllers and performed the segue, that also worked:
performSegue(withIdentifier: "DetailsSegue", sender: self)
I used the ExpandTableView of this repository on Github:
Repo -> https://github.com/SubhiH/ExpandableTableView
I need know how i connect a position of the array of this expandable view in a View in the Main storyboard, example:
Image of the ExpandableTableView
I want that when a User click for example in the cell a1 user is sent to a TableView (View) on Main storyboard.
Any ideas?
I think you are looking for the function func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath), that you already implemented in ExpandableTableViewViewController.swift.
There, you can add a segue to your Main View Controller, passing it the data.
if let resultController = storyboard!.instantiateViewControllerWithIdentifier("IDOfYourMainView") as? ResultViewController {
//Here you can access to the view's functions and attributes.
//You can set, for example, an imageView and set it the image you want.
//Then, when the view loads (Read next line), it should have your image loaded.
presentViewController(resultController, animated: true, completion: nil)
}