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

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

Related

How to read cell value long press gesture on table cell in xamarin.ios?

I have Tableview with longpress cell.
I can't read the data inside the cell which have been long pressed.
rowselected() method is not the right way because I must select cell first. I didn't want to select cell first.
This is my table adapter class:
internal class AbsetAdapterClass : UITableViewSource
{
private List<benood2.AbsentClass> absentList;
public AbsetAdapterClass(List<benood2.AbsentClass> absentList)
{
this.absentList = absentList;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = (TableClass)tableView.DequeueReusableCell("cell_id", indexPath);
var AbsentDay = absentList[indexPath.Row];
var longPressGesture = new UILongPressGestureRecognizer(LongPressMethod);
cell.AddGestureRecognizer(longPressGesture);
cell.UpdateCell(AbsentDay);
return cell;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return absentList.Count;
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
PublicClass.ReadCellValue = "";
var GetCellValue = absentList[indexPath.Row].BandValue;
tableView.DeselectRow(indexPath, true);
}
void LongPressMethod(UILongPressGestureRecognizer gestureRecognizer)
{
if (gestureRecognizer.State == UIGestureRecognizerState.Began)
{
Toast.MakeToast("I want to read the cell data ").SetTitle(PublicClass.ReadCellID.ToString()).SetDuration(ToastDuration.Regular).Show();
}
}
}
I can't get the long press cell data
You could attach LongPressGesture to the UITableView instead of the UITableViewCell.
You could try the following code (Note: i made my demo based on the Xamarin.iOS official samples):
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
table = new UITableView(new CGRect(0, 0, width, height));
...
// add longPressGesture to the tableView
var longPressGesture = new UILongPressGestureRecognizer(LongPressMethod);
table.AddGestureRecognizer(longPressGesture);
...
}
Then for LongPressMethod:
void LongPressMethod(UILongPressGestureRecognizer gestureRecognizer)
{
var p = gestureRecognizer.LocationInView(table);
var indexPath = table.IndexPathForRowAtPoint(p);
if (indexPath == null)
{
Console.WriteLine("Long press on table view but not on a row.");
}
else if (gestureRecognizer.State == UIGestureRecognizerState.Began)
{
Console.WriteLine("Long press on {0} row", indexPath.Row);
//you could get the selectedItem through the Row index
}
}
For more info, you could refer to Working with Tables and Cells in Xamarin.iOS.
Hope it works for you.

Dynamic UITableViewCell based on UILabel

Working with Xamarin.ios and I need my UITableViewCell to adjust its height based on the size (number of lines of text) of a UILabel. I have a custom UITableViewCell where the UILabel is created and the text is set based on user input. The only way I really know how to adjust the height of the cell is in the UITableViewSource class using the public override nint RowsInSection(UITableView tableview, nint section) method.
public class ChatTableSource : UITableViewSource
{
public List<MessageDetails> messages;
public ChatTableSource()
{
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
CustomMessageCell cell = tableView.DequeueReusableCell(cellIdentifier) as CustomMessageCell;
// if there are no cells to reuse, create a new one
if (cell == null)
cell = new CustomMessageCell(cellIdentifier);
tableView.Layer.BackgroundColor = UIColor.White.CGColor;
cell.UpdateCell(messages[indexPath.Row].body);
return cell;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return messages.ToArray().Length;
}
//public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
//{
// return dynamic size
//}
}
public class CustomMessageCell : UITableViewCell
{
UILabel body;
public CustomMessageCell(NSString cellId) : base(UITableViewCellStyle.Default, cellId)
{
body = new UILabel();
ContentView.Add(body);
}
public void UpdateCell(string body)
{
this.body.Text = body;
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
body.Frame = new CGRect(distanceFromScreenEdge, ContentView.Bounds.Top, longTextSize, ContentView.Bounds.Height);
body.Lines = 0;
}
}
I don't work with Xamarin - so I can't test this - but this should be what you want to do...
Use constraints and let auto-layout handle the sizing for you.
public class CustomMessageCell : UITableViewCell
{
UILabel body;
public CustomMessageCell(NSString cellId) : base(UITableViewCellStyle.Default, cellId)
{
body = new UILabel();
ContentView.Add(body);
var margins = View.LayoutMarginsGuide;
// Pin the leading edge of body to the margin
body.LeadingAnchor.ConstraintEqualTo (margins.LeadingAnchor).Active = true;
// Pin the trailing edge of body to the margin
body.TrailingAnchor.ConstraintEqualTo (margins.TrailingAnchor).Active = true;
// Pin the top edge of body to the margin
body.TopAnchor.ConstraintEqualTo (margins.TopAnchor).Active = true;
// Pin the bottom edge of body to the margin
body.BottomAnchor.ConstraintEqualTo (margins.BottomAnchor).Active = true;
// set body number of lines to Zero so it will automatically set its own height
body.Lines = 0
}
public void UpdateCell(string body)
{
this.body.Text = body;
}
}
You don't need LayoutSubviews() at all.

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.

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;

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