Gif of the Problem
public override async void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
tableView.DeselectRow(indexPath,true);
var myCell = _cellDataDict[_cellSectionList[indexPath.Section]][indexPath.Row];
myCell.IsSelected = !myCell.IsSelected;
if( _previousCell != null && _previousCell != myCell)
_previousCell.IsSelected = false;
tableView.BeginUpdates();
tableView.EndUpdates();
tableView.ScrollToRow(indexPath, UITableViewScrollPosition.Top, true);
}
public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
var myCell = _cellDataDict[_cellSectionList[indexPath.Section]][indexPath.Row];
if(myCell.IsSelected)
return 293.0f;
else
return 68.0f;
}
public override nfloat GetHeightForHeader(UITableView tableView, nint section)
{
return 44.0f;
}
public override nfloat EstimatedHeightForHeader(UITableView tableView, nint section)
{
return 44.0f;
}
public override nfloat EstimatedHeight(UITableView tableView, NSIndexPath indexPath)
{
var myCell = _cellDataDict[_cellSectionList[indexPath.Section]][indexPath.Row];
if(myCell.IsSelected)
return 293.0f;
else
return 68.0f;
}
Basically I want to achieve expanding my table view cell then scrolling to the top of the tableview after it is expanded. But the animation right now looks weird and I want to smooth it out. It looks like the bottom section header slides up even though there is a copy already there.
Related
I need the UIMenuItem to call a method inside the UITableViewCell. Something similar is possible in swift as explained here: https://stackoverflow.com/a/31358474/202179 .
At the moment I am only able to call the method inside the UIViewController from the UIMenuItem if I add an Export attribute to the method.
There is some trick in the export of this method in the cell, but I have failed to find it till now. I would expect this code to work, but it doesn't:
[Register("CustomCell")]
public class CustomCell : UITableViewCell
{
public CustomCell(IntPtr intPtr) : base(intPtr)
{
var menuItem = new UIMenuItem("Menu Item", new ObjCRuntime.Selector("CustomCell.SeekSelectedText"));
UIMenuController.SharedMenuController.MenuItems = new UIMenuItem[] { menuItem };
UIMenuController.SharedMenuController.Update();
}
[Export("SeekSelectedText")]
void SeekSelectedText()
{
//do something
}
}
As said just quoting a different selector inside the UIViewController works, so the problem is that this selector doesn't appear to be recognized whatever I try.
Here is my test and the custom UIMenuItem works fine.
First, define a custom cell class which inherits UITableViewCell
class MyCell: UITableViewCell
{
public MyCell(UITableViewCellStyle style, string reuseIdentifier):base(style, reuseIdentifier)
{
}
[Export("custom")]
void Custom()
{
//do something
Console.WriteLine("custom pop up");
}
public override bool CanPerform(Selector action, NSObject withSender)
{
if (action == new Selector("custom"))
return true;
else
return false;
}
}
Second, set the source of your UITableView
class MyTableViewSource : UITableViewSource
{
int i = 0;
// create custom cell
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
string cellStr = "cell";
MyCell cell = (MyCell)tableView.DequeueReusableCell(cellStr);
if (cell == null)
{
cell = new MyCell(UITableViewCellStyle.Subtitle, cellStr);
cell.TextLabel.Text = $"User Name {i}";
cell.DetailTextLabel.Text = $"details here... {i++}";
}
return cell;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return 10;
}
}
Then override the realted methods(e.g., ShouldShowMenu, CanPerformAction).
class MyTableViewDelegate : UITableViewDelegate
{
public override bool ShouldShowMenu(UITableView tableView, NSIndexPath rowAtindexPath)
{
return true;
}
public override bool CanPerformAction(UITableView tableView, Selector action, NSIndexPath indexPath, NSObject sender)
{
return true;
}
public override void PerformAction(UITableView tableView, Selector action, NSIndexPath indexPath, NSObject sender)
{
}
public override bool ShouldHighlightRow(UITableView tableView, NSIndexPath rowIndexPath)
{
return true;
}
}
Last, don't foget to add custom MenuItem to your UITableViewCell.
UIMenuController.SharedMenuController.MenuItems = new UIMenuItem[] {
new UIMenuItem ("Custom", new Selector ("custom"))
};
Since UICollectionView has similar functions to UITableVIew, you can directly refer to the sample SimpleCollectionView.
We've created a TableViewController so that a user can enable/disable different notification types. After the initial load, everything is fine until the user scrolls to the bottom then back to the top and the first 1-2 table view cells aren't displaying correctly.
Example:
https://imgur.com/7n2VpTo
Typically deleting and recreating the view controller and xib/cs files fixes this, but was wondering if any one knows the cause of this.
Controller Code:
public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
return 305;
}
public override nint NumberOfSections(UITableView tableView)
{
return 1;
}
public override nint RowsInSection(UITableView tableView, nint section)
{
return _numRows;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell(Setting.Key) as Setting;
if (cell == null)
{
var values = _settings.Where(s => s.Index == indexPath.Row).FirstOrDefault();
cell = new Setting(values);
var views = NSBundle.MainBundle.LoadNib(Setting.Key, cell, null);
cell = Runtime.GetNSObject(views.ValueAt(0)) as Setting;
}
cell.SelectionStyle = UITableViewCellSelectionStyle.None;
cell?.PopulateData(_settings.Where(s => s.Index == indexPath.Row).FirstOrDefault(), this);
return cell;
}
public override void ViewWillLayoutSubviews()
{
base.ViewWillLayoutSubviews();
}
Cell Code:
public partial class Setting : UITableViewCell
{
public static readonly NSString Key = new NSString("Setting");
public static readonly UINib Nib;
public SettingModel Values { get; set; }
static Setting()
{
Nib = UINib.FromName("Setting", NSBundle.MainBundle);
}
protected Setting(IntPtr handle) : base(handle) { }
public Setting() : base() {
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
}
public void PopulateData(SettingModel values)
{
//logic...
}
}
Upgrading to Visual Studio for Mac 8.6.5 resolved the issue.
In Xamarin iOS - I have a class named TableCell ( public class TableCell : UITableViewCell { } ) - in this class I have declared buttons.
In button click event , i'm trying to access [indexPath.Row] in UITableViewCell. I can select a row to find [indexPath.Row] in UITableViewSource.
public class TableSource : UITableViewSource {
// - - - -
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
new UIAlertView("Row Selected", tableItems[indexPath.Row], null, "OK", null).Show();
tableView.DeselectRow (indexPath, true); // iOS convention is to remove the highlight
}
// - - - -
}
How can I get [indexPath.Row] in UITableViewCell, Using button click event ..?
It's not the best approach but it will definitely work:
I would extend TableCell class with a new property:
public NSIndexPath IndexPath { get; set; }
Then I would add this line to the UITableViewSource's GetCell method if you are using the cell reusing pattern:
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
TableCell cell = tableView.DequeueReusableCell("YourIdentifier") ?? new TableCell();
cell.IndexPath = indexPath;
return cell;
}
And after that you could access the cell's current IndexPath anywhere. i.e.:
public TableCell()
{
UIButton btn = new UIButton(UIButtonType.RoundRect);
btn.TouchUpInside += (sender, args)
{
new UIAlertView("Button pressed!", indexPath.Row, null, "OK", null).Show();
}
}
Use VisibleCells property.
As soon as user selected row, the UITableViewCell will be visible.
Alternative solution (if you want to get similar, but not the same cell):
You can get it via UITableViewCell.GetCell using passed UITableView tableView, then cast it into your type of UITableViewCell, then call it's method using passed NSIndexPath indexPath.
Something like this:
public class TableSource : UITableViewSource {
// - - - -
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.GetCell(tableView, indexPath);
var myCell class = cell as MyCellClass;
if (myCell != null) {
// TODO: do something with cell.
}
}
// - - - -
}
// - - - -
}
Ive added a print statement in my row selected method and it is never being called:
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
Console.WriteLine ("Row selected");
}
My cells have a UIImageView that covers the whole cell acting as a background image. Could this be causing the row to not recognize the touch?
Had to call:
MyTableView.AllowsSelection = true;
It must have been set to false by default.
Adding latest: Visual Studio/Xamarin iOS/C#
1) Add IUITableViewDelegate to the ViewController.cs
2) On ViewDidLoad:
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.yourTableview.Delegate = this;
this.yourTableview.AllowsSelection = true;
}
3) Implement IUITableViewDelegate the method.
[Export("tableView:didSelectRowAtIndexPath:")]
public virtual void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
Console.WriteLine("Row Selected");
}
Please note that RowSelected will not be called if [Export("tableView:didSelectRowAtIndexPath:")] is not added.
I'm trying to apply an event to a cell in order to specify the TouchesBegan method.
cell.TouchesBegan += OnTouchesBegan;
But TouchesBegan is a method group and not an event.
How do I add custom behavior to a Cells TouchesBegan() method in monotouch?
[Register("MenuView")]
public class MenuView : ViewControllerBase
{
private new MenuViewModel ViewModel { get { return (MenuViewModel)base.ViewModel; } }
public override void ViewDidLoad()
{
base.ViewDidLoad();
// this ensures the sliding panel doesn't fill the entire view.
var frame = View.Frame;
frame.Width = 300;
View.Frame = frame;
var chapters = ViewModel.Chapters;
//var listHeight = (chapters.Count*40);
var navigationList = new UITableView(new RectangleF(0, 50, 300, 300))
{
Source = new NavigationTableSource(chapters)
};
Add(navigationList);
}
}
public class NavigationTableSource : UITableViewSource
{
private readonly IList<ChapterViewModel> _chapters;
private const string CellIdentifier = "NavigationCell";
public NavigationTableSource(IList<ChapterViewModel> chapters)
{
_chapters = chapters;
}
public override int RowsInSection(UITableView tableview, int section)
{
return _chapters.Count;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell(CellIdentifier) ??
new UITableViewCell(UITableViewCellStyle.Default, CellIdentifier);
// if there are no cells to reuse, create a new one
cell.TextLabel.Text = _chapters[indexPath.Row].Title;
cell.TouchesBegan += OnTouchesBegan;
return cell;
}
}
TouchesBegan is a method that you can override by subclassing UITableViewCell:
public class CustomCell : UITableViewCell
{
public CustomCell(UITableViewCellStyle style, NSString reuseIdentifier) : base(style, reuseIdentifier)
{
}
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
// do something
base.TouchesBegan(touches, evt);
}
}
Then use your subclass when creating a cell:
var cell = tableView.DequeueReusableCell(CellIdentifier) ??
new CustomCell(UITableViewCellStyle.Default, CellIdentifier);
So the way I was able to manage this was to SubClass my UITableViewSource. In there I overrode RowSelected(UITableView tableView, NSIndexPath indexPath)
public class NavigationTableSource : UITableViewSource
{
private readonly IList<ChapterViewModel> _chapters;
private const string CellIdentifier = "NavigationCell";
public NavigationTableSource(IList<ChapterViewModel> chapters)
{
_chapters = chapters;
}
public override int RowsInSection(UITableView tableview, int section)
{
return _chapters.Count;
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
// todo: This is where we're going to load up the appropriate chapter.
new UIAlertView("Row Selected", _chapters[indexPath.Row].Title, null, "OK", null).Show();
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell(CellIdentifier) ??
new UITableViewCell(UITableViewCellStyle.Default, CellIdentifier);
// if there are no cells to reuse, create a new one
cell.TextLabel.Text = _chapters[indexPath.Row].Title;
return cell;
}
}