Monotouch UITableviewCells never destroyed - memory-management

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.

Related

Pop the UIViewController in xamarin ios

I want to open a UIViewController from a content page and this code helps me in doing this
UIWindow Window = new UIWindow(UIScreen.MainScreen.Bounds);
var cvc = new ScanningPage();
var navController = new UINavigationController(cvc);
Window.RootViewController = navController;
Window.MakeKeyAndVisible();
but I also want a Back button on that Controller Page which navigate me back to that content Page.
this.NavigationController.PopViewController(true);
or
this.DismissViewController(true,null);
not working in this case.
I would recommend not creating a new Window and a UINavigationController...
Xamarin.Forms is contained in a single VC in the first Window, so you can obtain that view controller via:
UIApplication.SharedApplication.Windows[0].RootViewController;
So as an example Dependency service that presents and dismisses a VC (either from Forms or the view controller), you can do something like this.
Dependency interface:
public interface IDynamicVC
{
void Show();
void Dismiss();
}
iOS Dependency implementation
public class DynamicVC : IDynamicVC
{
UIViewController vc;
public void Show()
{
if (vc != null) throw new Exception("DynamicVC already showing");
vc = new UIViewController();
var button = new UIButton(new CGRect(100, 100, 200, 200));
button.SetTitle("Back", UIControlState.Normal);
button.BackgroundColor = UIColor.Red;
button.TouchUpInside += (object sender, EventArgs e) =>
{
Dismiss();
};
vc.Add(button);
var rootVC = UIApplication.SharedApplication.Windows[0].RootViewController;
rootVC.PresentViewController(vc, true, () => { });
}
public void Dismiss()
{
vc?.DismissViewController(true, () =>
{
vc.Dispose();
vc = null;
});
}
}

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

Set ItemSize of UICollectionViewFlowLayout to width of device

Using Xamarin, I am trying to create a UICollectionViewFlowLayout where my cells will be the width of the device and flow down vertically. Something like the Facebook news tab iOS app.
Currently to get the Cells in the layout, here is by code:
public override async void ViewWillAppear (bool animated)
{
try{
base.ViewWillAppear (animated);
var layout = new UICollectionViewFlowLayout ();
layout.MinimumInteritemSpacing = 30;
var collectionView = new NewsListView (UIScreen.MainScreen.ApplicationFrame, layout);
collectionView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
collectionView.BackgroundColor = UIColor.LightGray;
collectionView.RegisterClassForCell (typeof(NewsListViewCell), cellId);
collectionView.ReloadData ();
CollectionView = collectionView;
Logger.Log(""+CollectionView.Bounds.Width);
}catch(Exception ex){
Logger.Log (ex);
ShowUserMessage ("Error",ex.Message);
}
}
I want to use this to set the size of the item:
layout.ItemSize = new CGSize (CollectionView.Bounds.Width-20, 200.0f);
But CollectionView does not exist yet when i am creating the UICollectionViewFlowLayout,
Is there any other way i can set the size of UICollectionViewFlowLayout to the width of the device?
I found a solution to my problem. I created the layout as a global variable and then added it to the view in ViewDidLoad (), then in ViewWillAppear(..) i can set layout.ItemSize
So my code will as follows:
UICollectionViewFlowLayout layout;
public override async void ViewDidLoad ()
{
try{
base.ViewDidLoad ();
Title = "News";
layout = new UICollectionViewFlowLayout ();
layout.MinimumInteritemSpacing = 30;
var collectionView = new NewsListView (UIScreen.MainScreen.ApplicationFrame, layout);
collectionView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
collectionView.BackgroundColor = UIColor.LightGray;
collectionView.RegisterClassForCell (typeof(NewsListViewCell), cellId);
collectionView.ReloadData ();
CollectionView = collectionView;
}catch(Exception ex){
Logger.Log (ex);
ShowUserMessage ("Error",ex.Message);
}
}
public override async void ViewWillAppear (bool animated)
{
try{
base.ViewWillAppear (animated);
Logger.Log(""+CollectionView.Bounds.Width);
layout.ItemSize = new CGSize (CollectionView.Bounds.Width-20, 200.0f);
}catch(Exception ex){
Logger.Log (ex);
ShowUserMessage ("Error",ex.Message);
}
}
This way the item width of the layout is always based on device width and not hardcoded

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