toggle checkbox image in uitableviewcell - ios

I've been having a problem of adding a checkbox image to my uitableviewcell and toggle between checked and unchecked image.
My simple code is:
-(UITableViewCell *)tableView:(UITableView *)todoTable cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
UITableViewCell *cell = [self.todoTable dequeueReusableCellWithIdentifier: SimpleTableIdentifier];
if (!cell) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SimpleTableIdentifier] autorelease];
}
cell.textLabel.text = [self.todoList objectAtIndex:indexPath.row];
return cell;
}
and i try to add in the solution in from here
But i don't know where shall i put the
interface ToggleImageControl : UIControl
I assume i put it in the same header file as my viewcontroller?
also i try to put in
ToggleImageControl *toggleControl = [[ToggleImageControl alloc] initWithFrame: <frame>];
toggleControl.tag = indexPath.row; // for reference in notifications.
[cell.contentView addSubview: toggleControl];
into my code above, i will get a ToggleImageControl reference error because of the implementation of the interface is not found, how can i fix this?
Thanks.

The easiest way to accomplish such modifications in look and behaviour is to write your own subclass of UITableViewCell. UIButton actually has toggling feature built in via selected property.

KakoSquid is correct. It looks like you might need to spend some time getting to know how classes and subclasses are built.
In your case it sounds like you have made a new interface section for your ToggleImageControl in the .h file but you need to put an #implementation section in your .m file.
In many situations you will make a new file set for a new class. (.h & .m files). In this case a toggle image is something you could reuse across other projects so it would make sense to break it out into its own file.
But, you can add the interface and implementation into any existing flies as you see fit. Just make sure to #import the correct files where you are using them.

Related

How should I implement a custom table view cell?

I am trying to change a cell in a tableview from generic to custom and have created a new tableview cell class. However, I cannot get the cell to recognize the new custom cell. Instead, it is still displaying the generic cell although I've changed the setting in storyboard to custom in the identify inspector and also changed the class for the tableview cell to the new custom one. I have also wired the elements in the cell in storyboard to the new custom class.
My understanding is the tableview VC knows which class to use from the tableView cellForRowAtIndexPath method and I have changed that too with the code below. The project compiles but continues to show old generic cell. Can anyone see error or suggest what else to do?
#import "customCell.h"
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
customCell *cell = (customCell *)[self.tableView dequeueReusableCellWithIdentifier:#"Cell"];
Items *item = [self.fetchedResultsController objectAtIndexPath:indexPath];
return cell;
}
Thanks in advance for any suggestions.
Edit:
A custom cell is created in the storyboard on top of tableview by dragging uielements. Maybe this is an issue:
Style of cell is set to Custom:
You need to create new UITableViewCell and enable the "create XIB file...".
Create your custom cell in the XIB and make it's custom class as your class you just created.
Then in tableView cellForRowAtIndexPath register the Nib: (it's in swift but I bet you can figure out the objective c parallel...)
tableView.registerNib(UINib(nibName: "YourUITableViewCellClass", bundle: nil), forCellReuseIdentifier: "YourCustomIdentifierFromTheCustomClass")
Then access your cell:
var cell = tableView.dequeueReusableCellWithIdentifier("YourCustomIdentifierFromTheCustomClass")
and that's it.
you can create custom cell in your main story board by drag the cell view.
create custom class for that prototype.
mention the class name in identifier inspector.
import that class to your view controller .h file.
and made connection of your custom from main story board to custom class.h file.
it works!.
When you create a custom cell you have to do these things:
Setup the labels, images etc on storyboard cell.
Create a custom cell class (inheriting from
UITableViewCell)(CustomCell.h & .m), CustomCell.h having all of the
properties as iboutlet for labels, images etc. and synthesize them all
in implementation.
After creating this custom class go back to storyboard, select the
custom cell, change its class to the CustomCell and give it some
identifier like "MyCustomCell", then right click on the custom cell
and connect the IBOutlets with labels etc.
Now import CustomCell class in the class where you are implementing
the UITableView and use the properties you defined in CustomCell
class.
- (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *) indexPath
{
static NSString *MyIdentifier = #"MyCustomCell";
CustomCell*cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
// Here we use the provided setImageWithURL: method to load the web image
// Ensure you use a placeholder image otherwise cells will be initialized with no image
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://example.com/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder"]];
cell.myCustomLabel.text = #"My Text";
return cell; }
Select the cell on your Storyboard, and enter the name of your class in this field.
When you dequeue it from the identifier, it'll be an instance of that class.
Please note that each regular tableViewCell has a builtin and hidden UIImageView.
In Objective-C, you simply do this within your cellForRowAtIndexPath,
cell.imageView.image = [UIImage imageNamed:#"My awesome image"];
In Swift, it's pretty close.
cell.imageView?.image = UIImage(named: "My awesome image")

UITableView Slow to load

I have an UIViewController with an UITableView inside him, I draw the items inside my Table using the Interface (Drag and drop Labels, and UITextViews) my table have 25 rows.
Now it's time to link my labels with IBOutlets for this I create a Subclass of TableViewCell Like this:
TableViewCell.h
#property (nonatomic, retain) IBOutlet UILabel *label1;
TableViewCell.m
#synthesize label1 = _label1;
And I use this code for change my first label:
- (UITableViewCell *)tableView:(UITableView *)tableView2 cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [menuItems objectAtIndex:indexPath.row];
HobbiesTableViewCell *cell = [tableView2 dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[HobbiesTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.label1.text = #"GG";
return cell;
}
But I saw a little problem, When I open my View (in simulator) is too slow to open (I think my table is loading), for try to solve this problem I delete the nonatomic of my property and my View open faster.
But I have one question, When I create Properties I always put the command nonatomic, and in this project I had to take it off because the slowness, have a problem to take off the nonatomic in this property?(Since the labels will never be changed!)
You should make label1 weak, as it is is in Storyboard. You also don't need to #synthesize anymore.
Also, if you are dequeuing with different identifiers, you are really not dequeueing. Prototype cells should have one identifier in storyboard.
NSString *CellIdentifier = #"MyCellID"
HobbiesTableViewCell *cell = [tableView2 dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Nonatomic should increase performance, and is not causing your problem.
From what you have listed, I would rather blame not the table view, but the way you fill menuItems. Does its contents come from the internet or a file? If yes, I guess the problem is that you perform access to a remote data source on the main thread.
UPD:
After a short talk with the PO it became clear the the issue was because of having 25 cells with different Reuse ID's.

Custom prototype cell xcode 6

Good morning,
I would like to create a custom design for my prototype cell and I don't have any idea on how to do that. I have tried to follow some guides or tutorials but I always get some error and there is something that I'm not doing right.
At the moment I'm using the default prototye cell to display the following:
http://i.stack.imgur.com/TnYGZ.png
Now I would like to insert a UIImageView, and also 2 UILabels (something like Facebook) with the author and the image displayed in the prototype cell.
How can I do that? Can you show me some example or a good tutorial to follow?
Thanks in advance.
A brief list of things to do in order to achieve your goal is:
1) Create a Cocoa Touch Class File subclass of UITableViewCell
2) Click on storyboard, and change the class of your cell to this one you created
3) Create your IBOutlets for the views you added to your cell (UILabel, UIImageView, etc)
4) Then under cellForRowAtIndexPath, dequeue your customCell and pass data to your views
For example:
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"yourCellIdentifier" forIndexPath:indexPath];
cell.yourImageView.image = [UIImage imageNamed:#"yourImage"];
cell.yourLabel.text = #"Your text";
These are the basic steps to configure your cell, but you can follow this tutorial here since you are a new iOS Developer, and a Video Tutorial comes more handy for you.
Creating a Custom UITableViewCell
Check this tutorial for how to make custom cell with different ways, and this that discuss it in details starting from how to use storyboards.
eridb explained you with IBOutlet. If you want to do that programmatically;
1-) Create new UITableViewCell class. (e.g NewTableViewCell)
2-) Create your properties in NewTableViewCell.h
3-) Create and customize your properties in NewTableViewCell.m like that;
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self)
{
// create label, uiimageview, etc. here
}
return self;
}
4-) Ok, your custom UITableViewCell class is ready. Now, call it whereever you want to use (e.g NewTableViewController);
#import "NewTableViewCell.h"
5-) Configure your cell in cellForRowAtIndexPath like that;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *reuseIdentifier = #"myTableViewID";
NewTableViewCell *cell = (NewTableViewCell *)[tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if(cell == nil)
{
cell = [[NewTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
}
cell.yourCustomLabel.text = #"Label-1 text";
cell.yourCustomImageView.image = [UIImage imageNamed:#"test"];
return cell;
}

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!

Copying UITableViewCell

I'm reading a custom table cell in tableView:cellForRowAtIndexPath: from a nib file. This works great for my purposes, except it's quite slow.
Now, I know the right thing to do in the long term is to create the cell entirely in code, and to use a single view, and so on. But this is a prototype, and I don't want to put that much effort into it.
For now, I'd be happy if I was reading the nib only once in the UIViewController subclass, then tableView:cellForRowAtIndexPath: made copies of it. My assumption here is that copying would be faster than reading the nib.
Here's what I use to load the nib, which I call from viewDidLoad: (and retain after)
-(id)loadFromNamed:(NSString*)name {
NSArray *objectsInNib = [[NSBundle mainBundle] loadNibNamed:name
owner:self
options:nil];
assert( objectsInNib.count == 1 );
return [objectsInNib objectAtIndex:0];
}
All is good so far. But the question is: How do I copy this over and over? Is it even possible?
I tried [_cachedObject copy] and [_cachedObject mutableCopy] but UITableViewCell doesn't support either copy protocol.
If I have to, I can just tell them to ignore the speed until I'm prepared to remove the nib entirely, but I'd rather get it going a little faster if there's a low-hanging fruit here.
Any ideas?
I think coping of table cell can be used together with dequeuing mechanism, which will allow to create cell one time (from nib or programmatically or getting it loaded automatically from other nib and linking as an outlet in IB) and then clone it or dequeue it when needed.
UITableViewCell doesn't conform to NSCopying protocol, but it supports keyed archiving/unarchiving mechanism, so it can be used for cloning.
Based on answer "
How to duplicate a UIButton in Objective C? " my data source delegate method looks like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellID = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellID];
if (!cell) {
NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:self.tableViewCell];
cell = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
}
// ... config ...
return cell;
}
And in my case self.tableViewCell is a cell that was loaded one time from view's nib file.
I don't tested what will be faster: "archive + unarchive" to clone or "load nib file + unarchive" which framework will do in case of -loadNibNamed:owner:options:, I used this method only with convenience considerations, but good chances that memory operation vs file operation will be faster.
EDIT: It appears not as easy as it seemed at first. As UIImage doesn't conforms to NSCoding, cells with configured UIImageViews can't be just copied without additional code. Yep, copying whole image is definitely not a good practice, cheers to Apple for pointing this.
Use the cell cloning built into the table view. Apple knew generating a lot of table cells was slow. Check out the docs for this method:
- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier
You create the cell once, then as new cells are requested, use that method to clone the existing cells. Then you just change what needs to be changed about the new cell and return the cell object.
Also check out the table view realted sample code provided by Apple that uses this method and show you the right way. The fact your cell was loaded from a nib shouldn't matter at all.
Minor clarification: I dont think the above method clone cells for you. Instead it takes cell object that have scrolled off the screen and simply moves them to a new spot. So it's literally reusing a cell. So be sure your custom table view can be set to all the new values it needs outside of the intialization.
Not proud of this solution, but it works with the maximum number of possible IB bindings:
Interface (AlbumTableViewCell is a subclass of UITableViewCell of which an instance is defined in AlbumViewController's XIB file):
#interface AlbumsViewController : UITableViewController {
IBOutlet AlbumTableViewCell *tableViewCellTrack;
}
#property (nonatomic, retain) AlbumTableViewCell *tableViewCellTrack;
Implementation (unarchive / archive makes a copy / clones the table view cell):
#implementation AlbumsViewController
#synthesize tableViewCellTrack;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
AlbumTableViewCell *cell = (AlbumTableViewCell *)[tableView dequeueReusableCellWithIdentifier: #"AlbumCell"];
if (cell == nil) {
AlbumsViewController *albumsViewController = [[[AlbumsViewController alloc] init] autorelease];
[[NSBundle mainBundle] loadNibNamed: #"AlbumsViewController" owner: albumsViewController options: nil];
cell = albumsViewController.tableViewCellTrack;
}
cell.labelTitle.text = ...;
cell.labelArtist.text = ...;
return cell;
}
Well, I'm not sure why all the tutorials out there doesn't specify this step.
When using your own custom UITableViewCell from Nib, calling dequeueReusableCellWithIdentifier is not enough. You have to specify the "Identifier" in the IB, just for for it in the Table View Cell tab section.
Then make sure the identifier you put in IB is the same as the identifier you use for the dequeueReusableCellWithIdentifier.
Here it is in Swift
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : UITableViewCell?
let cellId = String(format: "Cell%d", indexPath.row)
cell = alertTable!.dequeueReusableCellWithIdentifier(cellId) as! UITableViewCell?
if cell == nil {
let archivedData = NSKeyedArchiver.archivedDataWithRootObject(masterTableCell!)
cell = NSKeyedUnarchiver.unarchiveObjectWithData(archivedData) as! UITableViewCell?
}
// do some stuff
return cell!
}

Resources