Why are my UIScrollView's bounds changed when rotating the device? - uikit

I'm adding my view controller's view to the main window. My view controller's view is a UIScrollView.
The view's bounds are set to 500x500 and the view really is shown with the correct size.
However, if I rotate the device, the scroll view gets maximized and eats up all available scpace.
I do not have an auto resizing mask anywhere, nor do I change the scroll view's bounds.
What is changing the frame/bounds of my scroll view?
this.oPdfController = new PdfViewController(NSUrl.FromFilename("./pdffeatures.pdf"), 2);
this.oPdfController.View.Frame = new RectangleF(new PointF(40, 40), new SizeF(500, 500));
this.oPdfController.View.AutoresizingMask = UIViewAutoresizing.None;
window.AddSubview (this.oPdfController.View);
Here's the source of the controller:
using System;
using MonoTouch.UIKit;
using MonoTouch.CoreAnimation;
using MonoTouch.CoreGraphics;
using MonoTouch.Foundation;
using System.Drawing;
namespace PdfViewerTest
{
public class PdfViewController : UIViewController
{
public PdfViewController (IntPtr handle) : base( handle )
{
}
public PdfViewController (NSUrl oUrl, int iPage) : base( )
{
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
public override void LoadView ()
{
base.LoadView ();
UIScrollView oScrollView = new UIScrollView (new RectangleF (new PointF (0, 0), new SizeF(1, 1)));
oScrollView.Delegate = new ScrollViewDelegate (this);
oScrollView.MinimumZoomScale = 1.0f;
oScrollView.MaximumZoomScale = 4.0f;
oScrollView.BackgroundColor = UIColor.ScrollViewTexturedBackgroundColor;
this.View = oScrollView;
}
/// <summary>
/// Gets the scroll view.
/// </summary>
private UIScrollView ScrollView
{
get
{
return this.View as UIScrollView;
}
}
/// <summary>
/// Delegate for the scroll view.
/// </summary>
public class ScrollViewDelegate : UIScrollViewDelegate
{
public ScrollViewDelegate (PdfViewController oParentController) : base( )
{
this.oParentController = oParentController;
}
private PdfViewController oParentController;
public override UIView ViewForZoomingInScrollView (UIScrollView scrollView)
{
// Not implemented here.
return null;
}
}
}
}

I think this strange behaviour is due to oScrollView becoming a direct subview of the window.
I just tested your code and couldn't find a solution to keep the good size with this view structure, but a simple workaround is to add oScrollView as a subview of PdfViewController.View (just tested (on simulator), size stays the same even when rotating).
This way, your first code block should become :
this.oPdfController = new PdfViewController(NSUrl.FromFilename("pdffeatures.pdf"), 2);
window.AddSubview (this.oPdfController.View);
and your controller :
using System;
using MonoTouch.UIKit;
using MonoTouch.CoreAnimation;
using MonoTouch.CoreGraphics;
using MonoTouch.Foundation;
using System.Drawing;
namespace PdfViewerTest
{
public class PdfViewController : UIViewController
{
UIScrollView oScrollView = null;
public PdfViewController (IntPtr handle) : base( handle )
{
}
public PdfViewController (NSUrl oUrl, int iPage) : base( )
{
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
public override void LoadView ()
{
base.LoadView ();
oScrollView = new UIScrollView (new RectangleF (new PointF (0, 0), new SizeF(1, 1)));
oScrollView.Delegate = new ScrollViewDelegate (this);
oScrollView.MinimumZoomScale = 1.0f;
oScrollView.MaximumZoomScale = 4.0f;
oScrollView.BackgroundColor = UIColor.ScrollViewTexturedBackgroundColor;
oScrollView.Frame = new RectangleF(new PointF(40, 40), new SizeF(500, 500));
oScrollView.AutoresizingMask = UIViewAutoresizing.None;
this.View.AddSubView(oScrollView);
}
/// <summary>
/// Gets the scroll view.
/// </summary>
private UIScrollView ScrollView
{
get
{
return oScrollView;
}
}
/// <summary>
/// Delegate for the scroll view.
/// </summary>
public class ScrollViewDelegate : UIScrollViewDelegate
{
public ScrollViewDelegate (PdfViewController oParentController) : base( )
{
this.oParentController = oParentController;
}
private PdfViewController oParentController;
public override UIView ViewForZoomingInScrollView (UIScrollView scrollView)
{
// Not implemented here.
return null;
}
}
}
}
HTH

Related

How can I create a custom TableView that will allow me to specify footer height and text and space out the text just like in the iOS settings page?

I saw this example:
Xamarin Forms - How to create custom render to give TableSection the default iOS Footer?
It does 75% of what I am looking for with this code:
using CoreGraphics;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(TableView), typeof(Japanese.iOS.TableViewCustomRenderer))]
namespace Japanese.iOS
{
public class TableViewCustomRenderer : TableViewRenderer
{
UITableView tableView;
protected override void OnElementChanged(ElementChangedEventArgs<TableView> e)
{
base.OnElementChanged(e);
if (Control == null)
return;
var tableView = Control as UITableView;
var formsTableView = Element as TableView;
tableView.WeakDelegate = new CustomFooterTableViewModelRenderer(formsTableView);
}
void Current_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
}
private class CustomFooterTableViewModelRenderer : TableViewModelRenderer
{
public CustomFooterTableViewModelRenderer(TableView model) : base(model)
{
}
public override nfloat GetHeightForFooter(UITableView tableView, nint section)
{
return 10;
}
public override string TitleForFooter(UITableView tableView, nint section)
{
return "This is the title for this given section";
}
}
}
}
1. However what I would like is to be able to extend TableView so that I am able to put in the XAML some way to set or leave unset the footer text and height. Something like:
<ExtTableView FooterText="abc" FooterHeight="50". ..
2. From experiments with the code above I tried hardcoding in some text and realize that there is no spacing set. So I would also like to find out if there is a way to set the spacing and font so it appears just like in the iOS settings pages?
Could someone suggest how I could go about creating what I am looking for which is I guess something like an ExtTableView class that can accept additional arguments.
As hankide said , I just provide more details.
However what I would like is to be able to extend TableView so that I am able to put in the XAML some way to set or leave unset the footer text and height.
Create MyTableView that inherits from TableView
public class MyTableView : TableView
{
public static readonly BindableProperty FooterHeightProperty =
BindableProperty.Create("FooterHeight", typeof(string), typeof(MyTableView), "");
public string FooterHeight
{
get { return (string)GetValue(FooterHeightProperty); }
set { SetValue(FooterHeightProperty, value); }
}
public static readonly BindableProperty FooterTextProperty =
BindableProperty.Create("FooterText", typeof(string), typeof(MyTableView), "");
public string FooterText
{
get { return (string)GetValue(FooterTextProperty); }
set { SetValue(FooterTextProperty, value); }
}
}
Get the value that you set in XMAL and assign them to CustomFooterTableViewModelRenderer
protected override void OnElementChanged(ElementChangedEventArgs<TableView> e)
{
base.OnElementChanged(e);
if (Control == null)
return;
var tableView = Control as UITableView;
var formsTableView = Element as MyTableView;
CustomFooterTableViewModelRenderer render = new CustomFooterTableViewModelRenderer(formsTableView);
render.height = float.Parse(formsTableView.FooterHeight);
render.text = formsTableView.FooterText;
tableView.WeakDelegate = render;
}
private class CustomFooterTableViewModelRenderer : TableViewModelRenderer
{
public float height { get; set; }
public String text { get; set; }
public CustomFooterTableViewModelRenderer(TableView model) : base(model)
{
}
public override UIView GetViewForFooter(UITableView tableView, nint section)
{
UIView view = new UIView(new CGRect(0, 0, tableView.Frame.Width, 50));
view.BackgroundColor = UIColor.Gray;
UILabel label = new UILabel();
label.Frame = new CGRect(0, 0, tableView.Frame.Width, height);
label.BackgroundColor = UIColor.Red;
label.Text = text;
label.Font = UIFont.SystemFontOfSize(15);
view.Add(label);
return view;
}
public override nfloat GetHeightForFooter(UITableView tableView, nint section)
{
return 50;
}
}
Usage:
<local:MyTableView FooterHeight="20" FooterText="ABC">
<TableRoot>
<TableSection>
<TextCell Text="22222" ></TextCell>
</TableSection>
</TableRoot>
</local:MyTableView>
From experiments with the code above I tried hardcoding in some text and realize that there is no spacing set. So I would also like to find out if there is a way to set the spacing and font so it appears just like in the iOS settings pages?
You could override the method GetViewForFooter to change the defalut style of footer,find it in the code above .
My test :
You had the right idea about creating the custom control. Here's what to do:
Create ExtTableView class that inherits from TableView
public class ExtTableView : TableView { }
Create BindableProperties for both FooterText and FooterHeight, as outlined here.
After that you can set the properties in XAML
<ExtTableView FooterText="abc" FooterHeight="50" ...
Within the renderer, you can get the values from Element (which points to our Xamarin.Forms ExtTableView).
// Modify the native control with these values
var text = Element.FooterText;
var height = Element.FooterHeight;

Centering a UIView within a UIScrollView Xamarin.iOS

I am currently trying to center a UIIView inside of a UIScrollView and am having some difficulty in doing so.
Here is the image of my current view:
Here is the code snippet I'm working with:
public void AddView(UIViewController viewCont)
{
this.AddChildViewController(viewCont);
this.mainScrollView.AddSubview(viewCont.View);
viewCont.DidMoveToParentViewController(this);
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
var m = new Menu();
//var c = new Camera();
AddView(m);
AddView(c);
CGRect cFrame = c.View.Frame;
cFrame.X = this.View.Frame.Width;
c.View.Frame = cFrame;
this.mainScrollView.ContentSize = new CGSize(this.View.Frame.Width * 2, 1.0);
}
I want to fill this whole view with Green but as you can see, the bottom quarter of the View does not stretch all the way to the bottom.
For the time being, I have removed all constraints because every attempt in adding them results in no successes. I was hoping to get a concrete answer here as to how I could go about centering this view within this UIScrollView.
Thanks
UPDATE: 3-21-2017
My main goal is to have 2 ViewControllers side by side within my UIScrollView that I can navigate to and from using a swipe gesture, like SnapChat. Following, #Digitalsa1nt suggestions, I unfortunately come up with the same issue.
Here are some more pictures:
This first one shows what happens when I only add the 1 view:
This next one shows what happens when I try to add both views to my UIScrollView, only the camera shows:
Finally, here is the code that I am using to back my Camera view:
using Foundation;
using UIKit;
using AVFoundation;
namespace BRB.iOS
{
public partial class Camera : UIViewController
{
AVCaptureSession captureSession;
AVCaptureStillImageOutput stillImageOutput;
AVCaptureVideoPreviewLayer previewLayer;
public Camera() : base("Camera", null)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
previewLayer.Frame = cameraView.Bounds;
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
captureSession = new AVCaptureSession();
captureSession.SessionPreset = AVCaptureSession.Preset1920x1080;
var backCamera = AVCaptureDevice.GetDefaultDevice(AVMediaType.Video);
NSError error;
var input = AVCaptureDeviceInput.FromDevice(backCamera, out error);
if (error == null && captureSession.CanAddInput(input))
{
captureSession.AddInput(input);
stillImageOutput = new AVCaptureStillImageOutput();
stillImageOutput.OutputSettings = new NSDictionary(AVVideo.CodecKey, AVVideo.CodecJPEG);
if (captureSession.CanAddOutput(stillImageOutput))
{
captureSession.AddOutput(stillImageOutput);
previewLayer = new AVCaptureVideoPreviewLayer(captureSession);
previewLayer.VideoGravity = AVLayerVideoGravity.ResizeAspect;
previewLayer.Connection.VideoOrientation = AVCaptureVideoOrientation.Portrait;
cameraView.Layer.AddSublayer(previewLayer);
captureSession.StartRunning();
}
}
}
}
}
I usually override 'didlayoutsubviews' for making changes to the views within my UIScrollViews. The below worked for me.
public void AddView(UIViewController viewCont)
{
AddChildViewController(viewCont);
mainScrollView.AddSubview(viewCont.View);
viewCont.DidMoveToParentViewController(this);
}
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
// Ensure our contentinsets are 0 so we don't have any blank space
mainScrollView.ContentInset = new UIEdgeInsets(0, 0, 0, 0);
// set the contentsize to the bounds of the container view within.
mainScrollView.ContentSize = View.Bounds.Size;
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
var m = new Menu();
//var c = new Camera();
AddView(m);
AddView(c);
}

Monotouch UITableviewCells never destroyed

I have a controller which has a UITableView named WaitTableView. It has only one cell, here is the code of the UITableViewCell class :
public class TableViewWaitCell : UITableViewCell
{
public UIActivityIndicatorView activityIndicator = new UIActivityIndicatorView(UIActivityIndicatorViewStyle.Gray);
public UILabel lblLoading = new UILabel();
public TableViewWaitCell(UITableViewCellStyle style, string reuseIdentifier) : base (style, reuseIdentifier)
{
this.SelectionStyle = UITableViewCellSelectionStyle.None;
}
~TableViewWaitCell(){
System.Console.WriteLine("TableViewWaitCell.~TableViewWaitCell");
lblLoading = null;
activityIndicator = null;
System.GC.Collect();
}
protected override void Dispose (bool disposing){
System.Console.WriteLine("TableViewWaitCell.Dispose");
lblLoading = null;
activityIndicator = null;
base.Dispose (disposing);
GC.Collect();
}
public override void Draw (System.Drawing.RectangleF rect)
{
base.Draw (rect);
var context = UIGraphics.GetCurrentContext();
var gradient = new CGGradient(
CGColorSpace.CreateDeviceRGB(),
new float[] { 1f, 1f, 1f, 1f,
0.68f, 0.68f, 0.72f, 1f },
new float[] { 0f, 1f } );
context.DrawLinearGradient(gradient,
new PointF(rect.X+rect.Width/2, rect.Y),
new PointF(rect.X+rect.Width/2, rect.Y+rect.Height),
CGGradientDrawingOptions.DrawsAfterEndLocation);
var activityIndicatorViewFrame = new RectangleF(rect.X + rect.Width/2-10, rect.Y+10, 20, 20);
this.activityIndicator .Frame = activityIndicatorViewFrame;
this.activityIndicator.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
this.activityIndicator.StartAnimating();
this.AddSubview(this.activityIndicator);
var labelFrame = new RectangleF(rect.X, rect.Y+10+activityIndicatorViewFrame.Height, rect.Width, 35);
this.lblLoading.Frame = labelFrame;
this.lblLoading.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
this.lblLoading.TextColor = UIColor.Black;
this.lblLoading.BackgroundColor = UIColor.Clear;
this.lblLoading.TextAlignment = UITextAlignment.Center;
this.lblLoading.Text = Dictionary.GetValue("Loading");
this.AddSubview(this.lblLoading);
}
}
here is the ViewWillDisappear method of the main UIViewController :
public override void ViewWillDisappear (bool animated)
{
Console.WriteLine("SpotlightView.ViewWillDisappear");
if(this.PopoverController!=null)
this.PopoverController.Dismiss(true);
this.PopoverController = null;
this.tableView.RemoveFromSuperview();
this.WaitTableView.RemoveFromSuperview();
this.searchBar.RemoveFromSuperview();
this.tableView.Source = null;
this.tableView.Dispose();
this.tableView = null;
this.WaitTableView.Source = null;
this.WaitTableView.Dispose();
this.WaitTableView = null;
this.searchBar.Delegate = null;
this.searchBar.Dispose();
this.searchBar = null;
base.ViewWillDisappear (animated);
}
My problem is that neither the destructor nor the Dispose of my cells got called. When I run heapshot the number of instances of the TableViewWaitCell class grow up has I navigate through my app. I don't understand how the cells life-cycle is managed in Monotouch, what could have I done wrong ?
I do not see anything that would cause this problem in the code you shared. However you do not show how the cell is constructed and stored. Your objects may be kept alive by a root you are not showing in your sample code. I have created a sample below that shows Dispose and the finalizer being called.
Using the simulator the table view and the cell are collected quickly. Usually after a press the of the 'Show Table' button the second time.
Running on the device shows a different behavior. The table and cell are not collected right away. The simplest explanation is that the GC is 'tuned' to only run when it needs to. So if your app is not using much memory, all the objects will continue to live.
There are two things you can do to force the GC to run as shown in the sample.
showTable.TouchUpInside += delegate {
navController.PushViewController (new MyViewController (), true);
// Not a great idea to call Collect but you could to force it.
// GC.Collect ();
};
allocate.TouchUpInside += delegate {
// Trigger the GC by creating a bunch of objects
System.Collections.Generic.List<object> list = new System.Collections.Generic.List <object> ();
for (int i=0; i<2048; i++)
{
list.Add (new object ());
}
};
First you can call GC.Collect. However I do not recommend that. The GC will run best when you let it run when it wants to. (In most cases.) When is it acceptable to call GC.Collect?
Second just keep writing code and let the GC decide what is best. In the sample I added another button that allocates a bunch of objects and adds them to a list. So if you toggle between the table view and the main view a few times then press the allocate button a couple of times you should see the finalizers run.
using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.CoreGraphics;
using System.Drawing;
namespace delete20130320
{
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
UIWindow window;
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
window = new UIWindow (UIScreen.MainScreen.Bounds);
var mainView = new UIViewController ();
var showTable = UIButton.FromType (UIButtonType.RoundedRect);
showTable.Frame = new System.Drawing.RectangleF (10, 10, 150, 35);
showTable.SetTitle ("Show Table", UIControlState.Normal);
var allocate = UIButton.FromType (UIButtonType.RoundedRect);
allocate.Frame = new System.Drawing.RectangleF (10, 55, 150, 35);
allocate.SetTitle ("Allocate", UIControlState.Normal);
mainView.View.BackgroundColor = UIColor.White;
mainView.View.Add (showTable);
mainView.View.Add (allocate);
var navController = new UINavigationController (mainView);
showTable.TouchUpInside += delegate {
navController.PushViewController (new MyViewController (), true);
// Not a great idea to call Collect but you could to force it.
// GC.Collect ();
};
allocate.TouchUpInside += delegate {
// Trigger the GC by creating a bunch of objects
System.Collections.Generic.List<object> list = new System.Collections.Generic.List <object> ();
for (int i=0; i<2048; i++)
{
list.Add (new object ());
}
};
window.RootViewController = navController;
window.MakeKeyAndVisible ();
return true;
}
}
public class MyViewController : UIViewController
{
UITableView _tableView;
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
_tableView = new UITableView (this.View.Bounds);
View.Add (_tableView);
_tableView.DataSource = new MyDataSource ();
}
~MyViewController ()
{
// Bad practice to call other managed objects in finalizer
// But for sample purposes it will be ok
Console.WriteLine ("~MyViewController");
}
protected override void Dispose (bool disposing)
{
// Bad practice to call other managed objects in Dispose
// But for sample purposes it will be ok
Console.WriteLine ("MyViewController.Dispose");
base.Dispose (disposing);
}
class MyDataSource : UITableViewDataSource
{
public override int RowsInSection (UITableView tableView, int section)
{
return 1;
}
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell ("SomeUniqueString");
if (cell != null)
return cell;
return new TableViewWaitCell (UITableViewCellStyle.Default, "SomeUniqueString");
}
}
}
public class TableViewWaitCell : UITableViewCell
{
public TableViewWaitCell(UITableViewCellStyle style, string reuseIdentifier) : base (style, reuseIdentifier)
{
this.SelectionStyle = UITableViewCellSelectionStyle.None;
this.TextLabel.Text = "Something";
}
~TableViewWaitCell()
{
// Bad practice to call other managed objects in finalizer
// But for sample purposes it will be ok
System.Console.WriteLine("TableViewWaitCell.~TableViewWaitCell");
// Avoid forcing the GC
//System.GC.Collect();
}
protected override void Dispose (bool disposing)
{
// Bad practice to call other managed objects in Dispose
// But for sample purposes it will be ok
System.Console.WriteLine("TableViewWaitCell.Dispose");
base.Dispose (disposing);
//GC.Collect();
}
}
}
The problem came from an EventHandler which referenced a method of my view controller thus prenventing the collection of my cells and my controller.

How can I add a Dialog View Controller as a Subview to a UIView or Vice Versa?

I have looked around the web for some time looking for any resources on this topic and have come up with nothing that solves my dilemma.
I have a dialog view controller and its root is simply displaying a list of strings similar to how the iphone music song scrollable view is laid out. What I need is a subview located at the top of the screen and the scrollable DVC below it. I need to the top view to be always in view while the user can scroll through the root element because the top view will be holding statistics.
I have tried adding a subview but it simply overlaps the dvc below it, and I have not been able to figure out a way to add a dvc as a subview to a UIView.
Any help would be much appreciated.
What is needed to achieve this is a single root view controller that hosts two subview controllers. One subview contains the statistics at the top of the window. The bottom subview contains a navigation controller that holds the dialog view.
using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.Dialog;
using System.Drawing;
namespace delete201205203
{
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
UIWindow window;
MyUIViewController _mvc;
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
window = new UIWindow (UIScreen.MainScreen.Bounds);
_mvc = new MyUIViewController ();
window.RootViewController = _mvc;
window.MakeKeyAndVisible ();
return true;
}
}
public class MyUIViewController : UIViewController
{
MyDialogViewController _dvc;
UINavigationController _nav;
StatisticsViewController _statistics;
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
var root = new RootElement ("Root") {
new Section ("Section") {
new EntryElement ("caption", "placeholder", ""),
new RootElement ("Root 2") {
new Section ("Section") {
new EntryElement ("caption", "placeholder", ""),
new StringElement ("Back", () => {
_nav.PopViewControllerAnimated (true);
})
}
}
}
};
_dvc = new MyDialogViewController (root);
_nav = new UINavigationController (_dvc);
_nav.SetNavigationBarHidden (true, false);
_nav.View.Frame = new RectangleF (0, 70f,
this.View.Bounds.Width,
this.View.Bounds.Height -70f);
_statistics = new StatisticsViewController ();
_statistics.View.Frame = new RectangleF (0, 0,
this.View.Bounds.Width,
70f);
this.AddChildViewController (_nav);
this.View.AddSubview (_nav.View);
this.AddChildViewController (_statistics);
this.View.AddSubview (_statistics.View);
}
public override void ViewWillLayoutSubviews ()
{
base.ViewWillLayoutSubviews ();
_nav.View.Frame = new RectangleF (0, 70f,
this.View.Bounds.Width,
this.View.Bounds.Height -70f);
_statistics.View.Frame = new RectangleF (0, 0,
this.View.Bounds.Width,
70f);
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
}
public class StatisticsViewController : UIViewController
{
UILabel _label;
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
this.View.BackgroundColor = UIColor.White;
_label = new UILabel (new RectangleF (this.View.Bounds.Width * .5f - 50f,
this.View.Bounds.Height * .5f -10f,
100f, 20f));
_label.AutoresizingMask = UIViewAutoresizing.FlexibleMargins;
_label.Text = "statistics";
this.View.AddSubview (_label);
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
}
// This overrde is needed to ensure the pop view animation
// works correctly in landscape mode
public class MyDialogViewController : DialogViewController
{
public MyDialogViewController (RootElement root) : base (root) {}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
}
}

Slowly initialized components that cause lack of user experience

This is the view that appears when I click a button on a previous view.
The text boxes, the smiling face image and the labels are predesigned created by xCode.
Please see the image and the code of the view to clear why all the view's components are initializing very slowly and getting ready to give the last shoot that is captured by me when it is finished to be totally loaded . Moreover, It is very slow when I type letters, the letters are appearing very slowly while I am typing with the keyboard that iOS provides on every touch on the text box.
The Code of The View;
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace IstanbulCity
{
public partial class AskForNAme : UIViewController
{
public delegate void AskForNAmeClosingDelegate (AskForNAme form);
public event AskForNAmeClosingDelegate AskForNAmeClosed;
NSObject obs1;
float scrollamount = 0.0f;
float bottomPoint = 0.0f;
float yOffset = 0.2f;
bool moveViewUp = false;
public AskForNAme () : base ("AskForNAme", null)
{
}
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.
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(true);
obs1 = NSNotificationCenter.DefaultCenter.AddObserver (
"UIKeyboardDidShowNotification", KeyboardUpNotification);
this.tbOwnerMailAdress.ShouldReturn += TextFieldShouldReturn;
this.tbOwnerBirthDay.ShouldReturn += TextFieldShouldReturn;
this.uivGuguPhoto.Image = UIImage.FromFile ("image/fcuk.jpeg");
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(false);
obs1 = NSNotificationCenter.DefaultCenter.AddObserver (
"UIKeyboardDidShowNotification", KeyboardUpNotification);
this.tbOwnerMailAdress.ShouldReturn += TextFieldShouldReturn;
this.tbOwnerBirthDay.ShouldReturn += TextFieldShouldReturn;
this.uivGuguPhoto.Image = UIImage.FromFile ("image/fcuk.jpeg");
}
public override void ViewDidUnload ()
{
base.ViewDidUnload ();
// Clear any references to subviews of the main view in order to
// allow the Garbage Collector to collect them sooner.
//
// e.g. myOutlet.Dispose (); myOutlet = null;
ReleaseDesignerOutlets ();
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
// Return true for supported orientations
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
}
void HandleIstanbulCityViewControllerClosed (babyAge form)
{
form.DismissModalViewControllerAnimated (true);
form = null;
}
partial void tbKadikoyHallEditDidEndOnExit (MonoTouch.Foundation.NSObject sender)
{
tbIstanbulName.ResignFirstResponder ();
}
private bool TextFieldShouldReturn (UITextField tf)
{
tf.ResignFirstResponder ();
if (moveViewUp) {
ScrollTheView (false);
}
return true;
}
private void KeyboardUpNotification (NSNotification notification)
{
ResetTheView ();
RectangleF r = UIKeyboard.BoundsFromNotification (notification);
if (this.tbOwnerMailAdress.IsEditing ) {
//Calculate the bottom of the Texbox
//plus a small margin...
bottomPoint = (this.tbOwnerMailAdress.Frame.Y + this.tbOwnerMailAdress.Frame.Height + yOffset);
//Calculate the amount to scroll the view
//upwards so the Textbox becomes visible...
//This is the height of the Keyboard -
//(the height of the display - the bottom
//of the Texbox)...
scrollamount = (r.Height - (View.Frame.Size.Height - bottomPoint));
}
else if (this.tbOwnerBirthDay.IsEditing)
{
bottomPoint = (this.tbOwnerBirthDay.Frame.Y + this.tbOwnerBirthDay.Frame.Height + yOffset);
scrollamount = (r.Height - (View.Frame.Size.Height - bottomPoint));
}
else
{
scrollamount = 0;
}
//Check to see whether the view
//should be moved up...
if (scrollamount > 0) {
moveViewUp = true;
ScrollTheView (moveViewUp);
} else
moveViewUp = false;
}
private void ResetTheView ()
{
UIView.BeginAnimations (string.Empty, System.IntPtr.Zero);
UIView.SetAnimationDuration (0.3);
RectangleF frame = View.Frame;
frame.Y = 0;
View.Frame = frame;
UIView.CommitAnimations ();
}
private void ScrollTheView (bool movedUp)
{
//To invoke a views built-in animation behaviour,
//you create an animation block and
//set the duration of the move...
//Set the display scroll animation and duration...
UIView.BeginAnimations (string.Empty, System.IntPtr.Zero);
UIView.SetAnimationDuration (0.3);
//Get Display size...
RectangleF frame = View.Frame;
if (movedUp) {
//If the view should be moved up,
//subtract the keyboard height from the display...
frame.Y -= scrollamount;
} else {
//If the view shouldn't be moved up, restore it
//by adding the keyboard height back to the original...
frame.Y += scrollamount;
}
//Assign the new frame to the view...
View.Frame = frame;
//Tell the view that your all done with setting
//the animation parameters, and it should
//start the animation...
UIView.CommitAnimations ();
}
}
}
The Recent Version - Still The Same User Experience' slow!
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace IstanbulCity
{
public partial class AskForNAme : UIViewController
{
public delegate void AskForNAmeClosingDelegate (AskForNAme form);
public event AskForNAmeClosingDelegate AskForNAmeClosed;
public AskForNAme () : base ("AskForNAme", null)
{
}
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.
}
public override void ViewDidUnload ()
{
base.ViewDidUnload ();
// Clear any references to subviews of the main view in order to
// allow the Garbage Collector to collect them sooner.
//
// e.g. myOutlet.Dispose (); myOutlet = null;
ReleaseDesignerOutlets ();
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
// Return true for supported orientations
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
}
void HandleIstanbulCityViewControllerClosed (babyAge form)
{
form.DismissModalViewControllerAnimated (true);
form = null;
}
}
}
This does not look to be initialization related. You are adding notifications from both ViewDidAppear and ViewWillAppear. You're also always calling ResetTheView, which does animations, on every keyboard notification (even if nothing else changed).
My guess is that you are calling ResetTheView way more often that you realize - and the continuous animations are killing the performance of your application.
You can confirm this by putting a Console.WriteLine, and maybe a counter, in the ResetTheView method.

Resources