I have 4 custom UITableViewCell subclasses generated from nibs that all include UILabels. I noticed that I am not able to select the cell when I tap on the frame of the UIlabel. Is there a way around this issue?
I believe that you can set userInteractionEnabled to NO so touches aren't intercepted by the UILabels.
Go into UIBuilder and select the labels, and make sure that userInteractionEnabled (it's under the view properties) is set to no.
OK I figured it out. I needed to set the entire UITableViewCell subclass nib to userinteractionenabled = NO. In my init method of each subclass I added the following code:
[[NSBundle mainBundle] loadNibNamed:#"ROIUITableViewCellType1"
owner:self
options:nil];
[self addSubview:self.mainView];
The subview from the nib obscured the cell which was responding to tap events. I am not sure if this is the proper way to load a nib for a UITableViewCell subclass which may have caused my problem. Any thoughts?
Related
I am trying to add a custom UIView that I created in XIB, to my view controller in my main.storyboard as a subview. How can I do this?
matchScrollView (tag 1) is the UIScrollView in view controller in main.storyboard, while matchView (tag 2) is the custom UIView I created in another XIB file.
With the press of a button i want to have the custom UIView added to the UIScrollView as a subview. But how can i actually make it show up on display? I guess i have yet to alloc and init it, along with indicate position and such, but how can i do that? I tried different ways without success. I can create UIViews programmatically, but have yet to find a way to just load the UIView from XIB.
-(IBAction) buttonTapped:(id)sender {
UIScrollView *matchScrollView = (UIScrollView *) [self.view viewWithTag:1];
UIView *matchView = (UIView *) [self.view viewWithTag:2];
[matchScrollView addSubview:matchView];
}
The reason that I am creating my custom UIView in another XIB file instead of directly implementing it on my main.storyboard view controller, is because I want to re-use the same view multiple times. So the UIScrollView has a numerous subviews of UIViews.
I was hoping I could create numerous instances of MatchView and add them all to matchScrollView as subviews.
The issue you are having is completely normal. The way Apple designed it doesn't allow to reuse custom views with their own xib into other xibs.
Lets say you have a custom view named HeaderView with a custom xib named HeaderView.xib. And lets say you want to be able to, in another xib named GlobalView.xib, drag a subview and specify its class to be of type HeaderView expecting it to load that view from HeaderView.xib and insert it inplace. You can do it like this:
A) Make sure File's Owner in HeaderView.xib is set to be HeaderView class.
B) Go to your GlobalView.xib, drag the subview and make it of class HeaderView.
C) In HeaverView.m implement initWithCoder, if after loading the view there aren't subviews means it got loaded from GlobalView, then load it manually from the correct nib, connect the IBOutlets and set the frame and autoresizingmasks if you want to use the GlobalView's frame (this is usually what you want).
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self.subviews.count == 0) { //means view got loaded from GlobalView.xib or other external nib, cause there aren't any subviews
HeaverView *viewFromNib = [[NSBundle mainBundle] loadNibNamed:#"HeaverView" owner:self options:nil].firstObject;
//Now connect IBOutlets
self.myLabel1 = viewFromNib.myLabel1;
self.myLabel2 = viewFromNib.myLabel2;
self.myLabel3 = viewFromNib.myLabel3;
[viewFromNib setFrame:self.bounds];
[viewFromNib setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[self addSubview:viewFromNib];
}
return self;
}
I have a storyboard and one of my viewControllers has a CollectionView. I have a prototype cell that has a label inside. I created a class for that prototype cell in order to have access to the label via an IBOutlet property.
The problem is that I have many cells. Inside the initWithCoder constructor of the cell I add some cornerRadius.
When I push this viewController on the screen, it lags a lot. Without the corner radius it doesn't. I also noticed that initWithCoder gets called all the time, for each cell.
I tried to register the cell like this [self.myCollectionView registerClass:[MyCell class] forReuseIdentifier:#"MyReuseIdentifier"] but it doesn't work. I dont know how to use the registerNib method.
The reuse identifier is set in the storyboard prototype cell.
I don't know how to achieve the rounded corner effect without loss in perforrmance.
I have done my cell corner round in cellForItemAtIndexPath method like
cell.imageView.layer.cornerRadius = 10;
cell.imageView.layer.masksToBounds = YES;
and dont forget to import #import <QuartzCore/QuartzCore.h>
So here I am upgrading a working ios6 app to ios7, and now I can't receive taps or other actions on custom buttons (or other subviews) inside my tableviewcells.
Edit:
My code:
Here is where I deploy my PlaceCell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"PlaceCell";
PlaceCell *cell = [tableView dequeueReusableCellWithIdentifier: cellIdentifier];
if (!cell) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"PlaceCell" owner:self options:nil];
cell = [nib lastObject];
cell.reuseIdentifier = cellIdentifier;
}
[cell configureCellWithPlace: [self.places objectAtIndex:indexPath.row]];
cell.delegate = self;
cell.userInteractionEnabled = YES;
return cell;
}
And then it is a normal custom cell with buttons which are connected to some actions by the interface.
It works perfectly with iOS6, but it does nothing with iOS7.
Thank you for your help.
Solved with:
[cell.contentView setUserInteractionEnabled: NO];
Put your button into cell's contentView.
This happens when your Cell's view in xib file is not a UITableViewCell, but only a UIView. Make sure that that the xib's top view is a UITableViewCell.
You can easily check it by looking into the first child of the main view inside the interface builder. If the first subview is not "Content View" then you should rebuild the cell with UITableViewCell on the top.
Also make sure that button is a subview of the "Content View".
I had a similar problem. I had dragged a UIView into the xib to use as my UITableViewCell. Even though I changed the classname to a subclass of a UITableViewCell in Interface Builder, the events on my buttons still didn't fire. Since it was originally a UIView, IB never knew about contentView and didn't add my controls to it.
Dragging a "real" UITableViewCell into the xib, changing its class to the one I wanted, and then rewiring up the IBOutlets fixed everything. Didn't need to mess with delaysContentTouches or other properties either.
Moral of the story: drag the right thing onto your xibs.
It seems to be that when you use interface builder to customize a cell subclass all the views added are added below the contentView. This is why setting userInteractionEnabled = NO on the content view works, because touch events are allow to pass through.
I used po [view recursiveDescription] with lldb to determine this.
I have a xib with a 2 UIViews named subview1 and subview2. In subview1 a UILabel is palced and in subview2 a UITableView is placed.
I want to refresh the subview1 to change the label text at a particular time but no need to refresh tableview that time. After few operations again I need to refresh the tableview but no need to refresh the label.
How can I achieve this ?.
Thanks.
You can try next way.
Load xib by loadNibNamed and just replace wanted subview.
NSArray * views = [[NSBundle mainBundle] loadNibNamed:#"your xib name" owner:self options:nil];
can someone please explain why you should use viewWithTag to get subviews (e.g. UILabel etc) from a cell in dequeueReusableCellWithIdentifier?
Some background info: I've got a custom UITableViewCell with a couple of UILabels in it (I've reproduced a simple version of this below). These labels are defined in the associated NIB file and are declared with IBOutlets and linked back to the custom cell's controller class. In the tableview's dequeueReusableCellWithIdentifier, I'm doing this:
CustomCell *customCell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:#"CustomCellId"];
if (customCell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"customCell" owner:self options:nil];
for (id oneObject in nib)
if ([oneObject isKindOfClass:[CustomCell class]])
customCell = (CustomCell *)oneObject;
}
customCell.firstLabel.text = #"Hello";
customCell.secondLabel.text = #"World!";
return customCell;
Everything works fine. However from the tutorials I've seen, it looks like when changing the labels' values I should be doing this instead:
UILabel *firstLabel = (UILabel *)[customCell.contentView viewWithTag:555];
firstLabel.text = #"Hello";
UILabel *secondLabel = (UILabel *)[customCell.contentView viewWithTag:556];
secondLabel.text = #"World!";
(The labels' tag values have been set in the NIB).
Can someone tell me which method is preferred and why?
Thanks!
viewWithTag: is just a quick and dirty way to pull out child views without having to set up IBOutlet properties on the parent, or even without having to create a UITableViewCell subclass.
For very simple cases this is an acceptable solution, that's what viewWithTag: was intended for. However if you are going to reuse that cell a lot or you want it to have a more developer-friendly interface then you will want to subclass and use real properties as in your first example.
So use viewWithTag: if it's a very simple cell you designed in IB with no subclass and with just a couple of labels. Use a cell subclass with real properties for anything more substantial.
I've realised that it's useful to retrieve elements using "viewWithTag" if the elements were added to the cell programmatically (i.e. not defined in a NIB and hooked-up via IBOutlets)—this prevents multiple labels etc. to be created for each instance of the cell.
For me , viewWithTag is a God given. First of all : treating all views in a loop like taskinoor said is really easy. Also , I personally prefer this way because if I take a look on the code and want to see what happens with a view , I simply search for the tag. It's used everywhere the view is handled. Opposed to the xib approach where you have to look in the code and xib too. Also , if you have an offscreen view in a xib , you might oversee it.
I found a lot of xibs made by other programmers that were FULL with lots and lots of views. Some hidden , some offscreen , couldn't tell which is which since there were all overlapping.
In those cases , I think xibs are bad. They are not easy to read anymore.
I prefer everything made in code.
But if you decide to work with tags, remember to avoid hard-coding any tag. Instead make a list of #define definitions to keep the code clean and readable.
I always hook subviews to properties of my UITableViewCell subclass via IBOutlets, as you have done. I can't think of any good reason to use viewWithTag.
From UITableViewCell Class Reference: "The table view's delegate in tableView:cellForRowAtIndexPath: should always reset all content when reusing a cell." Keep it simple, clear out the content view. This makes no assumptions about custom cell classes, no casts, no class inspection:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (cell != nil)
{
NSArray* contentSubViews = [cell.contentView subviews];
for (UIView* viewToRemove in contentSubViews)
{
[viewToRemove removeFromSuperview];
}
}
viewWithTag: allows styling without creating a custom subclass of UITableViewCell.
You can assign a tag and reuse identifier to a prototype UITableViewCell in Interface Builder, then dequeue and modify the view with that tag within the implementation of your UITableViewController, without creating a custom class for that cell or creating IBOutlets for the cell's subviews.
In some cases, the simplicity of a cell makes a custom class feel like overkill. viewWithTag: allows you to add custom text and image to a cell in the Storyboard, then set those customizations via code, without adding extra class files to your Xcode project.