I am using a grouped UITableView in XIB. When loaded its showing extra space on top of first section header.
What I have tried so far:
if #available(iOS 11, *) {
self.recordTableView.contentInsetAdjustmentBehavior = .never
} else {
//Doesn't Work
//self.automaticallyAdjustsScrollViewInsets = false
self.parent?.automaticallyAdjustsScrollViewInsets = false
}
Also tried setting tableView -> Content Insets to Never in XIB.
What am I missing here?
Well you will need to understand two things. Setting zero height of TableHeaderView and SectionHeaderHight
This will set your Table Header Height to zero
tableView.tableHeaderView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: self.view.frame.size.width, height: CGFloat.leastNormalMagnitude)))
This will set section header hight (NOTE : YOU might not need this. Depends on your use case)
tableView.sectionHeaderHeight = CGFloat.leastNormalMagnitude
Related
I'm trying to use a custom view as an accessory view over the keyboard, for various reasons, in this case, it is much preferred over manual keyboard aligning because of some other features.
Unfortunately, this is a dynamic view that defines its own height. The constraints all work fine outside of the context of an accessoryView without errors, and properly resizing
When added as a keyboardAccessoryView it seems to impose a height of whatever the frame is at the time and break other height constraints
It appears as:
"<NSLayoutConstraint:0x600003e682d0 '_UIKBAutolayoutHeightConstraint' Turntable.ChatInput:0x7fb629c15050.height == 0 (active)>"
(where 0 would correspond to whatever height had been used at initialization
It is also labeled accessoryHeight which should make it easy to remove, but unfortunately, before I can do this, I'm getting unsatisfiable constraints and the system is tossing my height constraints
Tried:
in the inputAccessoryView override, I tried to check for the constraints and remove it, but it doesn't exist at this time
setting translatesAutoresizing...Constraints = false
tl;dr
Using a view as a KeyboardAccessoryView is adding its own height constraint after the fact, can I remove this?
Looks like keyboard doesn't like inputAccessoryView with height constraint. However you still can have inputAccessoryView with dynamic height by using frame (it is still possible to use constraints inside your custom inputAccessoryView).
Please check this example:
import UIKit
final class ViewController: UIViewController {
private let textField: UITextField = {
let view = UITextField()
view.frame = .init(x: 100, y: 100, width: 200, height: 40)
view.borderStyle = .line
return view
}()
private let customView: UIView = {
let view = UIView()
view.backgroundColor = .red
view.frame.size.height = 100
view.autoresizingMask = .flexibleHeight // without this line height won't change
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(textField)
textField.inputAccessoryView = customView
textField.becomeFirstResponder()
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
self.customView.frame.size.height = 50
self.textField.reloadInputViews()
}
}
}
Happens only when compiled with Xcode9 and iOS 11 devices.
Section header does not automatically stick to the top leaving a space in the view through which content can be seen. (Screenshot included)
Happens when tapped for full screen.
But some times the header sticks to the top on the tap action
On scrolling up/down the header sticks to the top. (GIF included)
Screenshot
GIF
Correct me if I am wrong, the floating nature of section header is provided by UITableViewStyle set to plain.
tableView = UITableView()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44
tableView.cellLayoutMarginsFollowReadableWidth = false
tableView = UITableView(frame: self.view.frame, style: UITableViewStyle.plain)
tableView.sectionHeaderHeight = 44
// tableView.estimatedSectionHeaderHeight = 0
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "content")
tableView.register(UITableViewHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: "hContent")
tableView.dataSource = self
tableView.delegate = self
Tried to set the estimatedSectionHeaderHeight to 0 (Disable it) as suggested here. But it did not work.
We tried reloading the tableView data in our hideNavBar func as suggested here for the similar problem. But that would scroll us to some other content.
Tried the following as suggested by other answer in our hideNavBar function and again facing the same issue where we are scrolled to some distant content.
tableView.reloadData()
tableView.layoutIfNeeded()
tableView.beginUpdates()
tableView.endUpdates()
The change could be due to change in safe area constraints with iPhone X. So, instead of reloading the whole data, I suggest adding a reference for the frame.
A workaround that worked perfectly for me even in iPhone X.
Add the following lines in the respective functions.
func hideNavbar() and hideTabbar ()
tableView.frame = CGRect(x: 0, y: 0.01, width: view.bounds.width, height: view.bounds.height)
func showNavbar() and hideTabbar ()
tableView.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height)
func setTableHeader(){
let headerWidth = Double(tableHeader.frame.width)
// also tried let headerWidth = Double(tableView.frame.width)
print("header width is \(headerWidth)")
}
func viewWillAppear(){ output --> 351
setTableHeader()
//also tried in View Did Appear
}
func viewDidDisappear(){ output --> 296
setTableHeader()
}
The outputs refer to what occurs when run on Iphone SE. I designed my tableview and table header with constraints in Storyboard with the Iphone 6 display. I was able to get the result I wanted by changing setTableHeader to reflect view.frame.width - (left and right constraints from storyboard), however I was wondering why I couldnt get this to work, and what the less hacky work around would be? Also I am in actuality setting the dimensions of table header's subviews inside setTableHeader, but these subviews have no constraints (programatically nor in storyboard), in case that is relevant.
Thank you.
Try this , The solution was to override UIViewController().viewDidLayoutSubviews(), get the proper size of the header view based on it’s constraints, set the frame on the header, and reset it as the table header view
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Dynamic sizing for the header view
if let headerView = tableView.tableHeaderView {
let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
var headerFrame = headerView.frame
// If we don't have this check, viewDidLayoutSubviews() will get
// repeatedly, causing the app to hang.
if height != headerFrame.size.height {
headerFrame.size.height = height
headerView.frame = headerFrame
tableView.tableHeaderView = headerView
}
}
}
Please try to add this code to viewDidLayoutSubviews method.
All views got their actual sizes only alter layout. Method viewDidLayoutSubviews called before viewDidAppear and after viewWillAppear.
I have just tried below lines of code, but I doesn't work correctly. I wonder that how can I provide this case for header or footer programmatically, may be using autolayout I don't know exactly which one solved my problem. I'm using xib file both of UITableViewHeaderFooterView.
If someone explain I would be great.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Dynamic sizing for the footer view
if let footerView = tableView.tableFooterView {
let height = footerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
var footerFrame = footerView.frame
if height != footerFrame.size.height {
footerFrame.size.height = height
footerView.frame = footerFrame
tableView.tableFooterView = footerView
}
}
}
The UITableView calculates the HeaderFooter before they displayed, you can't update that height without calling reloadData() again.
Have you tried to use AutoLayout on those HeaderFooterViews?
I would set up the view from xib with the right constraint, and then:
self.tableView.estimatedSectionHeaderHeight = 100
self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension
I'm trying to create a UITableView with a header view using autolayout using storyboards. It looks fine in Xcode, but when I run the app, it does not look the same.
In Xcode:
In the app:
The image has a constraint for 150x150, and there are 8-high constraints between the top-image, image-middle label, middle description-label and description label-bottom.
Both labels have numberOfRows set to 0 and lineBreakMode set to ByWordWrapping.
I have tried settings the frame via:
if let headerView = self.tableView.tableHeaderView {
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
println("Setting height to \(height)")
var headerFrame = headerView.frame
headerFrame.size.height = height
headerView.frame = headerFrame
self.tableView.tableHeaderView = headerView
}
One of the original issues was that I had some erroneous constraints (that for some reason Xcode only started complaining about today), so I have removed those and set a contentHuggingPriority of 252 (higher than all others) on the app name label. When I resize the header view manually in the storyboard the image and app name label stay the same height, and the description label grows. It would appear that the apps uses the size of the header in the storyboard at run time, and doesn't get the height from its children.
Answering my own question here:
There are 2 steps that seem to get this to work. The first is in ViewDidLoad, and the second is in viewDidLayoutSubviews:
var headerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
if let currentTableHeaderView = self.tableView.tableHeaderView {
currentTableHeaderView.removeFromSuperview()
}
// Setting the table header view with a height of 0.01 fixes a bug that adds a gap between the
// tableHeaderView (once added) and the top row. See: http://stackoverflow.com/a/18938763/657676
self.tableView.tableHeaderView = UIView(frame: CGRectMake(0, 0, CGRectGetWidth(self.tableView.frame), 0.01))
self.headerView = AboutTableViewHeaderView(frame: CGRectZero)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let tableHeaderView = self.headerView {
var frame = CGRectZero
frame.size.width = self.tableView.bounds.size.width
frame.size.height = tableHeaderView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
if self.tableView.tableHeaderView == nil || !CGRectEqualToRect(frame, tableHeaderView.frame) {
tableHeaderView.frame = frame
tableHeaderView.layoutIfNeeded()
self.tableView.tableHeaderView = tableHeaderView
}
}
}
Hopefully that all makes sense. The viewDidLayoutSubview code is via http://osdir.com/ml/general/2014-06/msg19399.html