I have a SegmentedControl on a Cell at the top of my tableView (the tableView consists of all static cells)...I want the top cell (and segmentedControl) to "stick" so that it is always visible as a user scrolls through the table (see screenshot below). Is this possible?
Usually, for applying this behavior you should add it as a header view instead of a cell. Header views in table view does "stick". But since you are adding static cells (UITableViewController), even if you tried to add a header view to the table view it won't apply the sticking behavior.
As a workaround you might need to add a new UIViewController contains a view on the top (the header view) and a container view, as follows:
The one hackish solution which pops to my mind is:
Declare header in your VC, or hold the reference:
private var header: UIView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 40))
Add it as a subview of tableView and set content inset equal to height of the header.
tableView.addSubview(header)
tableView.contentInset.top = header.frame.height
If your header use autolayout you will need to call
view.layoutIfNeeded() before setting content inset
and then for header to stick always to the top of tableView:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
header.frame.origin.y = scrollView.contentOffset.y
}
Related
I have an issue at the moment I am trying to put two table views inside a scrollview in one controller and these tableview are placed one below another. these two tableview uses scrollview for scrolling.
so I used vertical stackview inside scrollview. but when I create cell, both tableview height is not increases as well as scrollview is not able to scroll.
How should i use scrollview scroll for scrolling tableview?
-- scrollview
-----VerticalStackView
--------Tableview 1
--------Tableview 2
I'm really lost with this.Any help will be greatly appreciate it.
You need to make each UITableView define it's own size based on their content. To do that subclass both of them using the class below.
final class ContentSizedTableView: UITableView {
override var contentSize:CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
}
}
Then, for each UITableView you need to set isScrollEnabled = false. Otherwise their defined size will be 0.
Then just add each table view to the stack view you're using inside the scrollview. If their combined height is larger than the screen height, it'll scroll.
I am having a tableview in which the row height is dynamic as per its UILabel content (using UITableViewAutomaticDimension). Now, I need a 15 point border around the table view, that also changes as per the tableview height.
I tried two approaches -
Took a UIView and placed the tableView on top of it with constraints
as 15 on each side (top, bottom, left and right).
Added four UIViews around the tableView with 0 constraint for each
view to the tableView. (so that the views are always attached to the
tableView).
In both the approaches, the bottom view (or bottom area) is always giving a space in towards tableView bottom.
And to achieve the dynamic height to the tableView, I am using the below code -
open override func viewDidLayoutSubviews() {
if isPopup! {
tableView.frame = CGRect(x: tableView.frame.origin.x, y: tableView.frame.origin.y, width: tableView.frame.size.width, height: tableView.contentSize.height + 190)
tableView.reloadData()
}
}
Here are my Storyboard and the result on the simulator -
How to make the bottom UIView always be attached with the tableView bottom, so it looks like a border around the tableView?
Use your first approach and a custom table view subclass that uses its contentSize to determine its height. That way you can remove the code in your viewDidLayoutSubviews and should be good to go.
class AutoHeightTableView: UITableView {
override var contentSize: CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric,
height: contentSize.height)
}
}
I have a UITableView with a bunch of custom cells (and each cell has a custom height and dynamic height).
I want to add a footer view to the tableview that will always be on the bottom of the tableView contentSize.
If the contentSize is bigger than the screen size so in the bottom of the tableView (you scroll down, like a regular last cell).
If the contentSize is smaller than the screen size so the footer will still be in the bottom of the screen and there will be a gap from the last cell to the footer.
I've tried to add a footer like this:
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let myFooterView = Bundle.main.loadNibNamed("MyFooterView", owner: self, options: nil)?.first as! MyFooterView
myFooterView.delegate = self
myFooterView.frame = CGRect(x: 0, y: 0, width: self.tableView.frame.size.width, height: 100)
return myFooterView
}
But the footer is floating in on the bottom when I scroll. Tha'ts not what I want to achieve.
Any idea how can I achieve a non-floating footer like I want?
Thanks! :)
Add a view as a subview to the table view and adjust the position in scrollView:didScroll:. To be able to do this, add conformance to UIScrollViewDelegate to your view controller. I think a UITabelViewController is automatically the delegate for the table view (which is also a UIScrollView).
The tricky part is the calculation of the position based on the content size, the content offset, the size of the view and the size of your footer.
I have a UIView with a UITableView right below it. The tableview has a custom header which hold a UISearchbar and a UISegmententedController. The top view and tableview are constrained to each other and to the superview. If I hide the top view, the header of the tableview gets stretched.
Top view visible:
Top view hidden (height constraint set to 0):
My expectation would be that when I hide the top view my tableview content should scroll up, but instead of repositioning the cells, the tableview stretches out the header view.
Thanks for any help!
I'm not sure why but if the custom tableView header is created from a xib then it gets messed up. But if the view is created programmatically it works. I don't know why but to fix the problem just needed to create the tableview header programmatically
Bad:
if let headerView = Bundle.main.loadNibNamed("HeaderView", owner: self, options: nil)?[0] as? HeaderView {
tableview.tableHeaderView = headerView
}
Good:
tableview.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 80))
If you want to make the tableView scroll up, I would recommend getting the height constraint of the top view and reducing it to 0. You can update the height constraint in a UIView.animate block to have a smoother transition when showing and hiding the top view.
Refer here for more details: AutoLayout with hidden UIViews?
I can't center a view that has been placed as a subview of a UITableView's tableHeaderView in a storyboard using auto layout.
In a storyboard, I have a UITableView. I dragged a UIView (the red view) to the top, released, and it created a table header view automatically. I then dragged and dropped another UIView (the yellow view) on top of the table header view, resized, and applied some constraints to ensure it stays centered:
When I run the app on the simulator, here's what I get:
The yellow view is obviously not centered. However, the "Filter" button at the bottom is.
I know it's tricky to get the height right using auto layout and storyboards and table header views (and you can see that the height of the red view is definitely incorrect), but at this point, I'm just trying to solve for horizontally centering my yellow view.
Am I able to set this all up in my storyboard without having to configure my constraints in code?
Make sure that your UITableView has the leading, trailing, bottom, top constraints set up against its superview.
Check the table header view and all sub views have Autoresize Subviews enabled:
You can also force the table to re-render the header view by re-setting it to the same view:
[self.tableView setTableHeaderView:self.outletToHeaderView];
Update: to resize the table header view, give give it an appropriate frame in viewWillAppear:
CGRect newFrame = self.outletToHeaderView.frame;
newFrame.size.width = self.tableView.bounds.size.width;
newFrame.size.height = 44;
[self.outletToHeaderView setFrame:newFrame];
// Then reset it to force the table view to re-render/accommodate
[self.tableView setTableHeaderView:self.outletToHeaderView]
In your file TableViewHeader:
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
yourView.translatesAutoresizingMaskIntoConstraints = false
yourView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
}
You need to use prototype cell from table view, than dequeue it with reusable identifier and return it contentView. Only that's do the trick
var headerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.headerView = (self.tableView.dequeueReusableCellWithIdentifier("CustomHeaderCell") as! UITableViewCell).contentView
}
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return self.headerView
}
upd:
Oh sorry, my example is written in Swift. But it's easy to understand how to do the same in Obj-C