I have created a View in Xamarin with a backing class and was wondering if I can create an instance of that class with a CGRect size. I have the following code right now:
using System;
using CoreGraphics;
using Foundation;
using UIKit;
namespace SimpleScroll.iOS
{
public partial class ViewController : UIViewController
{
public ViewController(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
// UIScrollView with same width and height as ViewController
var mainScrollView = new UIScrollView(new CGRect(0, 0, this.View.Frame.Size.Width, this.View.Frame.Size.Height));
// Enable pagination and set other attributes
mainScrollView.PagingEnabled = true;
mainScrollView.ShowsVerticalScrollIndicator = false;
mainScrollView.ShowsHorizontalScrollIndicator = false;
mainScrollView.Bounces = false;
int numberOfViews = 2;
for (int i = 0; i < numberOfViews; i++)
{
nfloat xOrigin = i * this.View.Frame.Size.Width;
var subView = new UIView(new CGRect(xOrigin, 0, this.View.Frame.Size.Width, this.View.Frame.Size.Height));
subView.BackgroundColor = UIColor.FromRGBA(0.5f / i, 0.5f, 0.5f, 1);
mainScrollView.AddSubview(subView);
}
mainScrollView.ContentSize = new CGSize(this.View.Frame.Size.Width * numberOfViews, this.View.Frame.Size.Height);
this.View.AddSubview(mainScrollView);
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
}
}
Instead of var subView = new UIView(new CGRect(xOrigin, 0, this.View.Frame.Size.Width, this.View.Frame.Size.Height));, would I be able to do the same thing with my own Menu class that I have created? How could I give Menu its own constructor so that I can do something along the lines of, var subView = new Menu(new CGRect(...));?
Just subclass uiview and override the frame constuctor
[Foundation.Register("Menu")]
public class Menu : UIView
{
public Menu(CGRect frame) : base(frame)
{
}
}
Related
In my Xamarin.Forms application I need to add a bottom bar that will be visible over the tab bar. Since my app is a Shell application, I'm trying to create a custom ShellItemRenderer.
I extended the TabBar so I that could add custom view:
<local:CustomTabBar IsBottomBarVisible="False">
<local:CustomTabBar.BottomLayout>
<StackLayout>
<Label Text="Bottom bar" />
</StackLayout>
</local:CustomTabBar.BottomLayout>
<ShellContent Title="About" Icon="icon_about.png" Route="AboutPage" ContentTemplate="{views:AppDataTemplate views:AboutPage}" />
<ShellContent Title="Browse" Icon="icon_feed.png" ContentTemplate="{views:AppDataTemplate views:ItemsPage}" />
</local:CustomTabBar>
It worked on the Android platform after extending ShellItemRenderer and implementing custom Layout, but I hit the wall on the iOS. If I have any scrollable content (ScrollView or CollectionView), my bottom bar covers some of the items:
bottom bar visible, without bottom bar.
Is there a way to implement a custom layout, like on the Android platform, or to adjust existing content each time after the bottom bar appears or disappears?
Here is the implementation of CustomShellItemRenderer:
public class CustomShellItemRenderer : ShellItemRenderer
{
#region Fields
private UIView BottomBar;
#endregion Fields
#region Constructors
public CustomShellItemRenderer(IShellContext context) : base(context)
{
}
#endregion Constructors
protected CustomTabBar CustomTabBar => ShellItem as CustomTabBar;
#region Methods
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
var view = ConvertFormsToNative(CustomTabBar.BottomLayout, BottomBar.Frame);
BottomBar.AddSubview(view);
BottomBar.BackgroundColor = UIColor.Gray;
if (!CustomTabBar.IsBottomBarVisible)
{
BottomBar.Hidden = true;
}
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
TabBar.Translucent = false;
BottomBar = new UIView();
InitView();
}
private UIView ConvertFormsToNative(Xamarin.Forms.View view, CGRect size)
{
var renderer = Platform.CreateRenderer(view);
renderer.NativeView.AutoresizingMask = UIViewAutoresizing.All;
renderer.NativeView.ContentMode = UIViewContentMode.ScaleToFill;
renderer.Element.Layout(size.ToRectangle());
var nativeView = renderer.NativeView;
nativeView.SetNeedsLayout();
return nativeView;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == nameof(CustomTabBar.IsBottomBarVisible))
{
if (CustomTabBar != null)
{
if (CustomTabBar.IsBottomBarVisible)
{
BottomBar.Hidden = false;
}
else
{
BottomBar.Hidden = true;
}
}
}
}
private void InitView()
{
var window = (UIApplication.SharedApplication.Delegate as AppDelegate)?.Window;
var root = window.RootViewController;
const int height = 60;
var realTabBarHeight = TabBar.Frame.Size.Height + (UIApplication.SharedApplication.KeyWindow?.SafeAreaInsets.Bottom ?? 34);
var frame = new CGRect(TabBar.Frame.X, window.Frame.GetMaxY() - (realTabBarHeight + height), TabBar.Frame.Width, height);
BottomBar.Frame = frame;
var windowHeight = window.Frame.GetMaxY();
window.AddSubview(BottomBar);
}
#endregion Methods
}
We can adjust the height of the content dynamically while the bottom bar appears/disappears.
Sample code
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == nameof(CustomTabBar.IsBottomBarVisible))
{
if (CustomTabBar != null)
{
var window = (UIApplication.SharedApplication.Delegate as AppDelegate)?.Window;
var root = window.RootViewController;
var view = root.View;
var viewframe = view.Frame;
if (CustomTabBar.IsBottomBarVisible)
{
BottomBar.Hidden = false;
viewframe.Height = viewframe.Height - bottomBarHeight;
}
else
{
BottomBar.Hidden = true;
viewframe.Height = viewframe.Height + bottomBarHeight;
}
view.Frame = viewframe;
}
}
}
I'm trying to decide view heights based on a model property, but as UICollectionView is scrolled up and down, incorrect heights are assigned to visible cells. It seems that setting a HeightAnchor in GetCell (i.e. cellForItemAtIndexPath) does not work. How can I make this work?
using CoreGraphics;
using Foundation;
using System;
using System.Collections.Generic;
using UIKit;
namespace App2
{
public partial class ViewController : UIViewController
{
private UICollectionView _collectionView;
public ViewController (IntPtr handle) : base (handle)
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
InitializeCollectionView();
}
private void InitializeCollectionView()
{
_collectionView = new UICollectionView(View.Frame, new UICollectionViewCompositionalLayout(GetSection()))
{
DataSource = new CustomUICollectionViewDataSource(),
TranslatesAutoresizingMaskIntoConstraints = false
};
_collectionView.RegisterClassForCell(typeof(CustomUICollectionViewCell), "CustomUICollectionViewCell");
View.AddSubview(_collectionView);
NSLayoutConstraint.ActivateConstraints(new[]
{
_collectionView.TopAnchor.ConstraintEqualTo(View.SafeAreaLayoutGuide.TopAnchor),
_collectionView.BottomAnchor.ConstraintEqualTo(View.SafeAreaLayoutGuide.BottomAnchor),
_collectionView.LeftAnchor.ConstraintEqualTo(View.SafeAreaLayoutGuide.LeftAnchor),
_collectionView.RightAnchor.ConstraintEqualTo(View.SafeAreaLayoutGuide.RightAnchor)
});
}
private static NSCollectionLayoutSection GetSection()
{
var size = NSCollectionLayoutSize.Create(NSCollectionLayoutDimension.CreateFractionalWidth(1), NSCollectionLayoutDimension.CreateEstimated(50));
var item = NSCollectionLayoutItem.Create(size);
var group = NSCollectionLayoutGroup.CreateHorizontal(layoutSize: size, subitem: item, count: 1);
var section = NSCollectionLayoutSection.Create(group);
section.InterGroupSpacing = 5;
return section;
}
}
public class CustomUICollectionViewDataSource : UICollectionViewDataSource
{
private readonly List<Model> _models = new List<Model>
{
new Model {Height = 250},
new Model {Height = 100},
new Model {Height = 300},
new Model {Height = 400},
new Model {Height = 500},
new Model {Height = 50},
new Model {Height = 230},
new Model {Height = 100},
new Model {Height = 600},
new Model {Height = 310},
new Model {Height = 150},
new Model {Height = 220}
};
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
var model = _models[(int)indexPath.Item];
var cell = collectionView.DequeueReusableCell("CustomUICollectionViewCell", indexPath) as CustomUICollectionViewCell;
cell.UpdateHeight(model.Height);
return cell;
}
public override nint GetItemsCount(UICollectionView collectionView, nint section)
{
return _models.Count;
}
}
public sealed class CustomUICollectionViewCell : UICollectionViewCell
{
private readonly UIView _uiView;
[Export("initWithFrame:")]
public CustomUICollectionViewCell(CGRect frame) : base(frame)
{
_uiView = new UIView
{
BackgroundColor = UIColor.Brown,
TranslatesAutoresizingMaskIntoConstraints = false
};
ContentView.AddSubview(_uiView);
NSLayoutConstraint.ActivateConstraints(new[]
{
_uiView.TopAnchor.ConstraintEqualTo(ContentView.SafeAreaLayoutGuide.TopAnchor),
_uiView.BottomAnchor.ConstraintEqualTo(ContentView.SafeAreaLayoutGuide.BottomAnchor),
_uiView.LeftAnchor.ConstraintEqualTo(ContentView.SafeAreaLayoutGuide.LeftAnchor),
_uiView.RightAnchor.ConstraintEqualTo(ContentView.SafeAreaLayoutGuide.RightAnchor)
});
}
public void UpdateHeight(int height)
{
_uiView.HeightAnchor.ConstraintEqualTo(height).Active = true;
}
}
public class Model
{
public int Height { get; set; }
}
}
If you do this, the print message should prompt you to repeat the constraint.
You set the constraints of left, right, bottom, top, and added a height constraint when updating. The first four constraints have already determined the final height, the new height here will not work, and a warning message will be printed.
If you really want to update the height, you should set the left, right, top, height constraints from the beginning, and save the height constraint, which is used when updating.
var heightConstraint: NSLayoutConstraint?
heightConstraint = _uiView.heightAnchor.constraint(equalToConstant: 50)//Defaults
NSLayoutConstraint.activate([
(_uiView.topAnchor.constraint(equalTo:ContentView.SafeAreaLayoutGuide.topAnchor))!,
(_uiView.leftAnchor.constraint(equalTo:ContentView.SafeAreaLayoutGuide.leftAnchor))!
(_uiView.rightAnchor.constraint(equalTo:ContentView.SafeAreaLayoutGuide.rightAnchor))!,
(heightConstraint)!
]);
public void UpdateHeight(int height){
heightConstraint?.isActive = false
heightConstraint = _uiView.heightAnchor.constraint(equalToConstant: height)
heightConstraint?.isActive = true
}
Here's the fix for this as recommended by Xamarin support:
NSLayoutConstraint heightConstraint;
public void UpdateHeight(int height)
{
if (heightConstraint == null)
{
heightConstraint = _uiView.HeightAnchor.ConstraintEqualTo(height);
heightConstraint.Active = true;
}
else
{
heightConstraint.Constant = height;
}
}
I'm trying to add gradient for TableViewCell. I'm updating the gradient layer in LayoutSubview(). When I debug it looks like it sets correct value for layer frame. But the gradient is not "redrawn" or something as on each rotation the gradient is displayed with size for previous orientation. What I'm doing wrong?
public override void AwakeFromNib()
{
base.AwakeFromNib();
_gradient = new CAGradientLayer();
_gradient.Frame = ContentView.Bounds;
_gradient.BackgroundColor = UIColor.Red.CGColor;
_gradient.StartPoint = new CGPoint(0, 0);
_gradient.EndPoint = new CGPoint(1, 1);
_gradient.Colors = new[] { _topColor, _bottomColor };
this.ContentView.Layer.InsertSublayer(_gradient, 0);
}
public override void LayoutSubviews()
{
_gradient.Frame = ContentView.Bounds;
base.LayoutSubviews();
}
I moved layer update from LayoutSubview to Draw as suggested by #dip
public override void Draw(CGRect rect)
{
_gradient.Frame = ContentView.Bounds;
base.Draw(rect);
}
The layout is working now.
I have a method to move a CollectionView if two text fields inside it are obscured by the frame of the iPad keyboard:
private void OnKeyboardNotification(NSNotification notification)
{
var activeTextField = FindFirstResponder(CollectionView);
NSDictionary userInfo = notification.UserInfo;
CGSize keyboardSize = ((NSValue)userInfo[UIKeyboard.FrameBeginUserInfoKey]).RectangleFValue.Size;
var contentInset = new UIEdgeInsets(0, 0, keyboardSize.Height, 0);
CollectionView.ContentInset = contentInset;
CollectionView.ScrollIndicatorInsets = contentInset;
CGRect oldRect = CollectionView.Frame;
CGRect aRect = new CGRect(oldRect.X, oldRect.Y, oldRect.Width,
oldRect.Height -= keyboardSize.Height);
if (!aRect.Contains(activeTextField.Frame.Location))
{
CGPoint scrollPoint = new CGPoint(0, activeTextField.Frame.Location.Y - (keyboardSize.Height - 15));
CollectionView.SetContentOffset(scrollPoint, true);
}
}
I don't believe the code is working as intended. It's complicated by the fact that I have a custom layout defined in a subclass of UICollectionViewFlowLayout. The layout allows me to have cells scrolling vertically which snap into focus.
Every time I call OnKeyboardNotification, override UICollectionViewLayoutAttributes[] is called afterwards in the custom layout. I thought this might be cancelling out the effect of the method, but if that's the case, then how can I change when UICollectionViewLayoutAttributes[] is called?
public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect(CGRect rect)
{
var array = base.LayoutAttributesForElementsInRect(rect);
var visibleRect = new CGRect(CollectionView.ContentOffset, CollectionView.Bounds.Size);
foreach (var attributes in array)
{
if (attributes.Frame.IntersectsWith(rect))
{
float distance = (float)(visibleRect.GetMidX() - attributes.Center.X);
float normalizedDistance = distance / ACTIVE_DISTANCE;
if (Math.Abs(distance) < ACTIVE_DISTANCE)
{
float zoom = 1 + ZOOM_FACTOR * (1 - Math.Abs(normalizedDistance));
attributes.Transform3D = CATransform3D.MakeScale(zoom, zoom, 1.0f);
attributes.ZIndex = 1;
}
}
}
return array;
}
Edit:
Here is an example of the problem.
I have two fields
and here, when 'edit mode' is entered, the keyboard hides the age field.
Seems like you use the sample from Xamarin Samples.
UICollectionViewLayoutAttributes will be invoked every time you change the size of your UICollectionView.
I suggest you changing the location of your view instead of changing size in your OnKeyboardNotification method:
CGRect oldRect = CollectionView.Frame;
CGRect aRect = new CGRect(oldRect.X, oldRect.Y - keyboardSize.Height, oldRect.Width,oldRect.Height);
Hope it can solve your problem, I'm midnight right now, if it can not work, leave some message, I will check latter when tomorrow morning.
Edit -----------------------------------------------------------------
I change some code in the Sample you using to make the effect.
At first, I choose the LineLayout in AppDelegate.cs, like this:
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
//Don't change anything
// simpleCollectionViewController = new SimpleCollectionViewController (flowLayout);
simpleCollectionViewController = new SimpleCollectionViewController (lineLayout);
// simpleCollectionViewController = new SimpleCollectionViewController (circleLayout);
simpleCollectionViewController.CollectionView.ContentInset = new UIEdgeInsets (50, 0, 0, 0);
window.RootViewController = simpleCollectionViewController;
window.MakeKeyAndVisible ();
return true;
}
And then, I add a static property to LineLayout.cs, like this:
public class LineLayout : UICollectionViewFlowLayout
{
private static bool flagForLayout = true;
public static bool FlagForLayout {
get {
return flagForLayout;
}
set {
flagForLayout = value;
}
}
public const float ITEM_SIZE = 200.0f;
public const int ACTIVE_DISTANCE = 200;
public const float ZOOM_FACTOR = 0.3f;
public LineLayout ()
{
//Don't change anything
}
public override bool ShouldInvalidateLayoutForBoundsChange (CGRect newBounds)
{
return flagForLayout;
}
public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect (CGRect rect)
{
//Don't change anything
}
public override CGPoint TargetContentOffset (CGPoint proposedContentOffset, CGPoint scrollingVelocity)
{
//Don't change anything
}
}
Then in the SimpleCollectionViewController.cs, I add a UITextField for every cell, like this:
public override UICollectionViewCell GetCell (UICollectionView collectionView, NSIndexPath indexPath)
{
var animalCell = (AnimalCell)collectionView.DequeueReusableCell (animalCellId, indexPath);
var animal = animals [indexPath.Row];
animalCell.Image = animal.Image;
animalCell.AddSubview (new UITextField (new CGRect (0, 0, 100, 30)){ BackgroundColor = UIColor.Red });
return animalCell;
}
And still in SimpleCollectionViewController.cs, I add some code in ViewDidload method and add two method to handle the keyboard display event, like this:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
CollectionView.RegisterClassForCell (typeof(AnimalCell), animalCellId);
CollectionView.RegisterClassForSupplementaryView (typeof(Header), UICollectionElementKindSection.Header, headerId);
UIMenuController.SharedMenuController.MenuItems = new UIMenuItem[] {
new UIMenuItem ("Custom", new Selector ("custom"))
};
this.View.AddGestureRecognizer(new UITapGestureRecognizer(()=>{
this.View.EndEditing(true);
}));
NSNotificationCenter.DefaultCenter.AddObserver(this,new ObjCRuntime.Selector("onKeyboardWillShowNotification:"),UIKeyboard.WillShowNotification,null);
NSNotificationCenter.DefaultCenter.AddObserver(this,new ObjCRuntime.Selector("onKeyboardWillHideNotification:"),UIKeyboard.WillHideNotification,null);
}
[Export("onKeyboardWillShowNotification:")]
private void OnKeyboardWillShowNotification(NSNotification notification)
{
LineLayout.FlagForLayout = false;
NSDictionary userInfo = notification.UserInfo;
CGSize keyboardSize = ((NSValue)userInfo[UIKeyboard.FrameBeginUserInfoKey]).RectangleFValue.Size;
CGRect oldRect = CollectionView.Frame;
CGRect aRect = new CGRect(oldRect.X, oldRect.Y - keyboardSize.Height, oldRect.Width,
oldRect.Height);
this.CollectionView.Frame = aRect;
}
[Export("onKeyboardWillHideNotification:")]
private void OnKeyboardWillHideNotification(NSNotification notification)
{
LineLayout.FlagForLayout = true;
this.CollectionView.Frame = UIScreen.MainScreen.Bounds;
}
Now LayoutAttributesForElementsInRect will be invoked when keyboard show, hope it can solve your problem.
I Have the following viewcontroller with a tableview and a custom cell:
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.Linq;
using System.Threading;
using System.Data;
using System.IO;
using Mono.Data.Sqlite;
using System.Collections.Generic;
using Zurfers.Mobile.Core;
using AlexTouch.MBProgressHUD;
using System.Collections;
namespace Zurfers.Mobile.iOS
{
public partial class iPhoneHotelSearchViewController : UIViewController
{
MBProgressHUD hud;
public string Destination {
get;
set;
}
public DateTime CheckInDate {
get;
set;
}
public DateTime CheckOutDate {
get;
set;
}
public int Rooms {
get;
set;
}
public iPhoneHotelSearchViewController (IntPtr handle) : base (handle)
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
hud = new MBProgressHUD(this.View);
hud.Mode = MBProgressHUDMode.Indeterminate;
hud.LabelText = "Loading...";
hud.DetailsLabelText = "Searching Hotel";
this.View.AddSubview(hud);
hud.Show(true);
}
public override void ViewDidAppear (bool animated) {
base.ViewDidAppear (animated);
SearchHotel ();
}
public void SearchHotel (){
Hotel hotel = new Hotel();
var distribution = new HotelDistribution[]{new HotelDistribution(){ Adults = 1, Children = 0, ChildrenAges = new int[0]} };
var items = hotel.SearchHotels(Convert.ToDateTime("2013-08-08"),Convert.ToDateTime("2013-09-09 "),"(MIA)", distribution,"","","",0);
List<DtoHotelinformation> data = new List<DtoHotelinformation>();
foreach (var item in items)
{
DtoHotelinformation DtoHotelinformation = new DtoHotelinformation();
DtoHotelinformation.code = item.Code.ToString();
DtoHotelinformation.price = item.Price.ToString();
DtoHotelinformation.title = item.Name.ToString().ToTitleCase();
DtoHotelinformation.subtitle = item.Address.ToString();
DtoHotelinformation.rating = item.Rating.ToString();
DtoHotelinformation.imageUlr = item.ImageUrl;
data.Add(DtoHotelinformation);
}
hud.Hide(true);
hud.RemoveFromSuperview();
HotelSearchTable.Source = new HotelTableSource(data.ToArray());
HotelSearchTable.ReloadData();
}
partial void GoBack (MonoTouch.Foundation.NSObject sender)
{
DismissViewController(true, null);
}
}
}
Now the table source
using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace Zurfers.Mobile.iOS
{
public class HotelTableSource : UITableViewSource
{
DtoHotelinformation[] tableItems;
NSString cellIdentifier = new NSString("TableCell");
public HotelTableSource (DtoHotelinformation[] items)
{
tableItems = items;
}
public override int RowsInSection (UITableView tableview, int section)
{
return tableItems.Length;
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
//WHAT TO DO HERE
tableView.DeselectRow (indexPath, true); // normal iOS behaviour is to remove the blue highlight
}
public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
CustomCell cell = tableView.DequeueReusableCell(cellIdentifier) as CustomCell;
if (cell == null)
cell = new CustomCell(cellIdentifier);
cell.UpdateCell(tableItems[indexPath.Row].title, tableItems[indexPath.Row].subtitle, tableItems[indexPath.Row].price,
tableItems[indexPath.Row].imageUlr, tableItems[indexPath.Row].rating );
return cell;
}
public override float GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
return 70;
}
}
}
Finally the customcell code:
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.Dialog.Utilities;
namespace Zurfers.Mobile.iOS
{
public class CustomCell : UITableViewCell, IImageUpdated
{
UILabel headingLabel, subheadingLabel, priceLabel;
UIImageView imageService;
UIImageView star, star2, star3, star4, star5;
public CustomCell (NSString cellId) : base (UITableViewCellStyle.Default, cellId)
{
imageService = new UIImageView();
star = new UIImageView();
star2 = new UIImageView();
star3 = new UIImageView();
star4 = new UIImageView();
star5 = new UIImageView();
headingLabel = new UILabel(){
Font = UIFont.FromName("Verdana-Bold", 14f),
BackgroundColor = UIColor.Clear,
TextColor = UIColor.FromRGB(241, 241, 211)
};
subheadingLabel = new UILabel(){
Font = UIFont.FromName("Verdana-Bold", 8f),
TextColor = UIColor.FromRGB(255, 255, 255),
BackgroundColor = UIColor.Clear
};
priceLabel = new UILabel(){
Font = UIFont.FromName("Verdana", 14f),
TextColor = UIColor.FromRGB(241, 241, 211),
BackgroundColor = UIColor.Clear
};
AddSubview(imageService);
AddSubview(headingLabel);
AddSubview(subheadingLabel);
AddSubview(priceLabel);
AddSubview(star);
AddSubview(star2);
AddSubview(star3);
AddSubview(star4);
AddSubview(star5);
}
public void UpdateCell (string title, string subtitle, string price, string imageUlr, string rating )
{
if (imageUlr != null) {
var u = new Uri(imageUlr);
ImageLoader MyLoader= new ImageLoader(50,50);
imageService.Image = MyLoader.RequestImage(u,this);
} else {
imageService.Image = UIImage.FromFile("generic_no_image_tiny.jpg");
}
headingLabel.Text = title;
subheadingLabel.Text = subtitle;
if (subtitle.Length > 40) {
subheadingLabel.LineBreakMode = UILineBreakMode.WordWrap;
subheadingLabel.Lines = 0;
}
switch (rating) {
case "T":
star.Image = UIImage.FromFile("ZurfersMovil-Stars.png");
star2.Image = UIImage.FromFile("ZurfersMovil-Stars.png");
break;
case "S":
star.Image = UIImage.FromFile("ZurfersMovil-Stars.png");
star2.Image = UIImage.FromFile("ZurfersMovil-Stars.png");
star3.Image = UIImage.FromFile("ZurfersMovil-Stars.png");
break;
case "F":
star.Image = UIImage.FromFile("ZurfersMovil-Stars.png");
star2.Image = UIImage.FromFile("ZurfersMovil-Stars.png");
star3.Image = UIImage.FromFile("ZurfersMovil-Stars.png");
star4.Image = UIImage.FromFile("ZurfersMovil-Stars.png");
break;
case "L":
star.Image = UIImage.FromFile("ZurfersMovil-Stars.png");
star2.Image = UIImage.FromFile("ZurfersMovil-Stars.png");
star3.Image = UIImage.FromFile("ZurfersMovil-Stars.png");
star4.Image = UIImage.FromFile("ZurfersMovil-Stars.png");
star5.Image = UIImage.FromFile("ZurfersMovil-Stars.png");
break;
}
priceLabel.Text = "USD " + price;
priceLabel.Font = UIFont.BoldSystemFontOfSize (16);
}
public void UpdatedImage (Uri uri)
{
imageService.Image = ImageLoader.DefaultRequestImage(uri, this);
}
public override void LayoutSubviews ()
{
base.LayoutSubviews ();
imageService.Frame = new RectangleF(10, 10, 50, 33);
headingLabel.Frame = new RectangleF(70, 4, 240, 25);
subheadingLabel.Frame = new RectangleF(70, 25, 240, 20);
priceLabel.Frame = new RectangleF(220, 45, 100, 20);
star.Frame = new RectangleF(70, 45, 15, 15);
star2.Frame = new RectangleF(85, 45, 15, 15);
star3.Frame = new RectangleF(100, 45, 15, 15);
star4.Frame = new RectangleF(115, 45, 15, 15);
star5.Frame = new RectangleF(130, 45, 15, 15);
}
}
}
I want to open another viewcontroller (iPhoneHotelDetailViewController) when the user touch a cell of the table view. But I don not have any idea of how to do this.
Could you help me please.
Thanks in advance for your help.
Generally, you want a NavigationController to be the "top" element in your app, wrapping all the other controllers.
In your AppDelegate, create a NavigationController, and make it the root of your application.
Then create an instance of your Search controller and push it onto the NavigationController.
Finally, add a NavigationController property to the constructor of your TableSource.
NavigationController nav;
public HotelTableSource (DtoHotelinformation[] items, NavigationController nav)
{
this.nav = nav;
tableItems = items;
}
When you create your TableSource, pass the NavigationController reference in. You can do this because all ViewControllers have a property that points to their NavigationController, if they are contained within one.
HotelSearchTable.Source = new HotelTableSource(data.ToArray(), this.NavigationController);
Finally, in your RowSelected, create an instance of the new ViewController you want to display:
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
//WHAT TO DO HERE
MyDetailController myDetail = new MyDetailController();
nav.PushViewController(myDetail, true);
tableView.DeselectRow (indexPath, true); // normal iOS behaviour is to remove the blue highlight
}
I think that link to UINavigationController (UI component) in UITableViewSource is a bit weird. I recommend to use event-based approach:
Declare event in UITableViewSource and call it on row selection:
public event Action<int> OnRowSelect;
...
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
tableView.DeselectRow (indexPath, true); // normal iOS behaviour is to remove the blue highlight
if (OnRowSelect != null) {
OnRowSelect(indexPath.Row);
}
}
Then, handle event on UIViewController - push new UIViewController:
var source = data.ToArray();
source.OnRowSelect += HandleOnRowSelect;
HotelSearchTable.Source = new HotelTableSource();
HotelSearchTable.ReloadData();
...
void HandleOnRowSelect(int index)
{
var data = items[index];
// Pass data to new view controller and push it
}
Tip to avoid memory leaks: don't forget to unsubscribe from OnRowSelect when you Pop this UIViewController or making new UITableViewSource instance. I.e:
Declare source in as class member;
Unsubscribe from it's event in, for example, ViewWillDisappear:
source.OnRowSelect -= HandleOnRowSelect;
If you are using StoryBord there is a very easy way to do this. You would then pass the data whit in the PrepareForSegue method like this.
public override void PrepareForSegue (UIStoryboardSegue segue, NSObject sender)
{
base.PrepareForSegue (segue, sender);
NSIndexPath indexPatch = tableView.IndexPathForSelectedRow;
if (segue.Identifier.Equals ("showHotelDetail")) {
var vc = segue.DestinationViewController as iPhoneHotelDetailViewController;
if (vc != null) {
//Pass some date to the iPhoneHotelDetailViewController if needed.
vc.hotelName = this.tableItems [indexPatch.Row].hotelName;
}
}
}
In your StoryBoard connect the customCell with the iPhoneHotelDetailViewController and call the segue "showHotelDetail" for example.