Implementing a custom table section header via Storyboard and new Xib - ios

Here is what I have done:
I created a custom xib file that has a small UIView used for a custom table section header.
I classed the custom xib file.
I want to add this to a tableView as the header. I have looked at a few resources, but they seem to be either outdated or missing information.
Looking in the documentation, I see a reference to adding a custom header with the following instructions:
To make the table view aware of your header or footer view, you need to register it. You do this using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method of UITableView.
When I added a tableView to my storyboard view, it was easy to assign it a reuse identifier within XCode. I was even able to create a custom cell xib file and it also had a spot for a reuse identifier within XCode.
When I created the custom UIView for the section header, it did not have an entry for reuse identifier. Without this, I have no idea how to use registerNib:forCellReuseIdentifier.
More information:
I have a storyboard scene that has a tableView inside. The tableView is of a custom class that is linked and the tableView object has an outlet in the parent view's ViewController file.
The parent ViewController is both the UITableViewDataSourceDelegate and UITableViewDelegate. Again, I was able to implement the custom cells with no issue. I can't even modify the header in any way besides the title.
I tried calling the method [[self tableHeaderView] setBackgroundColor:[UIColor clearColor]]; from the custom tableView class and nothing happens. I tried using this method in the parent ViewController class by using the outlet name like so:
[[self.tableOutlet tableHeaderView] setBackgroundColor:[UIColor clearColor]];
Any help would be greatly appreciated.
EDIT: (Can't change background to transparent)
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
HeaderView *headerView = [self.TableView dequeueReusableHeaderFooterViewWithIdentifier:#"tableHeader"];
// Set Background color
[[headerView contentView] setBackgroundColor:[UIColor clearColor]];
// Set Text
headerView.headerLabel.text = [self.sectionArray objectAtIndex:section];
return headerView;
}

You don't need to set the identifier in the xib -- you just need to use the same identifier when you register, and when you dequeue the header view. In the viewDidLoad method, I registered the view like this:
[self.tableView registerNib:[UINib nibWithNibName:#"Header1" bundle:nil] forHeaderFooterViewReuseIdentifier:#"header1"];
Then, in the delegate methods:
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerView = [self.tableView dequeueReusableHeaderFooterViewWithIdentifier:#"header1"];
return headerView;
}
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 100;
}

On the problem with background color (Unless you want transparent):
You can create an UIView which occupies the whole view then change the background color of that.
If you don't want others to know what's happening, you can overwrite the backgroundColor property:
//interface
#property (copy, nonatomic) UIColor *backgroundColor;
//implementation
#dynamic backgroundColor;
- (void)setBackgroundColor:(UIColor *)backgroundColor {
//self.viewBackground is the created view
[self.viewBackground setBackgroundColor:backgroundColor];
}
- (UIColor *)backgroundColor {
return self.viewBackground.backgroundColor;
}

Related

Button not working in UIView for UITableView

I've created a header for the first section in my UITableView. The Header is created by a view in .nib file. I've connected the button to the Views owner which is a class called HeaderSection which is a subclass of UITableViewHeaderFooterView.
Here's the code for what should happen when the button is clicked.
#import "HeaderSection.h"
#implementation HeaderSection
- (IBAction)touchButton1:(UIButton *)sender {
NSLog(#"Touch button 1 tapped!");
}
#end
And here's a screen shot of things overall.
The problem is when I tap on the button, it doesn't detect the tap, instead the cell below the button detects the tap and the code runs accordingly (brings on a new UIViewController).
How can I make it detect the top button?
Here's more code from my main ViewController.
- (void)viewDidLoad
{
[super viewDidLoad];
UINib *sectionHeaderNib = [UINib nibWithNibName:#"headerNib" bundle:nil];
NSString *SectionHeaderViewIdentifier = #"sectionHeaderIndentifier";
[self.tableView registerNib:sectionHeaderNib forHeaderFooterViewReuseIdentifier:SectionHeaderViewIdentifier];
self.iconSets = [IconSet iconSets];
self.tableView.allowsSelectionDuringEditing = YES;
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(longPressGestureRecognized:)];
[self.tableView addGestureRecognizer:longPress];
self.filteredIcons = [NSMutableArray array];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 60.0f;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
NSString *SectionHeaderViewIdentifier = #"sectionHeaderIndentifier";
HeaderSection *sectionHeaderView = [self.tableView dequeueReusableHeaderFooterViewWithIdentifier:SectionHeaderViewIdentifier];
return sectionHeaderView;
}
And here's a screen shot of the view in the .xib (I've made the underlying view dark grey to stand out).
One problem you have is that in the .xib file, the top-level object must be set, in the idendity inspector, to be the custom UIView subclass that it is, or nothing will work.
However, it looks like other things are going on. The gray from the tableview cell underneath shouldn't be peaking out on the right of the footer. Is this being added in the tableView:viewForHeaderInSection: method of the UITableViewDataSource? It can adjust the headerView's frame there to be the width of the tableView. Depending on what the button is going to do, it might also need a reference to the view controller.
If the search bar and buttons are going to stay on top always, they don't really need to be a header. On that .xib you have, just put a tableview underneath the button bar. Create a ViewController with that file as the .xib, then connect that tableView's dataSource and delegate to that View Controller. You may need to create a ViewController with built-in xib to do this automatically, in or out of storyboards.
Freestanding xibs are discouraged but I think they're perfect for this case, tableView/collectionView reusable views. But if its on top of the table, not in it, it should be part of the view controller that contains the table.

Loading a UIView within UITableViewCell

I am having an interesting problem creating the custom tableview I need...
I found this question, but it does not really address my issue...
I am trying to put a subclassed UIView inside a subclassed UITableViewCell. The custom view holds a UIButton and a couple labels. Simplified, it's like this:
Both the custom view and custom tableviewcell have xibs.
MyCustomView.xib's class is set to MyCustomView and I have properties for the labels and the button as well as an IBAction for the button.
MyCustomTableView.xib has a property for MyCustomView and is importing MyCustomView.h.
In MyCustomView.xib, I have this init:
-(id)initWithNibName:(NSString *)nibName nibBundle:(NSBundle *)nibBundle myLabelText:(NSString *)labelText {
//The custom view in the tableviewcell is 69 by 64...
if ((self = [super initWithFrame:CGRectMake(0, 0, 69, 64)])) {
[self setmyLabelText:labelText];
}
return self;
}
And in my TableViewController...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCustomTableViewCell *cell = (MyCustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"theCell" forIndexPath:indexPath];
// Configure the cell...
cell.customView = [[MyCustomView alloc] initWithNibName:#"MyCustomView" nibBundle:nil fileContentID:#"Some Text..."];
return cell;
}
When I run the app, the custom tableview cell's contents are fine, but the content of the custom view inside the custom tableview cell is blank.
It seems that MyCustomView's initializer(-initWithNibName:nibBundle:myLabelText:) don't load any xib.
This post will help you.
How to load a xib file in a UIView
...and MyCustomView should be created once inside MyCustomTableViewCell, as #rdelmar says.
You need to do most of the formatting work in MyCustomTableViewCell - I would not use a XIB and code the views directly because that class is called many times. Apple has number of sample codes regarding TableViewCells - One of them I believe is called Elements that use fancy tableview cells for the Elements of the Periodic Table. Most of my apps use custom cells with icon images and I started with that sample code many years back (since IOS 4).
Your CellForRowatIndexPath should just be passing the image and the label text to your tableviewCell Class instance. If you have question just ask - but I am sure that sample code from apple is sufficient to get you started.

Outlets cannot be connected to repeating content iOS 5

I am new to iOS i am working on uitableview cell i had drag and drop the button to table view cell from objects inspector. but when i am making its IBoutlet it is showing an error like "Outlets cannot be connected to repeating content" what does it means?? we cant make outlets of UIbutton in tableview cell.kindly review it . i am stuck in it.i am making an outlet like this:
#property (weak, nonatomic) IBOutlet UIButton *sa;
and the error is "The sa outlet to the UIbutton is invalid"
Your answer is that you use an object in UITableViewCell by reusing it,
So you can't create it's outlet except you create Your class for your "UITableViewCell".
Below is a reference for you,
I hope that it's useful for you.
You need to drag and drop the object in your UITableViewCell,
Then you have to give tag for that object.
then you can use it with its tag.
First give an identifier to UITableViewCell,
Below is a reference image for it.
Then give a tag to your UI object,
As this in this reference image.
Below is sample code for you which I use regularly,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *Cell = [self.TableListRegion dequeueReusableCellWithIdentifier:#"List"];
UIButton *objectOfButton = (UIButton *)[CellLast viewWithTag:200];
[objectOfButton addTarget:self action:#selector(YourSelector:) forControlEvents:UIControlEventTouchUpInside];
return Cell;
}
Now you can receive that button event by,
-(IBACTION)YourSelector:(id)sender{
// Your Button in Cell is selected.
// Do your stuff.
}
Feel free to ask if you need more help regarding it.
You can create subclass for UITableViewCell like below code
Create new class named CCell.h and CCell.m
in CCell.h
#interface CCell : UITableViewCell
#property(nonatomic,strong)IBOutlet UILabel *lblTemp;
#property(nonatomic,strong)IBOutlet UIButton *btnTemp;
#end
Now in your Viewcontroller.h
#import "CCell.h"
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CCell *cell = (CCell *)[tblView dequeueReusableCellWithIdentifier:#"CCell"];
cell.lblTemp.text = #"asd";
cell.btnTemp.tag = indexPath.row;
[cell.btnTemp addTarget:self action:#selector(btnTempClicked:) forControlEvents:UIControlEventTouchUpInside]
return cell;
}
-(void)btnTempClicked:(UIButton *)btnTemp
{
NSLog(#"Button Clicked Index = %d",btnTemp.tag);
}
Now open your Xib > tap on your UITableviewCell > open right side navigator > open 3rd tab named (Custom Class) > add Class = CCell > now open last tab you will get lblTemp bind option.
Maybe this will help you.
Since you are creating a custom cell, you need to create a class for it. You will subclass UITableViewCell.
For example (using the property that you had in your question):
Create a new Objective-C Class. Set the subclass to: UITableViewCell
Give it an appropriate name (i.e. cell)
In your cell.h file:
Create your property: #property (weak, nonatomic) IBOutlet UIButton *sa;
In the cell.m file:
#synthesize sa = _sa;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
3.In Interface Builder, go back to the row that you created.
Click the "Show Identity Inspector".
Under "Custom Class", set that to your cell file.
4.Hold down the "Option" key and click the "cell.h" file. Then connect the button to the IBOutlet.
5.In your table view controller file:
import your cell.h file.
In cellForRowAtIndexPath method:
Cell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
That's it!
Everything should work then. Hope this helps!
You can't, because the button is part of a cell, and there will (possibly) be multiple instances of that cell when the app runs.
Assume that you can make the connection, and there are 2 cells (and thus 2 buttons) when the app runs, Cocoa Touch can't decide which button will be referenced by that only outlet (neither can you).
You can subclass the UITableViewCell, ask the table view to use your subclass for its cells, and connect the button to the outlet in the subclass. In that case there will be multiple instances of the subclass, and each instance will map to one cell.
Whenever you need want to create custom tableView cell it is recommended to subclass UITableViewcell and add UIButton in that class. And in your tableview delegate method cellForRowAtIndexPath you can create an object of subclassed tableviewCell for every cell.
I have done in UITableviewcell cell's label's outlet connection in UIViewController,it should changed to Create a CustomCell in Subclass of UITableviewcell,then done in outlet connection in this subclass that error cleared.
#Mishal Awan
If you really want to do that and your have a finite number of cells. U can :
Changing your ViewController to be a subclass of UITableViewController, then drage a Table View Controller file to your StoryBoard
Changing the content of Table View in your StoryBoard from Dynamic Prototypes to Static Cells
Then you can add some views to your cell, for example some labels
Connectting the label to your ViewController and continue the remaining work
If you want to create a reusable cell, forget what i have said above
A very simple solution is:
Just take the view or NSLayoutConstraint reference outlets in the subclass of table view cell instead of table view controller and access using object of table view cell in cellForRowAtIndexPath method or any other method.
Note: This is a repetitive object so you can't take reference in table view controller.

Override Storyboard Configurations in Xcode with Delegate

I want to have the height of my UITableView cells depend on the material they contain. My view controller object is a subclass of UITableViewController and conforms to the <UITableViewDelegate> protocol. Is this the correct place to reference the protocol?
Then in my implementation I declare
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [indexPath row] * 20;
}
but when I run the app each row is of fixed height that is visually represented in the storyboard. Is it something with the prototype cell that is overriding my code? Am I missing something completely naive?
Did you set your view controller as delegate to table view. You can do it either through connection inspector of your table view in xib/ storyboard. Or you can do it by doing following in your initWithNibName:bundle: method
myTableView.delegate = self;

UITableView not displaying content in UIViewController

I have added a UITableView inside a UIViewController in IB, I have set the TableView content to "Static Cells" since that's what I want, and everything seems fine when I haven't added any content to the UITableView. But if I for example change the first UITableViewCell's background color to black it doesn't display black when running the app. I have added UITableViewControllerDelegate and UITableViewDataSource and set the tableView.delage = self;. But still no changes I make to the tableView displays when I run the app.
What can the problem be?
NOTE: I have also tried to add tableView.dataSource = self;, but that just make the app crash.
Yes, you can have static table view content in UIViewController.
All you need to do is:
-Create the table's static cells in interface builder and design them the way you like.
-Make the UIViewController implement table view's data source and delegate:
#interface MyViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
-Connect the table view's delegate and dataSource to the view controller in interface builder
-Implement -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section to return the number of your cells. (e.g. return 10, yes simple as that)
-Connect your cells to your code as IBOutlets in Interface Builder. IMPORTANT: Make sure they are strong, weak won't work. e.g. #property (strong, nonatomic) IBOutlet UITableViewCell *myFirstCell;
-Implement -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath to return the correct cell at index path. e.g:
int num = indexPath.row;
UITableViewCell *cell;
switch (num) {
case 0:
cell = self.myFirstCell;
break;
case 1:
cell = self.mySecondCell;
break;
}
return cell;
If you apply all these steps, you should have working static cells that works for tables with not many cells. Perfect for tables that you have a few (probably no more than 10-20 would be enough) content. I've ran the same issue a few days ago and I confirm that it works. More info check here: Best approach to add Static-TableView-Cells to a UIViewcontroller?
You will want to use a UITableViewController, not a UIViewController with a UITableView added to it, because you're only supposed to use static cells with a UITableViewController. There are probably ways to hack around it so you can get the static cells to work, but it's much simpler to just use a UITableViewController, and you'll have fewer issues to deal with, especially if you ever change the content of the table.
Seems you have problem with the background issue for UITableViewCell. So don't use background for checking if content is drawing or not.
You can use debugger for this for example or NSLog.
NOTE: the cell has content view that can be modified. I don't remember but seems the cell has not got background property that can be adjusted with a color.
If you tried this line below e.g. - it will no work and color will be white as default color.
[cell setBackgroundColor:[UIColor blackColor]];
Try to add something to the cell for example picture and then you can see the result as I think.
Use this code:
[cell.contentView setBackgroundColor:[UIColor blackColor]]; in this delegate
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
it will help you as I think.
Have you implementede the protocol? ...
another thing is that when implementing the protocol i had an issue when no cell was displayed..
try with this implementation for the given method.
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier=#"Cell";
CobranzaCell *cell = [[CobranzaCell alloc]init];
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
if (cell == nil) {
cell = [[CobranzaCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
// Configure the cell...
return cell;
}
You cannot use the static cells in simple UIViewController subclass. Instead, you should use the instance of UITableViewController. The hack is in your storyboard drag the instance of UIViewController to your storyboard canvas. Then, drag the Container View from objects library and drop it to your UIViewController's view. By default it will create the embed segue with related UIViewController instance. What you want to do - delete this view controller, drag and drop instance of UITableViewController from objects library, then right click and drag from your Container View to just dropped UITableViewController. Chose embed. Now your table view controller gets the size of container view and you can use static cells in it! Hope it will help!

Resources