I've got a UIView within a UIScrollView, both of which I've created programmatically. The white rectangle is the UIView.
I want to put a UITableView within the UIView so that they're roughly the same size, except I'd like to leave room for the title at the top of the view. Here's what I've tried:
let tableView = UITableView(frame: view1.bounds)
view1.addSubview(tableView)
tableView.center(in: view1)
tableView.rowHeight = 30
tableView.backgroundColor = .blue
Except nothing shows up. How can I fix this?
If you're not instantiating your UIView with a frame: argument, you need to do so. Everything will seem normal if you omit this, and simply use the view1.size() method, except for some reason the tableView will not appear.
I tried below and I could see the table view.
let uiView = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
self.view.addSubview(uiView)
let tableView = UITableView(frame: uiView.bounds)
uiView.addSubview(tableView)
tableView.rowHeight = 30
tableView.backgroundColor = .blue
tableView.separatorColor = .black
Below is my result :
You have to remove line tableView.center(in: view1)
Related
I a have created a footer for my UITableView like so:
let customView = UIView(frame: CGRect(x: 0, y: self.view.bounds.height - 50, width: self.view.bounds.width, height: 50))
customView.backgroundColor = UIColor.red
commentText = UITextField(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width - 50, height: 50))
commentText.backgroundColor = UIColor.white
commentText.layer.borderColor = UIColor.gray.cgColor
commentText.layer.borderWidth = 1
commentText.borderStyle = .roundedRect
commentText.placeholder = "Enter Comment"
let submitButton = UIButton(frame: CGRect(x: self.tableView.bounds.width - 50, y: 0, width: 50, height: 50))
submitButton.setTitle("Go", for: .normal)
submitButton.backgroundColor = UIColor.blue
submitButton.addTarget(self, action: #selector(self.submitButtonPressed(_:)), for: .touchUpInside)
customView.addSubview(commentText)
customView.addSubview(submitButton)
tableView.tableFooterView = customView
and here is the result of it in the screenshot:
What I am trying to do is have the footer always at the bottom of the screen, is this possible?
A table view footer is always at the end of the table view, after the last row in the table view. This is true no matter how many rows are in the table view.
If you want a view that stays at the bottom of the screen and never scrolls no matter how many rows there are, then you don't want a table view footer. You simply want a view added to the bottom of the screen.
The best solution is to use a UIViewController that has your "footer view" pinned to the bottom and a table view added that fills the rest of the screen.
maybe you can just add the footer view at the bottom of the screen view, not add it as a footer view of UITableView, since you don't want the textfield and submit button to move when UITableView scroll.
You can just add your custom view to the view itself instead of the tableview.
view.addSubView(customView)
Are there any tutorials, or examples to make a particular value of a table view cell from the table view return in the fixed footer view. A similar or simple concept would also be helpful. NOTE: This question is the logic part. Not for the UI design part.
Create your Custom view:
let customView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
customView.backgroundColor = UIColor.red
var label = UILabel(frame: CGRectMake(0, 0, 200, 21))
label.center = CGPointMake(160, 284)
label.textAlignment = NSTextAlignment.Center
label.text = "sawthinkar"
customView.addSubview(label)
And Then add into table View footer:
tableView.tableFooterView = customView
Also you can create your custom view with xib and set the required values in the custom view.
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?
Here is my NavBar
Now I know how to add a customView on the leftBarButtonItem by using this code
navigationItem.leftBarButtonItem!.customView = someCustomView
As seen on my screenshot here
But the question is, Is there a way that I could detect if there are any navigationItems next to my leftBarButtonItem so I could set the width to be dynamic? instead of overlapping like the screenshots?
Here's more screenshots of my test case
Note: Yes I know how to set the frame by using the code someCustomView.frame = CGRect(.....) also it seems that the UINavigationBar/Item inherits from NSObject rather than UIView
Edit: So apparently after doing much coding, recoding, and research, the only part of the UINavigationBar/UINavigationItem that automatically resizes itself according to the left and right barButtons is the titleView which kind of sucks in a way.
So according to my knowledge, the only way to achieve this:
is by using the titleView property of the UINavigationItem which doesn't answer my question.
If -hopefully- these are the outputs that are looking for:
Then you should set the titleView of the navigationItem:
A custom view displayed in the center of the navigation bar when the
receiver is the top item.
It dynamically handles the width to not overlap.
For example, in the follwoing code snippet, I'll set the value of navigationItem.titleView as a UILabel (and of course you can customize it):
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 40))
label.text = "Some very long text that should be in the middle of the navigation bar"
label.textAlignment = .center
label.textColor = UIColor.blue
navigationItem.titleView = label
}
The output should be similar to the screenshots above.
Note that "Item 01", "Item 02" and "Item 03" that appear in the screenshots are added directly in the storyboard, there is no code related to adding them.
If you want to let the label to at next of "Item 01" button, simply let it:
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 40))
label.text = "my label"
label.textAlignment = .left
label.textColor = UIColor.blue
navigationItem.titleView = label
Output should be like:
Hope this helped.
This is how I customise my UIBarButtonItem:
if DBAppSettings.imageViewForCartBarButtonItem == nil {
DBAppSettings.imageViewForCartBarButtonItem = UIImageView(frame: CGRectMake(5, 5, 30, 30))
DBAppSettings.imageViewForCartBarButtonItem.backgroundColor = UIColor.greenColor()
}
let wrapperView = UIView(frame: CGRectMake(0, 0, 40, 40))
wrapperView.backgroundColor = UIColor.yellowColor()
wrapperView.addSubview(DBAppSettings.imageViewForCartBarButtonItem)
let cartBarButtonItem = UIBarButtonItem(customView: wrapperView)
Once I setup my UIBarButtonItem it looks ok:
but when I push and then pop view controller (this means that I use the same green subview to load it into another UIBarButtonItem) from the navigation stack, it is yellow. It looks like green subview is deallocated. Why?
This is how I keep references to my green subview:
class DBAppSettings: NSObject {
static var imageViewForCartBarButtonItem: UIImageView!
}
note:
Everything works fine, when I keep green subview locally:
let green = UIImageView(frame: CGRectMake(5, 5, 30, 30))
green.backgroundColor = UIColor.greenColor()
wrapperView.addSubview(green)
As I wrote in my comment. UIView can have just one superview. If you add it as a subview 2nd time, it's removed from the first superview and then added to the new one. Check addSubview... docs:
Views can have only one superview. If view already has a superview and
that view is not the receiver, this method removes the previous
superview before making the receiver its new superview.
It's not deallocated. It's just removed from your first wrapperView.
You can use custom factory method, like the following one:
extension UIBarButtonItem {
static func myBarButtonItem() -> UIBarButtonItem {
let imageView = UIImageView(frame: CGRectMake(5,5,30,30))
imageView.backgroundColor = UIColor.greenColor()
let wrapperView = UIView(frame: CGRectMake(0, 0, 40, 40))
wrapperView.backgroundColor = UIColor.yellowColor()
wrapperView.addSubview(imageView)
return UIBarButtonItem(customView: wrapperView)
}
}
Don't be afraid even if you use UIImages. UIImages are cached, shared, ... One image is not multiple times in memory, just once. Talking about UIImage & init?(named name: String).
In every UIViewController, just use UIBarButtonItem.myBarButtonItem(). Multiple instances of your wrapperView, imageView and one UIImage.