I know the tableview header and footer but I want to add UIView between the row of tableview in objective-c. and uiview have three button also.
but how can it possible. Anybody can help me..
You can not add UIView in between two row or cell of UITableView. You need to customise your cells. And while filling data to your datasource of UITableView you need some kind of indications which you need to match in your cellForRowAtIndexPath method of UITableView and based on condition you need to show your data cell or custom UIView which is already in your custom cell.
Every UITableViewCell is a child of UIView class.
So in effect all your cells are UIViews which you can customize in any way you want.
So what you want to do is use custom cell. Create a model class for it, customize it as you want.
Suppose I have a UIView and I am creating its object in Controller class in which I have TableView:
var obj_ProfileView : UserProfileView!
In ViewDidLoad Method:
self.obj_ProfileView = Bundle.main.loadNibNamed("UserProfileView", owner: self, options: nil)![0] as! UserProfileView
Then In TableViewFooter Method:
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
{
if section == 0
{
//Do as per your requirements
return 184.0
}
else
{
//Do as per your requirements
return 45.0
}
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView?
{
if section == 0
{
return obj_ProfileView
}
else{
return nil
}
}
Related
We're want to do two changes to our search results.
Change the Collection View Controller to a Table View Controller
Have only the second section header show and have it scroll away inline. In other words, don't be sticky and don't stay at the top.
In regards to changing the Collection View Controller to a Table View Controller. This involves changing the section headers from a UICollectionReusableView subclass to something else. Normally, the change would be to using a UITableViewHeaderFooterView.
In regards to making the second section header scroll on up inline and out of sight and thus not be sticky, there's an issue to my solution.
To make it non-sticky, I changed the tableview to be UITableViewStyleGrouped. This causes a look for the second section that is different than what we have now. We would like it back to how it looks now.
Here's what we have in the App Store now:
Here's what we have when trying the UITableViewStyleGrouped approach and other changes:
Notice the extra gray above the "Other cars..." section header? I figure I can probably solve the rounded corners and insets via a subclass of the UITableViewHeaderFooterView. However, it's not clear how to handle the extra space above the section.
Code:
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.estimatedRowHeight = 800
self.tableView.rowHeight = UITableViewAutomaticDimension
let nib = UINib(nibName: "SearchResultsOtherCarsHeader", bundle: nil)
tableView.register(nib, forHeaderFooterViewReuseIdentifier: "SearchResultsOtherCarsHeader")
:
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section != 1 {
return 0
}
return 30
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section != 1 {
return nil
}
let searchResultsOtherCarsHeaderView = self.tableView.dequeueReusableHeaderFooterView(withIdentifier: "SearchResultsOtherCarsHeader") as! SearchResultsOtherCars
return searchResultsOtherCarsHeaderView
}
How to get rid of the extra gray space above the section header?
The solution:
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0.01
}
This solution was inspired by the comment made by #maddy and iPhone UITableView : How to remove the spacing between sections in group style table?
I'm using a custom cell as a section header in my UITableView. In that cell there are three buttons. If any of the buttons are clicked in that section's cell, it should reload that custom section cell only, not any rows. Is this possible?
I was using the following code to reload that cell:
tableViewHome.reloadSections([1], with: UITableViewRowAnimation.none)
It's hiding my section cell and distorting my entire table.
UPDATE
I'm using UITableView and following code I'm using:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cellHeader = tableViewHome.dequeueReusableCell(withIdentifier: "header") as! HeaderTableViewCell
cellHeader.filter1btn.addTarget(self, action: #selector(filterBtnAction(_:)), for: .touchUpInside)
cellHeader.filter2Btn.addTarget(self, action: #selector(filterBtnAction(_:)), for: .touchUpInside)
cellHeader.filter3btn.addTarget(self, action: #selector(filterBtnAction(_:)), for: .touchUpInside)
return cellHeader
}
#IBAction func filterBtnAction(_ sender: UIButton) {
print(sender.tag)
tableViewHome.reloadSections([1], with: UITableViewRowAnimation.none)
}
I'm a little unclear as to what's going on here, but it sounds like there is a UITableView concepts worth explaining here:
UITableView has its own concept of a cell, implemented as UITableViewCell, and its own concept of a header/footer, implemented as UITableViewHeaderFooterView.
Depending on which of these two you meant, there are a few things you can do to get the intended effect:
The UITableViewCell Approach:
If you're using a UITableViewCell as the first row of a section to act like a "header," and you just want to reload that row to the exclusion of the rest of the section, you can call yourTableViewInstance.reloadRows(at:with:) (Apple Documentation) This method takes an array of IndexPaths, and an animation style. You can pass in the indexPath of the one you want to reload.
The UITableViewHeaderFooterView Approach:
If you're using a proper UITableViewHeaderFooterView then you need to make sure that you're providing the appropriate view when reloading the section. Zack Shapiro outlines the steps you need to take in this answer:
Create a class that's a subclass of UITableViewHeaderFooterView.
Register it with your UITableView instance.
Then in viewForHeaderInSection, you do let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderView") as! YourHeaderViewSubclass
The last thing he points out is this:
The deceptive thing is the function calls for a return of UIView? when it really needs a dequeuedReusableHeaderFooterView or reloadData will cause it to disappear.
It depends on which of these two implementation paths you're taking, but this should be enough information to point you in the right direction.
Edit:
Based on the code you added, it looks like you're calling yourTableViewInstance.dequeueReusableCell(withIdentifier:for:) instead of yourTableViewInstance.dequeueReusableHeaderFooterView(withIdentifier:) inside of viewForHeaderInSection.
You need to have a subclass of UITableViewHeaderFooterView and then call it correctly. Create that new subclass, then change this:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cellHeader = tableViewHome.dequeueReusableCell(withIdentifier: "header") as! HeaderTableViewCell
// ...
to this:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cellHeader = tableViewHome.dequeueReusableHeaderFooterView(withIdentifier: "header") as! HeaderTableView
// ...
You need to follow two steps here:
Create a new class, subclassing UITableViewHeaderFooterView instead of UITableViewCell.
Then use the appropriate class as outlined above.
Yes, It is.
Let's say that this is implementation of your method:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let customCell = .... as! YourCustomCell
customCell.someLabel.text = "Some Data"
//... filling your curstom cell
return customCell
}
You can change it in this way
func updateHeaderView(headerView:YourCustomCell, section: Int) {
customCell.someLabel.text = "Some Data"
//... filling your curstom cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let customCell = .... as! YourCustomCell
self.updateHeaderView(customCell, section)
return customCell
}
And call again self.updateHeaderView(customCell, section) whenever you want, e.g.
func buttonClicked() {
let customCell = self.tableView.headerView(forSection: 0) as! YourCustomCell
self.updateHeaderView(customCell, 0)
}
I think your header view class is extending UITableViewHeaderFooterView class. Add a function in the extension
extension UITableViewHeaderFooterView{
func reloadHeaderCell(){
preconditionFailure("This method must be overridden")
}
}
Now override this in your Header class as below
class HeaderView: UITableViewHeaderFooterView {
override func reloadHeaderCell() {
////// add your logic to reload view
}
}
Now you can simply call below line to refresh views
self.tableView?.headerView(forSection:0)?.reloadHeaderCell()
What I did and working very correctly, Please follow the given answer:
SWIFT 3.1
Step 1:
Firstly I took a view xib, designed that according to my requirement and did register in my required class.
Secondly, did sub class class HeaderView: UITableViewHeaderFooterView of UITableViewHeaderFooterView
Like following image:
In my required class(here homeclass) I did register my xib file for my tableview.
override func viewDidLoad() {
super.viewDidLoad()
tableViewHome.register(UINib(nibName: "HeaderView", bundle: nil), forHeaderFooterViewReuseIdentifier: "HeaderView")
}
Step 2:
Then in my required class i did following:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cellHeader = tableViewHome.dequeueReusableHeaderFooterView(withIdentifier: "HeaderView") as! HeaderView
cellHeader.filterAction(cellHeader.filter1Btn)
return cellHeader
}
And it started working as per my requirement, later i added custom delegate for more actions in my class, but by subviewing, its now working.
I am trying to control my UITableView based on the selectedSegmentIndex of a UISegmentedControl inside my UITableView header. Essentially, I want this UISegmentedControl to work like Twitter's 'Me' tab. I have the UISegmentedControl inside a UITableView header and it is dequeued using this method:
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "sectionDetailsHeaderView") as! SectionDetailsHeaderTableViewCell
return cell
}
I have an outlet for the UISegmentedControl hooked up to SectionDetailsHeaderTableViewCell, but I can't figure out how to detect a change in the UISegmentedControl. I want to set a variable, var segmentedControlValue = Int() to the selectedSegmentIndex every time the value changes and call a function, func chooseDataToDisplay() {} when the value changes. How do I go about doing this?
With the help of #Schomes answer and this post, I was able to figure it out!
1) Add the UISegmentedControl into its own UITableViewCell. I would recommend adding a UIView with a white background behind the UISegmentedControl that covers the entire UITableViewCell so the TableView cells flow behind the UISegmentedControl.
2) Add your custom cell class and hook it up to the UITableViewCell
3) Add an outlet, such as yourSegmentedControl to your custom UITableViewCell class. DO NOT add an action into the custom UITableViewCell class. This is done programmatically in step 4.
4) In the UIViewController or UITableViewController class, add the code below.
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "yourCellIdentifier") as! yourCustomCellClass
header.yourSegmentedControl.selectedSegmentIndex = self.segmentedControlValue
header.yourSegmentedControl.addTarget(self, action: #selector(self.getSegmentValue(sender:)), for: .valueChanged)
return header
}
self.segmentedControlValue should be declared as var segmentedControlValue = Int() at the top of your ViewController class. self.getSegmentValue(sender:) should be declared as:
func getSegmentValue(sender: UISegmentedControl) {
self.segmentedControlValue = sender.selectedSegmentIndex
}
5) You also need to add:
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 45
}
This is the height of the header. In my case, the size is 45
6) You can now access self.segmentedControlValue anywhere in your ViewController. It will update when the user taps on a different segment.
segmentedControl.addTarget(self, action: "chooseDataToDisplay:", forControlEvents: .ValueChanged)
Where segmentedControl is your UISegmentedControl. This will call func chooseDataToDisplay(segment: UISegmentedControl) {} every time the value changes.
References:
https://developer.apple.com/reference/uikit/uisegmentedcontrol
The section Behavior of Segmented Controls
https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/UIKitUICatalog/UISegmentedControl.html#//apple_ref/doc/uid/TP40012857-UISegmentedControl
I have a tableView set up so that when a cell is touched, it expands in height to reveal more information. The tableView has 5 sections.
I have a bug: when a cell expands, all headersCells below that cell go invisible. The console outputs the following: "[31233:564745] no index path for table cell being reused"
In my storyboard I have 2 custom cells : "myCell" for the data bearing cells, and "headerCell" for the headers.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let thisGoal : GoalModel = goalArray[indexPath.section][indexPath.row]
if self.currentPath != nil && self.currentPath == indexPath {
self.currentPath = nil
} else {
self.currentPath = indexPath
}
tableView.beginUpdates()
tableView.endUpdates()
}
If I enter tableView.reloadData() in between the begin/end updates, it functions properly, although the header background turns black, and loses animation.
I have all of the stuff for headers declared in: func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
what am I missing? I'd really like the tableView to still have animations, and keep the background clearColor().
Thanks in advance. I did read through the objective C answers, but couldn't get them to work for me. I'd really appreciate some SWIFT help.
I think the problem is the no index path for table cell being reused.
I found an answer in the console output. Use this code in the header function:
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
Do not return your headerCell, or your reusable identifier. Return the reuseIdentifier.contentView. For me it's: return headerCell!.contentView.
Just to add, I was baffled for WAY longer than I should have been as to why I couldn't refer to the contentView of my cell, when I could quite clearly see it was there. My custom class (using UITableViewCell rather than UITableViewHeaderFooterView) would return a fatal error each time. Therefore make sure any custom styling is setup under UITableViewHeaderFooterView class like:
class CustomHeaderCell: UITableViewHeaderFooterView {
You will also need to register the resuableIdentifer like this:
tableView.registerNib(UINib(nibName: "HeaderCell", bundle: nil), forHeaderFooterViewReuseIdentifier: "CellHeader")
Then this bad boy:
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableHeaderFooterViewWithIdentifier("CellHeader") as! CustomHeaderCell!
return headerCell!.contentView
}
Since I'm not at 50 reputation yet, I can't comment on the previous answer, so I apologize for listing this as another answer.
Returning the ContentView will make the function work but will remove all formatting done to the reuseIdentifier (headerCell)
headerCell.backgroundColor = UIColor.cyanColor()
This will NOT provide a Cyan color to your headerCell
To fix this, just add the ".contentView" to your formatting lines
headerCell.contentView.backgroundColor = UIColor.cyanColor()
Table view headers in 2 tables disappeared when I converted my app to IOS 10 - I found the reason in Apple developer API documentation on table headers. When I added the following, the missing headers reappeared!
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
return 44 // where 44 is the header cell view height in my storyboard
}
You could wrap the TableViewCell inside an UIView
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let containerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 50)) // 50 = Header height
guard let headerCell = tableView.dequeueReusableCell(withIdentifier: "MyHeaderView") as? MyHeaderView else { fatalError(" Failed to load MyHeaderView") }
headerCell.frame = containerView.bounds
containerView.addSubview(headerCell)
return containerView
}
I had the same bug because I was returning a cell using dequeue method instead of a UITableViewHeaderFooterView.
Solution:
Add a view outside of the view hierarchy
Set the type to UITableViewHeaderFooterView
Customize
Link to an #IBOutlet
In func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? return the outlet
Common pitfalls:
Don't forget to set the header sizes
Don't forget to set the outlet as strong.
I have an UITableView with custom cells. I would like that the first row is always visible. As I have only once section, I thought of making a header but in this case I don't really know how to do it?
Is it possible to make a header from the first row with the same gesture recognizers, same dataSource behind the rows, briefly, have the header exactly like th row, just as if the row was pined to the top of the tableView?
You should use a header, or a separate view outside the table view. You can use the same gestures (generally, though not the delete) and data source.
If you want it all, you could use 2 table views- the first with one section and one row, the second with all the other data. It would be easiest if your data source was broken down in a similar way in the view controller.
In either case you can achieve what you want, but not by flicking a switch, you will need to add some logic and different views to make it happen.
If you want to make one static cell that is pinned to the top but in all other ways the same to the others, you could simply add one to your numberOfRowsInSection
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count + 1
}
Then when you display the cells, check for the row number and always set the first row to contain your static header content.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
// Create or set static cell content.
}
}
The other way is to create a custom section header and set it using viewForHeaderInSection
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0 {
var view = UIView()
view.backgroundColor = UIColor.blueColor()
return view
}
return nil
}