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

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;

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;
}

CollectionView inside TableViewCell

I used CollectionView inside TableViewCell. All works fine and shown all as expected. But if I scrolled the TableView very fast, items (i used images in collectionView) from one collection replaced with items (images) from another collection and override it on View (on Debug mode in code al works fine, its just displaying of them).
UITableView GetCell():
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var item = _view.Items[indexPath.Row];
var cell = (MyTableCell)tableView.DequeueReusableCell(“cell”);
cell.TextLabelView.Text = item.Title;
cell.YesButtonView.Hidden = item.IsCategory;
cell.NoButtonView.Hidden = item.IsCategory;
if (item.IsImagePoint)
{
cell.ImagesCollectionView.DataSource = new ItemsDataSource(item.Images, cell.ImagesCollectionView);
cell.ImagesCollectionView.Delegate = new ItemsDelegate(item, _view);
}
return cell;
}
UICollectionView GetCell():
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
var cell = (ImageViewCell)_collectionView.DequeueReusableCell(new NSString(“ImageViewCell”), indexPath);
var image = _images[indexPath.Row];
var imagePath = image.ThumbnailPath;
if (!string.IsNullOrEmpty(imagePath))
{
cell.ImagePath = imagePath;
}
return cell;
}
Swift 5
Add this in your custom UITableViewCell class.
override func prepareForReuse() {
collectionView.dataSource = nil
collectionView.delegate = nil
collectionView.reloadData()
collectionView.dataSource = self
collectionView.delegate = self
}
It's probably because of the reuse system of cells in UITableView. Do you set up properly your data when you configure the cell? Do you call CollectionView's reloadData()?
EDIT: You should call it in the tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell where you configure your cell. This way, each time a cell is reused, you update its content.
EDIT 2: Just like I said try to add the collection view reloadData() when you set up your tableview cell. You also have to clean your datasource and delegate, because it's a reused cell so it may already have been used with another value.
if (item.IsImagePoint)
{
cell.ImagesCollectionView.DataSource = new ItemsDataSource(item.Images, cell.ImagesCollectionView);
cell.ImagesCollectionView.Delegate = new ItemsDelegate(item, _view);
}
else
{
cell.ImagesCollectionView.DataSource = null;
cell.ImagesCollectionView.Delegate = null;
}
cell.ImagesCollectionView.ReloadData()
return cell;

Cell size not changed in collection view IOS (Implemented in Xamarin)

I have a collection view that needs to have the cells fitting size to content.
I use sizeForItemAtIndexPath: to set size for each cell.
It's fired and works great.
Here is the problem what I am facing.
The data list for collection view is changed dynamically.
collection view has only 1 item to show and shows it in correct cell size(let's say size1)
next time collection view has 1 item to show again but it's different data.
In this case, the collection view doesn't show it in correct cell size. it shows in size1
I want to show next item in its own size but collection view keep original size.
When item count is changed, sizeForItemAtIndexPath: is fired again.
When item count is same, it's not fired.
I want it to be fired everytime.
I share some of my code.
cllSelected.Source = new SelectedItemSource(this, _selectedItems);
Above code will be called whenever there is new _selectedItems
I implemented the UICollectionViewSource as following
public class SelectedItemSource : UICollectionViewSource, IUICollectionViewDelegateFlowLayout
{
CatalogVC _ownerVC;
SelectedCategoryList _selectedItems;
public SelectedItemSource(CatalogVC ownerVC, SelectedCategoryList selectedItems)
{
_ownerVC = ownerVC;
_selectedItems = selectedItems;
}
public override nint NumberOfSections(UICollectionView collectionView)
{
return 1;
}
public override nint GetItemsCount(UICollectionView collectionView, nint section)
{
return _selectedItems != null ? _selectedItems.Count : 0;
}
public override bool ShouldHighlightItem(UICollectionView collectionView, Foundation.NSIndexPath indexPath)
{
return true;
}
public override void ItemHighlighted(UICollectionView collectionView, Foundation.NSIndexPath indexPath)
{
}
public override void ItemUnhighlighted(UICollectionView collectionView, Foundation.NSIndexPath indexPath)
{
_ownerVC.SelectedFilter_ItemClick(indexPath.Row);
}
public override UICollectionViewCell GetCell(UICollectionView collectionView, Foundation.NSIndexPath indexPath)
{
SelectedFilterCollectionCell cell = collectionView.DequeueReusableCell("SelectedFilterCollectionCell", indexPath) as SelectedFilterCollectionCell;
cell.Layer.ShouldRasterize = true;
cell.Layer.RasterizationScale = UIScreen.MainScreen.Scale;
cell.BindDataToCell(_selectedItems[indexPath.Row]);
return cell;
}
[Export("collectionView:layout:sizeForItemAtIndexPath:")]
public CoreGraphics.CGSize GetSizeForItem(UICollectionView collectionView, UICollectionViewLayout layout, Foundation.NSIndexPath indexPath)
{
var text = new NSString(_selectedItems[indexPath.Row].Text);
CGSize cellSize = new CGSize(xxx, yyy); // cellSize will be determined according to text
return cellSize;
}
}
Thanks for any solution or suggestion!
Try to call CollectionView.ReloadData() after the data changes.
I think it will invoke the methods included in the delegate.

iOS Auto-resize custom cell width in UITableViewHeaderFooterView.ContentView Subview

I create a custom cell PVIssueTypeSectionHeaderCell and add it as a subview for ContentView in the header view with this code:
public override UIView GetViewForHeader(UITableView tableView, nint section)
{
var cell = (PVIssueTypeSectionHeaderCell)tableView.DequeueReusableCell(HeaderCellKey);
if(cell == null)
{
cell = PVIssueTypeSectionHeaderCell.Create();
}
cell.ViewModel = this.GroupedIssueTypesFilter.ElementAt((int)section);
var headerView = tableView.DequeueReusableHeaderFooterView(HeaderFooterViewKey);
if (headerView == null)
{
headerView = new UITableViewHeaderFooterView(HeaderFooterViewKey);
}
headerView.ContentView.AddSubview(cell);
return headerView;
}
But the custom cell's width does not auto-resize as you could see in these images below.
This is in iPad Landscape mode and in iPhone Portrait mode:
While this one is in iPad Portrait mode:
How to make the custom cell automatically resize its width?
I've finally make it work by returning my custom cell's ContentView directly in GetViewForHeader.
public override UIView GetViewForHeader(UITableView tableView, nint section)
{
var cell = (PVIssueTypeSectionHeaderCell)tableView.DequeueReusableCell(HeaderCellKey);
if(cell == null)
{
cell = PVIssueTypeSectionHeaderCell.Create();
}
cell.ViewModel = this.GroupedIssueTypesFilter.ElementAt((int)section);
return cell.ContentView;
}

Return different cell for last row of a UITableView

My app uses a UITableview to display a feed of images. The API only gives so many images at once so I want the final cell in the tableview to be small cell that has a Load More Button. To do this I created a custom cell called LoadMoreCell with an identifier LoadCell
Using the GetCell method I do:
public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
// request a recycled cell to save memory
FeedCell cell = tableView.DequeueReusableCell (cellIdentifier) as FeedCell;
if(indexPath.Row >= tableItems.Count)
{
LoadMoreCell loadCell = tableView.DequeueReusableCell ("LoadCell") as LoadMoreCell;
return loadCell;
}
//Set Date and title
cell.SetInfo (ids[indexPath.Row], userID, tableItems [indexPath.Row]);
cell.SetImage (images[indexPath.Row]);
cell.parent = this.parent;
return cell;
}
This gives me a cell at the bottom with the Load More Button, but the cell is the same dimensions as a FeedCell not the smaller dimensions of a LoadMoreCell
Anyone know what my problem might be with this?
You may need to override GetHeightForRow in your UITableViewSource
public override float GetHeightForRow (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
if (indexPath.Row >= tableItems.Count) {
return loadMoreHeight;
} else {
return regularRowHeight;
}
}
UITableViewDelegate has a method tableView:heightForRowAtIndexPath: You can return the height for the cell there.

Resources