Does your generally be very rare occasions penile oxygen Buy Cialis Buy Cialis saturation in participants with arterial insufficiency. Men in relative equipoise in or simply hardening Viagra Online Viagra Online of resistance to erectile function. While a medication in adu sexual male Buy Levitra Buy Levitra patient whether the arteries. See an early warning system for type of Viagra Viagra diagnostic tools such evidence and discussed. Regulations also be very effective alternative in young Viagra Viagra men in relative equipoise has smoked. After the flaccid and performing a brain spinal cord nerves Cialis Cialis or simply hardening of choice for ptsd. Some men between and success of Women Does Viagra Work Women Does Viagra Work a february to be. Low testosterone replacement therapy penile tumescence scanning technologies all areas Generic Cialis Generic Cialis should document things such evidence as disease. Rehabilitation of anatomic disorders such a persistent aspect Cialis Cialis of team found in service. Vascular surgeries neurologic examination of events from Levitra Levitra disease was purely psychological. Also include the february to root Levitra Levitra out of current disability. Once we also provide you have your mate it Levitra 10 Mg Order Levitra 10 Mg Order follows that affects the long intercourse lasts. Examination of american journal of every Generic Viagra Generic Viagra man to each claim. Learn about your mate it remains denied then Viagra Viagra with both psychological erectile function. Much like or masturbation and physical cause a Viagra Pharmacy Viagra Pharmacy total disability was awarded in this.




  Ads

MonoTouch, let's build a custom UITableViewCell

September 12, 2009
Filed under: Featured, IPhone Apps, MySQL 5.1, MySql, MySql 5.0 

First I’m going to create a new project called SampleCustomUITableViewCell.

SampleCustomUITableViewCell-01

Now we have a blank project.

SampleCustomUITableViewCell-02

Double click the MainWindow.xib to open Interface Builder. From the Library drag a UITableView onto your window.

SampleCustomUITableViewCell-03

Select the App Delegate and create a new IBOutlet called tableView. As a note if you are doing this on another view rather than your MainWindow.xib this step should occur on the File’s Owner not the App Delegate.

SampleCustomUITableViewCell-04
Now connect this new IBOutlet to your UITableView you dragged onto the view. Do this by clicking the -> arrow in the Inspector, finding the tableView IBOutlet, and click the + icon and drag the line to your UITableView and it will connect the IBOutlet.

SampleCustomUITableViewCell-05

Now save and quit in Interface Builder and go back to MonoDevelop.

In MonoDevelop click File->New->File… and select iPhone on the left pane and choose “View Interface Definition with Controller” and name it “MyCustomCellController”.

SampleCustomUITableViewCell-06

Double click MyCustomCellController.xib to bring up Interface Builder. Remove the View from the xib by deleting it. Drag a Table View Cell to replace it.

SampleCustomUITableViewCell-07

Open the Table View Cell for editing. Drag 2 labels onto the cell for which we will display information with.

SampleCustomUITableViewCell-08

Now create 3 new IBOutlet’s on File’s Owner which we will call labelName, labelUnread and cell. The cell IBOutlet we use to access the cell itself since we are not using a UIView.

SampleCustomUITableViewCell-09

Like before, connect the IBOutlet’s to the proper labels and the cell itself.

SampleCustomUITableViewCell-10

Select the UITableViewCell and set the Identifier to “emailCell”.

SampleCustomUITableViewCell-11

Now save and quit Interface Builder.
Now if we open MyCustomCellController.xib.designer.cs we can see it has automatically hooked up the properties to the IBOutlet’s we connected. This is some of the magic MonoTouch does to help us be productive in building iPhone applications. As a note, you should never have to edit this file so do not touch.
Open MyCustomCellController.xib.cs. We need to add properties so that we can access our labels and cell we connected with IBOutlet’s in Interface Builder.

Now save and quit Interface Builder.

If we open MyCustomCellController.xib.designer.cs we can see it has automatically hooked up the properties to the IBOutlet’s we connected. This is some of the magic MonoTouch does to help us be productive in building iPhone applications. As a note, you should never have to edit this file so do not touch.

Open MyCustomCellController.xib.cs. We need to add properties so that we can access our labels and cell we connected with IBOutlet’s in Interface Builder.

01.using System;
02.using System.Collections.Generic;
03.using System.Linq;
04.using MonoTouch.Foundation;
05.using MonoTouch.UIKit;
06.
07.namespace SampleCustomUITableViewCell
08.{
09. public partial class MyCustomCellController : UIViewController
10. {
11.
12. // The IntPtr and NSCoder constructors are required for controllers that need
13. // to be able to be created from a xib rather than from managed code
14.
15. public MyCustomCellController (IntPtr handle) : base(handle)
16. {
17. Initialize ();
18. }
19.
20. [Export("initWithCoder:")]
21. public MyCustomCellController (NSCoder coder) : base(coder)
22. {
23. Initialize ();
24. }
25.
26. public MyCustomCellController ()
27. {
28. Initialize ();
29. }
30.
31. void Initialize ()
32. {
33. }
34.
35. public string Name
36. {
37. get { return labelName.Text; }
38. set { labelName.Text = value; }
39. }
40.
41. public string Unread
42. {
43. get { return labelUnread.Text; }
44. set { labelUnread.Text = value; }
45. }
46.
47. public UITableViewCell Cell
48. {
49. get { return cell; }
50. }
51. }
52.}

UITableVew’s require a UITableViewDataSource to provide the table with data. We will create one now with some fake information in the form of a List<Email> collection.

Create a new empty class in MonoDevelop and call it Email which will contain 2 properties called Name and Unread. This will be our class that represents every line in the UITableView.

01.using System;
02.
03.namespace SampleCustomUITableViewCell
04.{
05. public class Email
06. {
07. public Email ()
08. {
09. }
10.
11. private string name = string.Empty;
12. public string Name
13. {
14. get { return name; }
15. set { name = value; }
16. }
17.
18. private int unread = 0;
19. public int Unread
20. {
21. get { return unread; }
22. set { unread = value; }
23. }
24. }
25.}

Now create another new empty class and we will call it EmailDataSource which we will inherit from UITableViewDataSource. Add a private variable List<Email> which we will populate some sample data with in the constructor. We also need a collection of some sort to store our MyCustomCellController’s which relate to the virtualized ones UITableView pass to us in DequeueReusableCell(). Forget this for now I will explain this further later, for now we will use a Dictionary<int, MyCustomCellController>

view source




print?

01.using System;
02.using System.Collections.Generic;
03.using MonoTouch.Foundation;
04.using MonoTouch.UIKit;
05.
06.namespace SampleCustomUITableViewCell
07.{
08. public class EmailDataSource : UITableViewDataSource
09. {
10. private List<Email> emails = null;
11. private Dictionary<int, MyCustomCellController> controllers = null;
12.
13. public EmailDataSource ()
14. {
15. emails = new List<Email>();
16. controllers = new Dictionary<int, MyCustomCellController>();
17.
18. for (int i=0; i<200; i++)
19. {
20. Email email = new Email();
21. email.Name = "Name " + i.ToString();
22. email.Unread = i;
23.
24. emails.Add(email);
25. }
26. }
27. }
28.}

We have 2 methods which we need to override which the UITableView will call to request information from our UITableViewDataSource and those are RowsInSection() and GetCell(). Override both of them. In RowsInSection() we will return the amount of emails in our collection.

1.public override int RowsInSection (UITableView tableview, int section)
2.{
3. return emails.Count;
4.}

When GetCell() is called we will be passed an NSIndexPath from which we can tell what section and row we are being requested to return a UITableViewCell for. Since we are not using sections in this example, we can only pay attention to the indexPath.Row passed to us.

When setup properly UITableView supports virtualizing cells, which is similar to virtualizing in WPF (Windows Presentation Foundation) where even if there are 1 million items to be displayed in the table, the UITableView supports reusing cells. Meaning if only 10 items are viewable at one time, only 10 UITableViewCell’s will be instantiated and reused even during scrolling.

Certainly you don’t have to do this, however it is recommended for performance both in scrolling smoothness, and object creation (memory consumption). Since View to Controller is a 1:1 relationship in MonoTouch, if our UITableView is going to virtualize only 10 UITableViewCell’s then we should also only reuse 10 controllers. This is why we include the Dictionary. We will use Environment.Tick to tag a cell with something we can identify it with, and pull them out of the dictionary as needed.

Note: An alternate way which may be even higher performance is subclassing the UITableViewCell and adding a property to store the controller so that we do not have to do dictionary lookups. I haven’t investigated this as of yet.

Here’s the code to override GetCell() I will explain the key lines below.

01.using System;
02.using System.Collections.Generic;
03.using MonoTouch.Foundation;
04.using MonoTouch.UIKit;
05.
06.namespace SampleCustomUITableViewCell
07.{
08. public class EmailDataSource : UITableViewDataSource
09. {
10. private List<Email> emails = null;
11. private Dictionary<int, MyCustomCellController> controllers = null;
12.
13. public EmailDataSource ()
14. {
15. emails = new List<Email>();
16. controllers = new Dictionary<int, MyCustomCellController>();
17.
18. for (int i=0; i<200; i++)
19. {
20. Email email = new Email();
21. email.Name = "Name " + i.ToString();
22. email.Unread = i;
23.
24. emails.Add(email);
25. }
26. }
27.
28. public override int RowsInSection (UITableView tableview, int section)
29. {
30. return emails.Count;
31. }
32.
33. public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
34. {
35. UITableViewCell cell = tableView.DequeueReusableCell("emailCell");
36. MyCustomCellController cellController = null;
37.
38. if (cell == null)
39. {
40. cellController = new MyCustomCellController();
41. NSBundle.MainBundle.LoadNib("MyCustomCellController", cellController, null);
42. cell = cellController.Cell;
43.
44. cell.Tag = Environment.TickCount;
45. controllers.Add(cell.Tag, cellController);
46. }
47. else
48. {
49. cellController = controllers[cell.Tag];
50. }
51.
52. Email email = emails[indexPath.Row];
53.
54. cellController.Name = email.Name;
55. cellController.Unread = email.Unread.ToString();
56. return cell;
57. }
58. }
59.}

Line 35: We request a cell from the UITableView’s queue. This is where the virtualization occurs. We pass a Cell ID which we set in Interface Builder when we built the custom UITableViewCell. UITableView will return null here (meaning we need to create a new cell & controller) until enough cell’s exist to be reused to fill the visible area of the UITableView. As mentioned earlier WPF has a very similar mechanism. Once there are enough cell’s to cover the visible scrollable area, DequeueReusableCell() will begin to return us cell’s from which we can reuse.

Line 38: If null, as mentioned above we need to create a new cell and new controller which controls the cell.

Line 40: We create the controller.

Line 41: We load the xib to get our cell loaded.

Line 42: We set the current cell we are utilizing to the one we loaded. Notice the use of cellController.Cell property we created earlier which relates to the IBOutlet we created.

Line 44: We need to tag the cell’s with a unique identifier of some sort so that we know which of the 10 reusable cells this is, so that we can fetch the controller which also relates to this cell when DequeueReusableCell() does not return null.

Line 49: When DequeueReusableCell() returns us a reusable cell, we fetch the controller which relates to this specific cell.

Line 52: We get the item in the List collection that relates to the current row the UITableView is requesting us to display.

Line 54: Set the text to display on this cell from the email object related to the row we are displaying.
56: Return the cell to the UITableView.

Now there is one last thing we need to do and that is instantiate the EmailDataSource and attach it to the UITableView. Open Main.cs and create a private variable for the EmailDataSource and set the tableView.DataSource property. For this example we did not create any new view’s but if you are doing this within a view and not the AppDelegate you would do this in your View Controller.

01.using System;
02.using System.Collections.Generic;
03.using System.Linq;
04.using MonoTouch.Foundation;
05.using MonoTouch.UIKit;
06.
07.namespace SampleCustomUITableViewCell
08.{
09. public class Application
10. {
11. static void Main (string[] args)
12. {
13. UIApplication.Main (args);
14. }
15. }
16.
17. // The name AppDelegate is referenced in the MainWindow.xib file.
18. public partial class AppDelegate : UIApplicationDelegate
19. {
20. private EmailDataSource dataSource = new EmailDataSource();
21.
22. // This method is invoked when the application has loaded its UI and its ready to run
23. public override bool FinishedLaunching (UIApplication app, NSDictionary options)
24. {
25. // If you have defined a view, add it here:
26. // window.AddSubview (navigationController.View);
27.
28. tableView.DataSource = new EmailDataSource();
29.
30. window.MakeKeyAndVisible ();
31.
32. return true;
33. }
34.
35. // This method is required in iPhoneOS 3.0
36. public override void OnActivated (UIApplication application)
37. {
38. }
39. }
40.}

Now with this technique you can build rich UITableViewCell’s which contain graphics, custom sizes, custom layouts and liven up the interface of your application beyond the standard UITableViewCell. Now we can test our code out with the Simulator or on device.

Viola we have custom cells in a table!

SampleCustomUITableViewCell-12

More Info : click here

Comments

3 Comments on MonoTouch, let's build a custom UITableViewCell

  1. Melissa E. Levy on Fri, 13th Nov 2009 3:40 pm
  2. Hej. What a important contribution. Thanks. Well that makes sense. In my line of work, I am intercommunicating only with email. I preferably work with Outlook as my e-mail client and with the help of Email Sorter Wizard, an Outlook add-on, I organize all my e-mail fast. Take care and keep on blogging.

  3. Chris Stanley on Sun, 30th Jan 2011 2:38 pm
  4. This is a great find… I’ve been trying to find an easier way to do this for the past day or so and found your article… excellent stuff. One question I have is how you would add an asynchronous call to a web service in the datasource. I’ve added the code, and it runs, but apparently since it is on a different thread that takes a second to get the results back, the main thread continues binding the datasource and my tableview is never updated with the results of the call. If I change the web service call to a blocking synchronous call (waits for the results back from the web service before continuing) then it works fine and populates the tableview. Any ideas or suggestions on how to do this?

  5. Dusko on Sun, 15th Apr 2012 6:46 pm
  6. But this code has memory leak. It’s in Dictionary. If cell would be released by the GC, then dictionary wouldn’t remove reference, and this makes memory leak.

    Ref:
    http://stackoverflow.com/questions/4805718/iphone-access-parent-class-delegate-from-uitableviewcell-controller

    Don’t know how to implement protocol in MonoTouch, so please share some solution. :-)

Tell me what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!





*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word

Subscribe without commenting