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
}
Related
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
I have this UIView added to my UITableView:
self.tableView.addSubview(viewInfoPlus)
self.viewInfoPlus.frame = CGRect.init(x: kWidth - 193 - 32, y: 751, width: 193, height: 103)
The one signaled with the red arrow.
The UIView in the screenshot have the right frame but when I try to reload the UITableView or just some cell/cells using:
let indexPath = IndexPath.init(row: 0, section: TableSection.plus.rawValue)
UIView.setAnimationsEnabled(false)
self.tableView.beginUpdates()
tableView.reloadRows(at: [indexPath], with: .none)
self.tableView.endUpdates()
UIView.setAnimationsEnabled(true)
The UIView automatically change the frame to the wrong one as you can see in this screenshot.
But when the user scroll to the top of UITableVIew the UIView automatically change again their frame to the right one.
Obviously I never changed the frame in the code.
Use Constraints instead of frame.
Setting Frames there is no guarantee when resize. Autolayout allows view that dynamically adjust to different size classes and positions. Check following example
Example:
viewInfoPlus.translatesAutoresizingMaskIntoConstraints = false
viewInfoPlus.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
viewInfoPlus.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 20).isActive = true
viewInfoPlus.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
viewInfoPlus.heightAnchor.constraint(equalToConstant: 103).isActive = true
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
}
On iOS 11 and 12, I can't figure out a way to make the searchBar use the whole width of the screen.
navigationItem.searchController = searchController
I can add more margin using:
let sb = searchController.searchBar
let selector = #selector(setter: UIScrollView.contentInset)
if sb.responds(to: selector) {
sb.perform(selector, with: UIEdgeInsets(top: 5, left: 0, bottom: 5, right: 35))
}
If I try to set left and right to 0... it just uses the default layout.
Edit:
Getting closer:
for tf in sb.subviews.first!.subviews where tf is UITextField {
tf.translatesAutoresizingMaskIntoConstraints = false
tf.widthAnchor.constraint(equalToConstant: width).isActive = true
tf.layoutIfNeeded()
}
Now I am trying to figure out a way to apply constraints so that when the textfield is active, it will make space for the cancel button (UINavigationButton)
Have you tried this?
let width = UIScreen.main.bounds.size.width
searchBar.translatesAutoresizingMaskIntoConstraints = false
searchBar.widthAnchor.constraint(equalToConstant: width).isActive = true
Here the search bar width will always equal the full width of the device's screen.
I added a scrollview to my viewController and anchored it to my view, like this:
class MainContainer: UIViewController {
let mainScrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.backgroundColor = .lightGray
scrollView.isPagingEnabled = true
scrollView.showsHorizontalScrollIndicator = false
scrollView.bounces = false
scrollView.contentInsetAdjustmentBehavior = .never
return scrollView
}()
override func viewDidLoad() {
view.addSubview(mainScrollView)
mainScrollView.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
}
}
The above code works great. Constraints work as expected
I then try to append a view to it by adding
mainScrollView.addSubview(cameraView.view)
That is when the constraints act weird on my scrollview. For some reason the width and height of the scrollview is doubled. Here is a screenshot of my view hierarchy to illustrate my issue
In the image I selected the scrollview and right clicked to "Show Constraints" which for some reason are doubled in width and height. Before adding the view controller the constraints where fine. The added view controller appears fine but the constraints on the scrollview are messed.
Make sure that cameraView.view's top , bottom , leading and trailing constraints are hooked to the scrollview (the superview) then give a height and width to cameraView.view , also don't forget to make translateAutoresizing.... equal to false for the scrollview . . .