How to get the relative position of a cell in CollectionView - xamarin.ios

I'm wondering how can I get the relative position of a cell in a collection view in regards to the app window? I saw some examples for swift and forms, but i can't find any for Xamarin.iOS

Translate the solution in this thread:
public class collectionViewDelegate : UICollectionViewDelegate {
UIView view;
public collectionViewDelegate(UIView v)
{
//get the parent v when create collectionViewDelegate instance
this.view = v;
}
public override void ItemSelected(UICollectionView collectionView, NSIndexPath indexPath)
{
UICollectionViewCell cell = (UICollectionViewCell)collectionView.DequeueReusableCell("CollectionViewCell",indexPath);
CGRect frame = new CGRect(0,0,cell.Frame.Size.Width,cell.Frame.Size.Height);
frame.Location = collectionView.ConvertPointToView(cell.Frame.Location, this.view);
}
}

Related

How to implement UICollectionView - XAMARIN.IOS

I'm trying to use UICollectionView but I can't find any samples that I can take advantage of. I needed the UICollectionView by code (without using swift/storyboard/forms). Could you give me a really simple example? For example 2 lines with 2 columns please? Basic stuff just to try to understand how I can implement it.
Thank you
You can refer to Collection Views in Xamarin.iOS doc to check how to use Collection View with Code .And here I will show a sample code to explain how to implement it .
Could you give me a really simple example? For example 2 lines with 2 columns please?
First , need to create a GridLayout :
public class GridLayout : UICollectionViewFlowLayout
{
public GridLayout ()
{
}
public override bool ShouldInvalidateLayoutForBoundsChange (CGRect newBounds)
{
return true;
}
public override UICollectionViewLayoutAttributes LayoutAttributesForItem (NSIndexPath path)
{
return base.LayoutAttributesForItem (path);
}
public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect (CGRect rect)
{
return base.LayoutAttributesForElementsInRect (rect);
}
}
Then you can init the Collection View in ViewDidLoad :
static NSString animalCellId = new NSString("AnimalCell");
List<IAnimal> animals;
animals = new List<IAnimal>();
for (int i = 0; i < 2; i++)
{
animals.Add(new Monkey());
}
// Perform any additional setup after loading the view, typically from a nib.
UICollectionView collectionView = new UICollectionView(new CGRect(0, 0, UIScreen.MainScreen.Bounds.Size.Width, 300), new GridLayout());
collectionView.RegisterClassForCell(typeof(AnimalCell), animalCellId);
collectionView.BackgroundColor = UIColor.Blue;
collectionView.DataSource = new MyCollectionViewDataDelegate(animals);
View.AddSubview(collectionView);
Here you also need to creat a Custom Cell for your needs , this can be modified by yourself :
public class AnimalCell : UICollectionViewCell
{
UIImageView imageView;
[Export("initWithFrame:")]
public AnimalCell(CGRect frame) : base(frame)
{
BackgroundView = new UIView { BackgroundColor = UIColor.Orange };
SelectedBackgroundView = new UIView { BackgroundColor = UIColor.Green };
ContentView.Layer.BorderColor = UIColor.LightGray.CGColor;
ContentView.Layer.BorderWidth = 2.0f;
ContentView.BackgroundColor = UIColor.White;
ContentView.Transform = CGAffineTransform.MakeScale(0.8f, 0.8f);
imageView = new UIImageView(UIImage.FromBundle("placeholder.png"));
imageView.Center = ContentView.Center;
imageView.Transform = CGAffineTransform.MakeScale(0.7f, 0.7f);
ContentView.AddSubview(imageView);
}
public UIImage Image
{
set
{
imageView.Image = value;
}
}
[Export("custom")]
void Custom()
{
// Put all your custom menu behavior code here
Console.WriteLine("custom in the cell");
}
public override bool CanPerform(Selector action, NSObject withSender)
{
if (action == new Selector("custom"))
return true;
else
return false;
}
}
The MyCollectionViewDataDelegate also need to be created:
public class MyCollectionViewDataDelegate : UICollectionViewDataSource
{
private List animals;
public MyCollectionViewDataDelegate(List<IAnimal> animals)
{
this.animals = animals;
}
public override nint NumberOfSections(UICollectionView collectionView)
{
return 2;
}
public override nint GetItemsCount(UICollectionView collectionView, nint section)
{
return animals.Count;
}
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
var animalCell = (AnimalCell)collectionView.DequeueReusableCell(animalCellId, indexPath);
var animal = animals[indexPath.Row];
animalCell.Image = animal.Image;
return animalCell;
}
}
You can find that animalCell should be registed when init Collection View .
Then effect :
This is the sample link for reference .

Update the text of label in UIViewController based on selected cell in UICollectionView Xamarin.iOS

This question is related to Xamarin.iOS. I have a UICollectionView and a Label inside a UIViewController. I have set up source for UICollectionView. In it I override the methods ItemSelected and ItemDeselected to highlight the selected items. I also get the index of the selected cell in the UICollectionView. But I don't know how pass this index to parent UIViewController so I can update the label based on the selected cell in UICollectionView.
public override void ItemSelected(UICollectionView collectionView, NSIndexPath indexPath)
{
var cell = (newCustomCollectionViewCell)collectionView.CellForItem(indexPath);
//cell.mainLabel.Alpha = 0.5f;
cell.ImageView.Alpha = 0.9f;
cell.ImageView.Layer.BorderWidth = 3.0f;
cell.ImageView.Layer.BorderColor = UIColor.Red.CGColor;
//base.ItemSelected(collectionView, indexPath);
_selectedItems.Add(indexPath);
ViewController.selectedIndex = indexPath.ToString();
ViewController.cusLabel.Text = indexPath.ToString();
//Console.WriteLine("Index of the highlighted cell is {0}", indexPath);
}
public override void ItemDeselected(UICollectionView collectionView, NSIndexPath indexPath)
{
var cell = (newCustomCollectionViewCell)collectionView.CellForItem(indexPath);
//cell.mainLabel.Alpha = 0.5f;
cell.ImageView.Alpha = 1f;
cell.ImageView.Layer.BorderWidth = 3.0f;
cell.ImageView.Layer.BorderColor = UIColor.White.CGColor;
//base.ItemDeselected(collectionView, indexPath);
_selectedItems.Remove(indexPath);
}
The above code is in newCustomCollectionSource.cs
I want to access the index of the cell in the parent view controller UIViewController
public override void ViewDidLoad()
{
base.ViewDidLoad();
cusLabel.Frame = new CGRect(50, 50, 100, 30);
cusLabel.BackgroundColor = UIColor.Gray;
CustomColllectionView.RegisterClassForCell(typeof(newCustomCollectionViewCell), newCustomCollectionViewCell.CellID);
CustomColllectionView.Source = new newCustomCollectionSource(imageLocations);
}
You can firstly declare a member variable in the your ViewController
public NSIndexPath selectedIndex ;
Then ,there two ways that you can pass this index to parent UIViewController .
Firstly ,you can implement the method of the UICollectionViewDataSource and UICollectionViewDelegate in the ViewController. And set the value of the member when you select the item .Refer to the following code:
public partial class ViewController : UIViewController,IUICollectionViewDataSource,IUICollectionViewDelegate
. . .
public override void ViewDidLoad()
{
base.ViewDidLoad();
cusLabel.Frame = new CGRect(50, 50, 100, 30);
cusLabel.BackgroundColor = UIColor.Gray;
CustomColllectionView.RegisterClassForCell(typeof(newCustomCollectionViewCell), newCustomCollectionViewCell.CellID);
CustomColllectionView.WeakDataSource= this;
}
public override void ItemSelected(UICollectionView collectionView, NSIndexPath indexPath)
{
…
this. myIndexPath= NSIndexPath.FromRowSection(indexPath.Row, indexPath. Section);
}
If you do want to implement the method of the UICollectionViewDataSource and UICollectionViewDelegate in single class. Pass the your ViewController as a parameter when you init the source.
In your newCustomCollectionSource.cs
private xxxViewController(your ViewController’s name) viewController;
public newCustomCollectionSource( xxxViewController viewController,…(other parameters) )
{
. . .
this. viewController= viewController;
. . .
}
And set the value of the member when you select the item as same as above :
public override void ItemSelected(UICollectionView collectionView, NSIndexPath indexPath)
{
…
this.viewController.myIndexPath= NSIndexPath.FromRowSection(indexPath.Row, indexPath. Section);
}
In your ViewController:
CustomColllectionView.Source = new
newCustomCollectionSource(this,imageLocations);
You can get the index of the selected cell just like myIndexPath.Row, myIndexPath. Section in your ViewController.

MonoTouch NullReferenceException on tableview scroll

In my app i simply trying to add a checkmark to the selected row. I have around 20 items in my row and want to show a checkmark for the selected row. When i scroll to the bottom of the page and select a row it is throwing NullReferenceException. I have checkmark code reference from here
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.ObjCRuntime;
using System.Collections.Generic;
namespace SampleApp
{
public partial class FirstViewController : UITableViewController
{
DataSource dataSource;
public FirstViewController () : base ("FirstViewController", null)
{
Title = NSBundle.MainBundle.LocalizedString ("First", "First");
TabBarItem.Image = UIImage.FromBundle ("first");
}
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Perform any additional setup after loading the view, typically from a nib.
// Add Table
TableView.Source = dataSource = new DataSource (this);
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
// Return true for supported orientations
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
}
class DataSource : UITableViewSource
{
static readonly NSString CellIdentifier = new NSString ("DataSourceCell");
FirstViewController controller;
private List<String> _listData = new List<String> ();
private NSIndexPath _previousRow;
public DataSource (FirstViewController controller)
{
this.controller = controller;
// POPULATE DISPOSITION LIST
PopulateDatabase();
_previousRow = NSIndexPath.FromRowSection(Settings.SelectedIndex,0);
}
void PopulateDatabase()
{
_listData.Add("val1");
_listData.Add("val2");
_listData.Add("val3");
_listData.Add("val4");
_listData.Add("val5");
_listData.Add("val6");
_listData.Add("val7");
_listData.Add("val8");
_listData.Add("val9");
_listData.Add("val10");
_listData.Add("val11");
_listData.Add("val12");
_listData.Add("val13");
_listData.Add("val14");
_listData.Add("val15");
}
// Customize the number of sections in the table view.
public override int NumberOfSections (UITableView tableView)
{
return 1;
}
public override int RowsInSection (UITableView tableview, int section)
{
return _listData.Count;
}
// Customize the appearance of table view cells.
public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell (CellIdentifier);
if (cell == null) {
cell = new UITableViewCell (UITableViewCellStyle.Default, CellIdentifier);
//cell.Accessory = UITableViewCellAccessory.DisclosureIndicator;
}
cell.TextLabel.Text = _listData[indexPath.Row];
cell.TextLabel.Font = UIFont.SystemFontOfSize(18);
return cell;
}
// Row Select
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
// Uncheck the previous row
if (_previousRow != null)
tableView.CellAt(_previousRow).Accessory = UITableViewCellAccessory.None;
// Do something with the row
var row = indexPath.Row;
Settings.SelectedIndex = row;
tableView.CellAt(indexPath).Accessory = UITableViewCellAccessory.Checkmark;
//Console.WriteLine("{0} selected",_controller.Items[row]);
_previousRow = indexPath;
// This is what the Settings does under Settings>Mail>Show on an iPhone
tableView.DeselectRow(indexPath,false);
}
// Set row height
public override float GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
return 50f;
}
}
public class Settings
{
public static int SelectedIndex = 0;
}
}
}
I get the exception at line
tableView.CellAt(_previousRow).Accessory =UITableViewCellAccessory.None;
When i debug i found that Accessory
tableView.CellAt(_previousRow).Accessory Unknown member: Accessory
Any idea what is going wrong???
Got the anser
// Row Select
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
// Uncheck the previous row
if (_previousRow != null)
{
NSIndexPath [] temp = tableView.IndexPathsForVisibleRows;
if (temp.Contains(preIndex))
{
tableView.CellAt(_previousRow).Accessory = UITableViewCellAccessory.None;
}
}
// Do something with the row
var row = indexPath.Row;
Settings.SelectedIndex = row;
tableView.CellAt(indexPath).Accessory = UITableViewCellAccessory.Checkmark;
//Console.WriteLine("{0} selected",_controller.Items[row]);
_previousRow = indexPath;
// This is what the Settings does under Settings>Mail>Show on an iPhone
tableView.DeselectRow(indexPath,false);
}

UITableView navigation in monotouch

I'm using mono develop 3.1.1 to build an IOS application. I'm receiving an object reference error (see >>>) from my reference to the navigation controller that I've not declared properly.
My question is what's the best way to declare and instantiate the controller so I'm able to show another view from the point the table cell is selected.
Can someone help me with the correct syntax please?
public class TableHelper : UITableViewSource {
protected string[] tableItems;
protected string cellIdentifier = "TableCell";
public TableHelper (string[] items)
{
tableItems = items;
}
public override int RowsInSection (UITableView tableview, int section)
{
return tableItems.Length;
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
switch (tableItems[indexPath.Row])
{
case "one":
var DetailViewController = new SupportContactsDetailsScreen ();
UINavigationController controller = new UINavigationController();
// Pass the selected object to the new view controller.
>>>controller.NavigationController.PushViewController(DetailViewController, true);
break;
default:
//Console.WriteLine("Default case");
break;
}
}
public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell (cellIdentifier);
if (cell == null)
cell = new UITableViewCell (UITableViewCellStyle.Default, cellIdentifier);
cell.TextLabel.Text = tableItems[indexPath.Row];
return cell;
}
}
The way that I usually go about doing this is to keep a reference to the main UIViewController (the view controller that holds the UITableView) for that particular set of views and access that Navigation Controller through the NavigationController property. (Another technique taken by Xamarin in the code sample linked below is to pass the UINavigationController in directly.)
So I would alter your class by adding:
UIViewController parentViewController;
public TableHelper(string[] items, UIViewController vc)
{
tableItems = items;
parentViewController vc;
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
switch (tableItems[indexPath.Row])
{
case "one":
var DetailViewController = new SupportContactsDetailsScreen ();
UINavigationController controller = new UINavigationController();
// Pass the selected object to the new view controller.
parentViewController.NavigationController.PushViewController(DetailViewController, true);
break;
default:
//Console.WriteLine("Default case");
break;
}
}
Xamarin has a document on their docs site as well as some code on their Github that talks about this further. Another important note is what the type of view controller is (regular UIViewController, UITableViewController, etc.).

Display UIWebView in custom MonoTouch.Dialog Element

Working on a way to display HTML and RTF content in a custom Element in MonoTouch.Dialog. To get started, I created a new class based on the UIViewElement implementation, with the intention of displaying a UIWebView in a cell (see UIViewElement code here).
The custom element works, but the contents of the UIWebView is never displayed. Once the text of the UIWebView is loaded, I try to resize it using UIWebView.SizeThatFits. This function always return 0s, even though the width given to it (from the actual UITableViewCell it is displayed in) is non-zero.
Is it sufficient to add the UIWebView to the UITableViewCell using this code:
cell.ContentView.AddSubview (webView);
The UIWebView never returns a non-zero height, so the actual cell is never displayed. Even if I override the height calculation and return a static height (such as 100f), the UIWebView is still not displayed.
The element's complete code:
public class RBHTMLRow : Element, IElementSizing
{
public enum CellFlags {Transparent = 1,DisableSelection = 2}
public CellFlags Flags;
private UIWebView webView = null;
private UITableViewCell current_cell;
NSString key;
private void ResizeWebView ()
{
if (current_cell != null)
{
RectangleF frame = webView.Frame;
SizeF fittingSize = webView.SizeThatFits(new SizeF(current_cell.Frame.Width, 1f));
frame.Size = fittingSize;
webView.Frame = frame;
}
}
private void InitWebView(bool isRTF, string content )
{
webView = new UIWebView();
webView.LoadHtmlString ( content, new NSUrl(""));
webView.LoadFinished += delegate {
ResizeWebView();
} ;
}
public RBHTMLRow (bool isRTF, String content, String caption) : base (caption)
{
key = new NSString("rbhtml_row");
InitWebView(isRTF, content);
}
protected override NSString CellKey {
get {
return key;
}
}
public override UITableViewCell GetCell (UITableView tv)
{
var cell = tv.DequeueReusableCell (CellKey);
if (cell == null){
cell = new UITableViewCell (UITableViewCellStyle.Default, CellKey);
if ((Flags & CellFlags.Transparent) != 0){
cell.BackgroundColor = UIColor.Clear;
cell.BackgroundView = new UIView (RectangleF.Empty) {
BackgroundColor = UIColor.Clear
} ;
}
cell.SelectionStyle = UITableViewCellSelectionStyle.None;
cell.ContentView.AddSubview (webView);
}
current_cell = cell;
ResizeWebView();
return cell;
}
public float GetHeight (UITableView tableView, NSIndexPath indexPath){
return webView.Bounds.Height;
}

Resources