How to make use of cell reuse in UITableViewSource in Xamarin? - ios

I have UITableViewSource class which is used for the UISearchDisplayController. In my main table view I have a custom cell which works fine. Now I want to use the custom cell also for the table view of the search results. But I only manage it to display the default style with
public class SearchSource : UITableViewSource
{
static NSString cellIdentifier = new NSString("CustomCell");
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell (cellIdentifier);
if (cell == null)
cell = new UITableViewCell (UITableViewCellStyle.Default, cellIdentifier);
cell.TextLabel.Text = myList [indexPath.Row].Name;
return cell;
}
But here I only have the standard cell and I want my custom cell. The custom cell on the main table view uses the following code:
public partial class TestViewController : UITableViewController
{
static NSString cellIdentifier = new NSString("CustomCell");
public TestViewController (IntPtr handle) : base (handle)
{
TableView.RegisterClassForCellReuse (typeof(CustomCell), cellIdentifier);
}
public class TableSource : UITableViewSource {
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath){
CustomCell cell = (CustomCell)tableView.DequeueReusableCell (cellIdentifier);
cell.UpdateCell(...);
}
}
Here is the constructor of the CustomCell:
public CustomCell (IntPtr handle) : base(handle)
This is how I create the UISearchDisplayController:
// create search controller
searchBar = new UISearchBar (new RectangleF (0, 0, View.Frame.Width, 50)) {
Placeholder = "Enter a search query"
};
searchController = new UISearchDisplayController (searchBar, this);
searchController.Delegate = new SearchDelegate (tableItems);
searchController.SearchResultsSource = new SearchSource (searchController);
this.TableView.TableHeaderView = searchBar;
But everything I try leads to a crash of the app (no reference, cannot dequeue, ...) or there is a constructor mismatch.
How can I use my custom cell for the table view generated by the UISearchDisplayController?

Switching to the new cell reuse pattern since iOS 6 I adapted my SearchSource to
CustomPatientCell cell = (CustomCell)tableView.DequeueReusableCell (cellIdentifier);
and I added the following to my TestViewController:
searchController.SearchResultsTableView.RegisterClassForCellReuse(typeof(CustomCell), cellIdentifier);
I only had to add some methods like GetHeightForRow to my SearchSource to get this thing to work.
Now I have two similar implementations of TableSource and SearchSource - perhaps it is possible to summarize both? I saw from other implementations that methods like numberOfRowsInSection query which table view is currently active. How could I summarize that also?

Related

GetCell method ignores changed values

I have a UITableView set up with GetCell, RowsInSection, and other methods required for my UITableView. Here is my code:
using UIKit;
...
namespace ...
{
public partial class (className) : UIViewController, IUITextFieldDelegate, IUITableViewDataSource, IUITableViewDelegate
bool test = false;
public override void ViewDidLoad()
{
base.ViewDidLoad();
table.ReloadData();
table.DataSource = this;
table.Delegate = this;
test = true;
}
...
public nint RowsInSection(UITableView tableview, nint section)
{
return 2;
}
public UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell("cell") as Cell;
bool selected = test;
cell.Setup(selected);
return cell;
}
}
What I attempt to do is checking a changed value of a variable while setting up the cell in GetCell. However, it seems that the GetCell method ignores the changed value of the variable test, so my question is how do I access the variable after the change in ViewDidLoad.
Call table.ReloadData(); after modifying test , because reloadData is used to trigger all the methods in the delegate including GetCell .
table.DataSource = this;
table.Delegate = this;
test = true;
table.ReloadData();
Your code is not for cell reuse , pls refer to the correct way here .
//register
table.RegisterClassForCellReuse (typeof(Cell), "cell");
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
//cell reuse
var cell = (Cell) tableView.DequeueReusableCell ("cell", indexPath);
if (cell == null) cell = new Cell("cell");
bool selected = test;
cell.Setup(selected);
return cell;
}

How do I put a button inside a tableview cell?

I'm new to this, so I have troubles doing that. My goal is too put, like the title said, a button inside a cell. If you want to see my code, so that this could help you to answer this question, here is the code:
using System;
using System.Collections.Generic;
using System.Text;
using Foundation;
using UIKit;
namespace TableView
{
public class TableSource : UITableViewSource
{
string[] tableItems;
string cellIdentifier = "TableCell";
public TableSource (string[] items)
{
tableItems = items;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return tableItems.Length;
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
new UIAlertView("Alert", "You selected: " + tableItems[indexPath.Row], null, "Next Site", null).Show();
tableView.DeselectRow(indexPath, true);
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell(cellIdentifier);
if (cell == null)
cell = new UITableViewCell(UITableViewCellStyle.Subtitle, cellIdentifier);
cell.TextLabel.Text = tableItems[indexPath.Row];
if(indexPath.Row > -1)
cell.DetailTextLabel.Text = tableItems[indexPath.Row - 0];
return cell;
}
}
}
Here is the code for ViewController, if this is needed to.
Create a custom TableViewCell and add the button there. Than use that custom TableViewCell in your GetCell method.
class MyButtonTableViewCell : UITableViewCell
{
public UIButton MyButton { get; private set; }
public MyButtonTableViewCell() : base(UITableViewCellStyle.Default, "MyButtonCell")
{
MyButton = new UIButton(UIButtonType.System);
MyButton.Frame = ContentView.Bounds;
MyButton.SetTitle("My Title", UIControlState.Normal);
ContentView.AddSubview(MyButton);
}
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell("MyButtonCell");
if (cell == null)
cell = MyButtonTableViewCell();
return cell;
}
First of all you need to add a tag to the button so that you can see what button is being pressed inside the cellForRowAtIndexPath function like this:
cell.Button.tag = indexPath.row
Then inside an IBAction you can see exactly what row's button was pressed like this:
#IBAction func buttonPressed(sender: AnyObject)
{
let button = sender as! UIButton
let index = NSIndexPath(forRow: button.tag, inSection: 0)
}

Add a Custom Footer at the end of UITableView in Xamarin.iOS

I want to add a footer view to a UITableView that shows a UIProgresIndicator when the user has reached the end of the list and new data will be loaded, or a UILabel when there are no more data to be fetched.
I have used the code below, but nothing happens:
UITableViewHeaderFooterView footer = new UITableViewHeaderFooterView ();
UILabel futerlabel = new UILabel ();
futerlabel.Text = "Duke u ngarkuar";
footer.AddSubview (futerlabel);
Any way how to achieve this.
If you are in a UITableViewController try this:
TableView.TableFooterView = footer;
UPDATE
After having a think about this I would suggest not using a footer but rather an extra cell at the end of your data, this will get this effect.
Using this method to check if you have scrolled to the last item and to update the table's data:
public override void WillDisplay (UITableView tableView, UITableViewCell cell, NSIndexPath indexPath)
{
// if showing last row of last section, load more
if (indexPath.Section == tableView.NumberOfSections()-1 && indexPath.Row == tableView.DataSource.RowsInSection(tableView, indexPath.Section)-1 && !FullyLoaded) {
var growRowSource = tableView.DataSource as GrowRowTableDataSource;
if (growRowSource != null) {
FullyLoaded = growRowSource.LoadNextPage ();
Task.Delay (5000);
tableView.ReloadData ();
}
}
}
And then in the Delegate checking for the last item and creating a different cell like so:
public override UITableViewCell GetCell (UITableView tableView, Foundation.NSIndexPath indexPath)
{
if (indexPath.Row == LoadedItems.Count) {
var loadingCell = tableView.DequeueReusableCell (LoadingCellID, indexPath) as LoadFooterCell;
loadingCell.Loading = !hasNextPage;
return loadingCell;
}
var cell = tableView.DequeueReusableCell (CellID, indexPath) as GrowRowTableCell;
var item = LoadedItems [indexPath.Row];
// Setup
cell.Image = UIImage.FromFile(item.ImageName);
cell.Title = item.Title;
cell.Description = item.Description;
return cell;
}
bool hasNextPage;
I quickly mocked an example from the GrowTable Xamarin sample code here:
https://github.com/b099l3/LoadingTableExample
You could accomplish this in several ways, I will layout a few here:
In your TableViewSource you can do this:
1.) Implement: public override UIView GetViewForFooter(UITableView tableView, nint section) and return your UILabel
2.) Implement public override nfloat GetHeightForFooter(UITableView tableView, nint section) and return a height for your UIView
If your Footer is going to be a simple UILabel, you can replace Step 1 above with this:
Implement public override string TitleForFooter(UITableView tableView, nint section) and return "Duke u ngarkuar".
You will still need to implement public override nfloat GetHeightForFooter(UITableView tableView, nint section) and return a height otherwise your footer wont show up.
Alternatively, UITableView exposes a property called TableFooterViewthat allows you to set a UIView for a footer.
You can size this to your liking.
var footerView = new UIView(new RectangleF(0, 0, 375, 66));
TableView.TableFooterView = footerView;

Xamarin Table View Crash

I want to use UITableView on XamarinApp.
I tried UITableView example Populating a Table with Data ,but it doesn't work.
When i used this.Add(table); cause crash. When I remove this.Add(table) it's shows empty table.
Please help me...
Here is my code
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
namespace KUkyuko
{
partial class MyTableViewSource : UITableView
{
public MyTableViewSource(IntPtr handle) : base (handle)
{
var table = this;
string[] tableItems = new string[] {"Vegetables","Fruits","Flower Buds","Legumes","Bulbs","Tubers"};
table.Source = new TableSource(tableItems);
this.Add(table); //this code cause crash
}
}
public class TableSource : UITableViewSource {
string[] TableItems;
string CellIdentifier = "TableCell";
public TableSource (string[] items)
{
TableItems = items;
}
public override nint RowsInSection (UITableView tableview, nint section)
{
return TableItems.Length;
}
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell (CellIdentifier);
string item = TableItems[indexPath.Row];
//---- if there are no cells to reuse, create a new one
if (cell == null)
{ cell = new UITableViewCell (UITableViewCellStyle.Default, CellIdentifier); }
cell.TextLabel.Text = item;
return cell;
}
}
}
Im abit unsure as to what you trying to achieve but
I would change the tableview to a tableViewController like so::
partial class TableViewController : UITableViewController
{
public TableViewController (IntPtr handle) : base (handle)
{
// Register the TableView's data source
string[] tableItems = new string[] {"Vegetables","Fruits","Flower Buds","Legumes","Bulbs","Tubers"};
this.TableView.Source = new TableSource(tableItems);
}
}
public class TableSource : UITableViewSource {
string[] TableItems;
string CellIdentifier = "TableCell";
public TableSource (string[] items)
{
TableItems = items;
}
public override nint RowsInSection (UITableView tableview, nint section)
{
return TableItems.Length;
}
public override nint NumberOfSections (UITableView tableView)
{
// TODO: return the actual number of sections
return 1;
}
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell (CellIdentifier);
string item = TableItems[indexPath.Row];
//---- if there are no cells to reuse, create a new one
if (cell == null)
{ cell = new UITableViewCell (UITableViewCellStyle.Default, CellIdentifier); }
cell.TextLabel.Text = item;
return cell;
}
}
If you are using the table inside a viewController then you need to do this part in your viewController and set up a outlet for the table.
The reason this code crashes as you are adding this to this:
var table = this;
string[] tableItems = new string[] {"Vegetables","Fruits","Flower Buds","Legumes","Bulbs","Tubers"};
table.Source = new TableSource(tableItems);
this.Add(table); //this code cause crash as it is the same as this.Add(this)
Hope this helps!

Monotouch custom UITableViewCell GetCell not initialising new custom view cells

I've been foloowing a number of tutorials to put together a custom table view cell using storyboard for a prototype table view.
I'm new to monotouch and managed to get a working solution for standard cell types. Running into issues with custom view cells as I'm unable to initialise a fresh cell in the correct manner. Some old tutorials appear to load a cell nib file but I'm using storyboard with the below code.
Where am I going wrong?
(I would use monotouch dialog but not couldn't figure out a way to add lovely uipickerviews on accessory, etc in a simple manner).
http://docs.xamarin.com/guides/ios/user_interface/tables/part_5_-_using_xcode%2C_interface_builder%2C_and_storyboards
public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
// in a Storyboard, Dequeue will ALWAYS return a cell
//*** above comment doesnt seem to hold for custom uitableview cells
UITableViewCell cell = tableView.DequeueReusableCell (cellIdentifier);
// now set the properties as normal
cell.TextLabel.Text = tableItems[indexPath.Row].Name;
if (tableItems[indexPath.Row].Done)
cell.Accessory = UITableViewCellAccessory.Checkmark;
else
cell.Accessory = UITableViewCellAccessory.None;
return cell;
}
// here's my implementation of GetCell but problem is that I can't seem to generate a new cell
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
_cellIdentifier = "SingleTimeViewCell";
CustomViewCell cell = tableView.DequeueReusableCell (_cellIdentifier) as
// if (cell == null)
// {
// cell = new SingleTimeViewCell();
// }
cell.myCustomProperty = "hello";
return cell;
}
// here's the auto generated CustomViewCell class from Xcode storyboard
public partial class CustomViewCell : UITableViewCell
{
public CustomViewCell () : base() // I added this ctor but it didnt seem to help matters
{
}
public CustomViewCell (IntPtr handle) : base (handle)
{
}
}
It can be done using only storyboards with prototype cells, see this sample from Xamarin forums.
Here is the relevant code (credit to Stephane Cordonnier):
public partial class CustomCellStoryBoardViewController : UIViewController
{
public CustomCellStoryBoardViewController(IntPtr handle) : base (handle)
{
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.MyTableView.DataSource = new MyDataSource();
}
private class MyDataSource : UITableViewDataSource
{
private String[] items = {"Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
public MyDataSource()
{
}
public override int RowsInSection(UITableView tableView, int section)
{
return this.items.Length;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
MyCustomCell cell = (MyCustomCell)tableView.DequeueReusableCell(MyCustomCell.Key);
cell.SetTitle(this.items[indexPath.Row]);
return cell;
}
}
}
The custom cell:
[Register ("MyCustomCell")]
public class MyCustomCell : UITableViewCell
{
[Outlet]
MonoTouch.UIKit.UILabel TitleLabel { get; set; }
public static readonly NSString Key = new NSString("MyCustomCell");
public MyCustomCell(IntPtr handle) : base(handle)
{
}
public void SetTitle(String title)
{
this.TitleLabel.Text = title;
}
}
Make sure you have set the custom cell class and identifier to the name of your cell class in the storyboard.
In your .xib file, for that cell, are you using the same cell identifier 'SingleTimeViewCell'. I'm not sure exactly how you've created your custom cell but I know I had what sounds like the same issue.
You cant'd do it with storyboard. Use main storyboard and separate xib files for the cells.
I read so mush non sense about tableview cell and reuse and Xib,
Almost every sample code a found jsute don't reuse properly...
on iOS6 and further the simplest way to do it :
create a new UITABLEVIEWCELL from Xamarin. (let's say MyCustomCell)
in InterfaceBuilder set the Identifier of the cell to the value of MyCustomCell.Key (found the value in MyCsutomCell.cs created by Xamarin Studio)
In your ViewController Register the nib this way :
tableView.RegisterNibForCellReuse (MyCsutomCell.Nib, MyCsutomCell.Key);
then on the GetCell méthode in your dataSource symple dequeue a cell (it will create one if none exists):
MyCsutomCell cell = tableView.DequeueReusableCell (MyCsutomCell.Key) as MyCsutomCell;

Resources