The first image is how my cells are currently and the second image is how I want them to be. I have a UITableViewController and want to programmatically change the layout margins however it does not work
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(named: "Gray")
tableView.backgroundColor = UIColor(named: "Gray")
tableView.contentInset.top = .padding
tableView.separatorStyle = .none
tableView.register(TaskCell.self, forCellReuseIdentifier: "taskCell")
tableView.layoutMargins = .init(top: 0, left: 20, bottom: 0, right: 20) // Does not work
}
Put a UIView inside the cell as background view and give margins to that view by adjusting its size in the storyboard. Then change the colour opacity of the cell's content view to 0
Related
I want the rows in my tableview to scale dynamicly based upon the content (2 labels, total of 3 lines of text). I keep getting this error (and my cells are set to standard size):
[Warning] Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a table view cell's content view. We're considering the collapse unintentional and using standard height instead. Cell: <ProjectSammy.AnnotationCell: 0x106061d80; baseClass = UITableViewCell; frame = (0 647.5; 414 70); autoresize = W; layer = <CALayer: 0x282d09ee0>>
I think I've cohered to all of the requirements (as mentioned in this post:https://stackoverflow.com/questions/25902288/detected-a-case-where-constraints-ambiguously-suggest-a-height-of-zero):
I fully constrain (top and bottom anchors) the labels in my custom cell:
private func configureContents() {
backgroundColor = .clear
separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
contentView.addSubviews(titleLabel, detailsLabel)
NSLayoutConstraint.activate([
titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor,constant: 5),
titleLabel.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
titleLabel.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor),
titleLabel.bottomAnchor.constraint(equalTo: detailsLabel.topAnchor),
detailsLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor),
detailsLabel.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
detailsLabel.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor),
detailsLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
])
}
I set the rows on the TableView to automic dimension:
private func configureTableView() {
tableView = UITableView(frame: view.bounds, style: .grouped)
view.addSubview(tableView)
tableView.delegate = self
tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
tableView.backgroundColor = .clear
tableView.register(AnnotationCell.self, forCellReuseIdentifier: AnnotationCell.reuseIdentifier)
tableView.register(AnnotationHeaderCell.self, forHeaderFooterViewReuseIdentifier: AnnotationHeaderCell.reuseIdentifier)
tableView.sectionHeaderHeight = 40
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 70
}
And I even supply an estimated row heigth in the delegate method: -NOT NEEDED1- can be done on tableview directly!
Where do I go wrong ?
The estimated row height can not be set to automatic dimension. You have to set it to a specific number try setting it to 44 which is by default the row height.
I am trying to add a separator to my uitableview cell. i tried this.
let separator = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 8.0))
cell.contentView.addSubview(separator)
But this adds the separator view on top of the cell, i need it to the bottom.
I also tried this way.
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(view)
view.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor).isActive = true
view.trailingAnchor.constraint(equalTo: cell.contentView.trailingAnchor).isActive = true
view.heightAnchor.constraint(equalToConstant: 8.0).isActive = true
view.topAnchor.constraint(equalTo: cell.contentView.bottomAnchor).isActive = true
But this gives me no common ancestor error. and i don't want to use storyboard. i need it because i am using same cell at different places, somewhere i need the separator somewhere not. what should i do?
Change constraint for this
view.topAnchor.constraint(equalTo: cell.contentView.bottomAnchor).isActive = true
to
view.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor).isActive = true
its better to create the line inside init of the custom cell and make it a property
let view = UIView()
then mange its state from cellForRowAt
view.isHidden = true/false
Here is a better way to use separators:
First enable separators in your UITableView by:
myTableView.separatorStyle = .singleLine
Then at your cellForRowAt function:
// Create your cell
// if you want to show the separator then
cell.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
// if you want to hide the separator then
self.separatorInset = UIEdgeInsets(top: 0, left: UIScreen.main.bounds.width, bottom: 0, right: 0)
This would work for cells in the same UITableView as well. Because by adding a left inset of screen width then it won't show on screen and if you set it to 0 it'll be displyed from left edge to right edge of the screen.
Also you can change the color or the insets of the separator by using other properties without using storyboards or xibs.
you can just try below line under viewDidLoad() that include the tableview
override func viewDidLoad() {
tableView.separatorStyle = .singleLine
}
I'm currently working on a side menu for my app, everything is working fine, however I've run into a problem the past week that I haven't been able to figure out how to solve.
The problem is that when the table view loads, the cells are pushed up and somewhat overlaps with the status bar, see picture 1 please.
Ideally I'm trying to achieve what picture 2 shows.
From what I've diagnosed, it has something to do with calling the Table View on viewDidLoad, because when I make a selection from the side menu and then dismiss it, the side menu cells are aligned correctly (see picture 2).
I'm not exactly sure what to make of the issue because the cells don't align correctly on initial load up of the app.
func configureTableView() {
tableView = UITableView()
tableView.delegate = self
tableView.dataSource = self
tableView.register(MenuOptionCell.self, forCellReuseIdentifier: reuseIdentifier)
tableView.backgroundColor = .lightGray
tableView.separatorStyle = .none
tableView.rowHeight = 80
view.addSubview(tableView)
tableView.anchorwithConstant(top: view.topAnchor, bottom: view.bottomAnchor, leading: view.leadingAnchor, trailing: view.trailingAnchor, paddingTop: 0, paddingBottom: 0, paddingLeading: 0, paddingTrailing: 80, width: 0, height: 0)
}
In the screenshots you shared, there is overlapping at top and bottom both. In iOS 11.0 and onwards safeAreaLayoutGuide represents the portion of your view that is unobscured by bars and other content. So adding top and bottom constraints with topLayoutGuide and bottomLayoutGuide resolves issue of overlapping.
Here is how you can add these constraints in Storyboard/Xib.
Use safeAreaLayoutGuide during programmatic constraint. Maybe it solves your problem
func configureTableView() {
tableView = UITableView()
tableView.delegate = self
tableView.dataSource = self
tableView.register(MenuOptionCell.self, forCellReuseIdentifier: reuseIdentifier)
tableView.backgroundColor = .lightGray
tableView.separatorStyle = .none
tableView.rowHeight = 80
view.addSubview(tableView)
tableView.anchorwithConstant(top: view.safeAreaLayoutGuide.topAnchor, bottom: view.bottomAnchor, leading: view.leadingAnchor, trailing: view.trailingAnchor, paddingTop: 0, paddingBottom: 0, paddingLeading: 0, paddingTrailing: 80, width: 0, height: 0)
}
I think you can use heightForHeaderInSection to increase the margin at the top of the table view. For example:
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 100.0
}
I have following suggestion. Please try this
override func viewDidLoad() {
super.viewDidLoad()
self.automaticallyAdjustsScrollViewInsets = false
}
I have created a Collection View and have made good use of the UICollectionView.elementKindSectionHeader by registering a Header class. See my code below:
override func viewDidLoad() {
super.viewDidLoad()
setupCollectionViewLayout()
setupCollectionView()
setupMenuBar()
}
var headerView: HeaderView?
fileprivate func setupCollectionViewLayout() {
if let layout = collectionViewLayout as? UICollectionViewFlowLayout {
layout.sectionInset = .init(top: padding, left: padding, bottom: padding, right: padding)
}
}
fileprivate func setupCollectionView() {
self.collectionView.backgroundColor = .white
//For iPhone X's make sure it doesn't cover the swipe bar at bottom
self.collectionView.contentInsetAdjustmentBehavior = .never
// Register cell classes
self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
self.collectionView.register(HeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerId)
self.collectionView.contentInset = UIEdgeInsets(top: 60, left: 0, bottom: 0, right: 0)
self.collectionView?.scrollIndicatorInsets = UIEdgeInsets(top: 60, left: 0, bottom: 0, right: 0)
}
which gives me a nice Header like:
But now I want a menu bar beneath the header, but above the main section of the collection view. I have created a MenuBar with the correct dimensions but I can't think what to constrain it to? See my code below to add a Menu Bar currently:
let menuBar: MenuBar = {
let mb = MenuBar()
return mb
}()
fileprivate func setupMenuBar() {
view.addSubview(menuBar)
view.addConstraintWithFormat(format: "H:|[v0]|", views: menuBar)
view.addConstraintWithFormat(format: "V:|-400-[v0(50)]|", views: menuBar)
}
..but this literally just pins the bar 400px down the entire view and does not move if you scroll up or down
Does anybody have an idea for this?
if you want this menu bar to move with the UITableView scrolling, it should be placed inside the header, below the "main header".
This approach abstraction is considering your header + menu bar as just one header.
I have added a UIView using storyboard and subclassing it. Within this view, I am adding a UITableView programmatically. Here is the code to create the tableview and add it:
private func commonInit() {
self.backgroundColor = .clear
self.categoryTableView = UITableView(frame: CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height))
categoryTableView?.delegate = self
categoryTableView?.dataSource = self
self.categoryTableView?.backgroundView = nil
self.categoryTableView?.backgroundColor = .yellow
self.categoryTableView?.isScrollEnabled = false
self.categoryTableView?.allowsMultipleSelection = true
self.addSubview(categoryTableView!)
}
This is what it looks like. I'm expecting the background of the tableview to be yellow (it is white in the screenshot)
I have also set the cells background color to clear which seems to be working. When I look at the UI hierarchy, it is pretty obvious that the White is coming from the the tableview.
I feel like this should be really strait forward. The strange part is the lines self.categoryTableView?.isScrollEnabled = false and self.categoryTableView?.allowsMultipleSelection = true both seem to be working, but the background color changing isn't.
I got the exactly same problem and found that just changing the tableView.backgroundColor after tableView.backgroundView = nil doesn't work.
My case also was a programmatically created UITableView inside an UIView.
The solution is to add a backgroundView to tableView and change the property backgroundColor of backgroundView object.
Swift 5 / iOS 12.x
Changing tableView background color
For any color other than .clear, the above should work:
self.tableView.backgroundView = UIView() //Create a backgroundView
self.tableView.backgroundView!.backgroundColor = .lightGray //choose your background color
Changing tableViewCells background color
Going a little further, some may find that the tableView background color didn't appear as intended because of the background colors of the UITableViewCell instances. A simple solution to make sure the cells have a transparent background:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.contentView.backgroundColor = UIColor.clear
cell.backgroundColor = .clear
}
I tested this in a playground, and the result was as expected.
import UIKit
import XCTest
import PlaygroundSupport
let view = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
PlaygroundPage.current.liveView = view
view.backgroundColor = UIColor.blue
let tableView = UITableView(frame:CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height))
tableView.backgroundColor = UIColor.yellow
view.addSubview(tableView)
The result:
My guess is something else is afoot here. Maybe something with the sizing of the frames, or where you are calling the commonInit() method?