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.
Related
I have created an app using a storyboard. In other screens, I have used a UITableViewController directly and the selection is working as expected.
In this case, I have a UITableView that is one of several controls within a UIViewController.
My custom ViewController.h file has a definition similar to the below:
#interface MyViewController : UIViewController <UITableViewDelegate,UITableViewDataSource>
#property (weak,nonatomic) IBOutlet UITableView *myTableView;
#end
Then within viewDidLoad I am doing this:
_myTableView.delegate = self;
_myTableView.dataSource = self;
Having done this, my numberOfSectionsInTableView, numberOfRowsInSection and cellForRowAtIndexPath methods are all being called and my table looks as I want it to.
The problem I have is that the rows do not select and the didSelectRowAtIndexPath method is not getting called.
I have checked that Selection is set to Single Selection in the storyboard view and I have also tried to set _myTableView.allowsSelection=YES; in viewDidLoad but this doesn't seem to make any difference.
I know that this is probably something to do with the fact that my table is within a normal view controller, but I can't figure out the magic step I've missed to make the selection work.
For now I have added a workaround. In cellForRowAtIndexPath I have attached a UITapGestureRecognizer to each view in the cell:
for(UIView *view in cell.contentView.subviews){
[view setUserInteractionEnabled:YES];
UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapRow:)];
[tap setNumberOfTapsRequired:1];
[view addGestureRecognizer:tap];
view.tag = row; // So that I can identify in the handler which row has been tapped
}
Then in the handler:
-(void)tapRow:(id)sender{
UITapGestureRecognizer *gesture = (UITapGestureRecognizer*)sender;
UIView *myView = (UIView*)gesture.view;
int row = myView.tag;
// Handle tap of row here
}
This achieves what I need, but I would still like to figure out what I've done wrong with the row selection!
Make sure there is not another view on top of the table view (e.g. a transparent view that would be stealing touch events). Also ensure that userInteraction is enabled for the tableview and all of its parent views.
We type sometime wrong delegate call didDeselectRowAtIndexPath instead of didSeselectRowAtIndexPath. Is it your case?
I see that you can update your content in the tableview so the connection should be OK. I think about mistakes with function names.
Just to test: Replace your didSelectRowAtIndexPath function with this (copy, paste).
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Selected %d",indexPath.row);
}
Just incase anyone still has this problem. I just realised -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath method won't work for any view or subview with a tap gesture recogniser set to it. So remove the tap gesture recogniser from that view of it's parent view. if you still want to handle touch events, then use "touchesBegan" function. ` - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
}`
I had the exactly the same problem with my current project for two minutes yesterday when I realised that I didn't link my delegate and dataSource of the table view. You made it programmatically, so it should work. For me was a delegation problem, you can check your Attributes Inspector to make sure that everything is ok.
In cellForRowAtIndexPath method add this line
cell.userInteractionEnabled = NO;
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.
I have a tableview controller with navigation bar, it is used for user profile screen. tableview has 10 custom cells containing label,textfields and textview and navigation bar buttons are use for enabling/disabling the editing of tableviewcell contents. A user can load this user profile screen from any controller in the app with a button on that that view controller. what i want to do is, when a user selects to open this user profile screen(tableview Controller) from anywhere, it should appear only viewing mode; its cell having textfields and Textviews should not be editable. However when user navigates through settings screen of app and goes to user profile screen, its cells could be enable or disabled for editing. any suggestions for this ??
try this:
Part 1. Preparing your UITableViewController class
in the .h:
add... #property (nonatomic, assign) BOOL enableCellSelection;
.
in the .m
in the -initWithStyle: do...
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
enableCellSelection = YES;
}
return self;
}
in the -cellForRowAtIndexPath: do...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//your normal cell handling code
[cell setUserInteractionEnabled:(enableCellSelection ? UITableViewCellSelectionStyleBlue : UITableViewCellSelectionStyleNone)];
return cell;
}
Part 2. Showing your UITableViewController class
From any method...
//alloc/init normally
MyTableViewController *tvcObj = [[MyTableViewController alloc] init];
//explicitly disable the cell selection ability
tvcObj.enableCellSelection = NO;
//display the tableView
[self.navigationController pushViewController:tvcObj animated:YES];
Basically, we create a property that we set before showing the tableView and when the table loads, it will read this property and appropriately set the interaction ability on the entire cell.
this is the best I could think of
I have a viewcontroller.xib which contains View, buttons,toolbarbutton, text box and a tableview. When I load the initial screen comes without table view which is fine. Now when I click on a toolbarbutton say, viewtable, I want the view to move to tableview. I have filled my tableview data with some default objects like this:
- (void)viewDidLoad
{
tableData = [[NSArray alloc] initWithObjects:#"object1",#"object2",#"object3",#"object4", nil];
[super viewDidLoad];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"My Cell"];
if(cell==nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"My Cell"];
}
cell.textLabel.text=[tableData objectAtIndex:indexPath.row];
return cell;
}
So when I click on toolbar view button it should show tableview with toolbar button which also has a back button so when I click on that it should hide the table view and show the initial view. Is it possible to do all this in single xib? I can achieve the result if I create another xib and simply transfer control over to that xib but I wanted to know if its possible do this without creating a second xib file. And also for navigation I can use navigation controller but I want to check and see if its possible to use toolbar to transfer the control. Thanks.
First check if your table view is inside your view, if not put it inside and set delegate of datasource to file owner, then in your view table method write this code
-(void)viewTable
{
self.tableView.hidden = NO;
self.viewToolbar.hidden=YES;
}
On your back button code in toolbar write
-(void)goback
{
self.tableView.hidden = YES;
self.viewToolbar.hidden=NO;
}
If you don't need animation then you can do the following
Get a handle of tableView in your interface like this:
#property(nonatomic,assign)IBOutlet UITableView *tableView;
Hide your table view in initially ( like in viewDidLoad method )
-(void)viewDidLoad
{
[super viewDidLoad];
self.tableView.hidden = YES;
}
Then in the method called by your toolbar's button do the following
-(void)on_click_toolbar_button
{
self.tableView.hidden = !self.tableView.hidden;
//This will keep toggling the table view from hidden to shown & vice-versa.
}
you could use the hidden property to achieve that. Put these in the appropriate ibaction methods.
_tableView.hidden = Yes;
_tableView.hidden = No;
I'd highly recommend to do this in two separate XIBs. The first should contain a UIViewController (your initial view) and the second a UITableViewController (your table view) class. Both should be handled by a UINavigationController - don't fight the API and try your own hacks if it's not necessary. The mentioned controller classes give you everything you need out of the box.
Well this is not recommended but you can do this by removing and adding tableview..
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;
}