Hide status bar in iOS from PageRenderer - c#

Is it possible to hide a status bar in a PageRenderer?
I tried setting these in Info.plist
<key>UIStatusBarHidden</key>
<true/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
And then overriding PrefersStatusBarHidden in the PageRenderer as
public override bool PrefersStatusBarHidden()
{
return true;
}
If I set UIViewControllerBasedStatusBarAppearance in Info.plist to false, it is hidden on all pages.
How can I fix this?

You should use a custom UINavigationController instead of the system one, like this sample:
In AppDelegate.cs:
UINavigationController navController;
UIWindow window;
public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
navController = new UINavigationController (new TestViewCtonroller ());
// create a new window instance based on the screen size
window = new UIWindow (UIScreen.MainScreen.Bounds);
window.RootViewController = navController;
window.MakeKeyAndVisible ();
return true;
}
MyNavigationController.cs:
public class MyNavigationController : UINavigationController
{
public MyNavigationController (UIViewController rootController) : base(rootController)
{
}
public override UIViewController ChildViewControllerForStatusBarHidden ()
{
return TopViewController;
}
public override UIViewController ChildViewControllerForStatusBarStyle ()
{
return TopViewController;
}
}
TestViewCtonroller.cs:
public class TestViewCtonroller : UIViewController
{
public TestViewCtonroller ()
{
this.View.BackgroundColor = UIColor.Red;
}
public override UIStatusBarStyle PreferredStatusBarStyle ()
{
return UIStatusBarStyle.LightContent;
}
public override bool PrefersStatusBarHidden ()
{
return true;
}
}
Hope it can help you.

Related

InstantiateViewController calls ViewDidLoad

I have a classic master-detail logic and trying to create instance of detail UIViewController with InstantiateViewController inside a click event.
Here is my code,
MasterViewController.cs
detailButton += delegate {
UIStoryboard Storyboard = UIStoryboard.FromName ("Main", null);
Console.WriteLine("InstantiateViewController() started");
var profileController = Storyboard.InstantiateViewController("ProfileController") as ProfileController;
Console.WriteLine("InstantiateViewController() ended");
profileController.Id = 5;
};
ProfileViewController.cs
public partial class ProfileController : UIViewController
{
public int Id { get; set; }
public override void ViewDidLoad()
{
Console.WriteLine("ViewDidLoad() called");
}
}
When I click the button output is,
InstantiateViewController() started
ViewDidLoad() called
InstantiateViewController() ended
This means profileController.Id is set after ViewDidLoad() which means I can't load data by Id in ViewDidload event beacuse Id is null.
So my question is why ViewDidLoad() called by InstantiateViewController(), in which method should I load data by Id?
Thanks.
VoewDidLoad is called when the ViewController is loaded into memory.
So, the correct place to get the data is on ViewDidAppear.
ViewDidAppear notifies the ViewController that its view was added to a view hierarchy.
UPDATE:
Based on the new information provided in comments you could do something like this:
public partial class ProfileController : UIViewController
{
private int _id;
public void SetupProfile (int id)
{
// Save the Id if necessary.
_id = id;
// Add event with this id related.
}
public override void ViewDidLoad()
{
Console.WriteLine("ViewDidLoad() called");
}
}
In alternative if you still want to do the event setup in ViewDidAppear you could use this approach with the events:
yourClass.Event -= MyHandler;
yourClass.Event += MyHandler;
I would do this via a custom segue.
1) Create a custom segue that can be re-used throughout your app:
public class CustomSeque : UIStoryboardSegue // or UIStoryboardPopoverSegue depending upon UI design so you can "POP" controller
{
public CustomSeque(String identifier, UIViewController source, UIViewController destination) : base (identifier, source, destination) { }
public override void Perform()
{
if (Identifier == "StackOverflow")
{
// Are you using a NavigationController?
if (SourceViewController.NavigationController != null)
SourceViewController.NavigationController?.PushViewController(DestinationViewController, animated: true);
else
SourceViewController.ShowViewController(DestinationViewController, this);
} else
base.Perform();
}
}
2) Then you can:
UIStoryboard Storyboard = UIStoryboard.FromName("Main", null);
Console.WriteLine("InstantiateViewController() started");
var profileController = Storyboard.InstantiateViewController("ProfileController") as ProfileController;
var seque = new CustomSeque($"StackOverflow", this, profileController);
profileController.Id = 5;
profileController.PrepareForSegue(seque, this); // instead of *this*, you can pass any NSObject that contains data for your controller
seque.Perform();
Console.WriteLine("InstantiateViewController() ended");
If your ProfileController looks like this:
public partial class ProfileController : UIViewController
{
public ProfileController (IntPtr handle) : base (handle)
{
Id = -99;
}
public int Id { get; set; }
public override bool ShouldPerformSegue(string segueIdentifier, NSObject sender)
{
if (segueIdentifier == "StackOverflow")
return true;
return base.ShouldPerformSegue(segueIdentifier, sender);
}
[Export("prepareForSegue:sender:")]
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
{
base.PrepareForSegue(segue, sender);
Console.WriteLine("ProfileController.PrepareForSegue()");
Console.WriteLine($" - ID = {Id}");
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
Console.WriteLine("ProfileController.ViewDidLoad()");
Console.WriteLine($" - ID = {Id}");
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
Console.WriteLine("ProfileController.ViewWillAppear()");
Console.WriteLine($" - ID = {Id}");
}
}
Your sequenced output would be:
InstantiateViewController() started
ProfileController.PrepareForSegue()
- ID = 5
ProfileController.ViewDidLoad()
- ID = 5
InstantiateViewController() ended
ProfileController.ViewWillAppear()
- ID = 5

Creating an iOS Local Notification

When loading the sample code in Xamarin Studio, the app runs as expected.
Xamarin.com Local Notifications Sample Code
But when starting a new single view project, I tried using bits of the code that seemed necessary. The viewcontroller class is structured differently, than in the sample code, on a new project.
ViewController.cs
using System;
using UIKit;
using Foundation;
namespace TestProject1
{
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.
}
public override void DidReceiveMemoryWarning ()
{
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
partial void ButButton_TouchUpInside (UIButton sender)
{
var notification = new UILocalNotification();
notification.FireDate = NSDate.FromTimeIntervalSinceNow(5);
notification.AlertAction = "Test";
notification.AlertBody = "Test Text";
notification.ApplicationIconBadgeNumber = 1;
notification.SoundName = UILocalNotification.DefaultSoundName;
UIApplication.SharedApplication.ScheduleLocalNotification(notification);
//throw new NotImplementedException ();
}
}
}
AppDelegate.cs
using Foundation;
using UIKit;
namespace TestProject1
{
[Register ("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
private ViewController viewController;
private UIWindow window;
public override UIWindow Window {
get;
set;
}
public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
viewController = new ViewController();
window = new UIWindow (UIScreen.MainScreen.Bounds);
viewController = new ViewController ();
window.RootViewController = viewController;
window.MakeKeyAndVisible ();
//if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
var notificationSettings = UIUserNotificationSettings.GetSettingsForTypes (
UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound, null
);
application.RegisterUserNotificationSettings (notificationSettings);
//}
if (launchOptions != null)
{
// check for a local notification
if (launchOptions.ContainsKey(UIApplication.LaunchOptionsLocalNotificationKey))
{
var localNotification = launchOptions[UIApplication.LaunchOptionsLocalNotificationKey] as UILocalNotification;
if (localNotification != null)
{
UIAlertController okayAlertController = UIAlertController.Create (localNotification.AlertAction, localNotification.AlertBody, UIAlertControllerStyle.Alert);
okayAlertController.AddAction (UIAlertAction.Create ("OK", UIAlertActionStyle.Default, null));
viewController.PresentViewController (okayAlertController, true, null);
// reset our badge
UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;
}
}
}
return true;
}
public override void ReceivedLocalNotification(UIApplication application, UILocalNotification notification)
{
// show an alert
UIAlertController okayAlertController = UIAlertController.Create (notification.AlertAction, notification.AlertBody, UIAlertControllerStyle.Alert);
okayAlertController.AddAction (UIAlertAction.Create ("OK", UIAlertActionStyle.Default, null));
viewController.PresentViewController (okayAlertController, true, null);
// reset our badge
UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;
}
}
}
In the sample project, the only difference is ViewController is declared with no parameters: public ViewController { }. If I add that code, the app complies and runs. The notifications fires and shows the badge, but never shows appears within the app.
Instead of trying to rig the code on a new project, how do you properly declare: viewController = new ViewController(); with a IntPtr parameter?
Thanks in advance!
Instead of trying to use attach the alert to the ViewController as shown in the demo code, use UIAlertView.
public override void ReceivedLocalNotification(UIApplication application, UILocalNotification notification)
{
UIAlertView alert = new UIAlertView () { Title = notification.AlertAction, Message = notification.AlertBody };
alert.AddButton("OK");
alert.Show ();
// CLEAR BADGES
UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;
}

Restrict orientation of view controller when using a static UITableView

I've set up a static UITableView with iOS Designer (IB in Objective-C world). But the orientation is changed despite I want to restrict it.
I've done the following:
In Properties under Simulated Metrics I chose Portrait as Orientation. Than I'm implementing the following functions for my UITableViewController:
public override bool ShouldAutorotate ()
{
return false;
}
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations ()
{
return UIInterfaceOrientationMask.Portrait;
}
public override UIInterfaceOrientation PreferredInterfaceOrientationForPresentation ()
{
return UIInterfaceOrientation.Portrait;
}
GetSupportedInterfaceOrientations is called and I return Portrait but the view is still rotated. What I'm missing?
Edit:
I've used the approach discussed in View Orientation. This works for my view controllers. The static UITableViewController is pushed in this way on the stack:
this.PresentViewController (new UINavigationController(myStaticTableViewController), true, null);
Here the standard implementation of UINavigationController is used. I also tried it with my CustomNavigationController which implements
partial class CustomNavigationController : UINavigationController
{
public CustomNavigationController (IntPtr handle) : base (handle)
{
}
public override bool ShouldAutorotate ()
{
return TopViewController.ShouldAutorotate();
}
public override UIInterfaceOrientation PreferredInterfaceOrientationForPresentation ()
{
return TopViewController.PreferredInterfaceOrientationForPresentation ();
}
}
but I can't do something like this
this.PresentViewController (new CustomNavigationController(myStaticTableViewController), true, null);
because it cannot convert my table view controller to IntPtr. Perhaps that's the reason why it doesn't respect the interface orientation. What solutions do I have?
Seems that I only had to add another constructor as stated in the linked thread. Now my CustoMNavigationController looks like this:
partial class CustomNavigationController : UINavigationController
{
public CustomNavigationController(UIViewController rootViewController) : base(rootViewController)
{
}
public CustomNavigationController (IntPtr handle) : base (handle)
{
}
public override bool ShouldAutorotate ()
{
return TopViewController.ShouldAutorotate();
}
public override UIInterfaceOrientation PreferredInterfaceOrientationForPresentation ()
{
return TopViewController.PreferredInterfaceOrientationForPresentation ();
}
}
Now I can use
this.PresentViewController (new CustomNavigationController(myStaticTableViewController), true, null)
and everything works as expected.

How to access NavigationController.PushViewController under UITableViewSource?

How can I access NavigationController inside UITableviewSource class?
On Row selection I want to navigate to another UIController.
This is my code,
public class RootTableSource : UITableViewSource
{
IList<VendorDetails> tableItems;
string cellIdentifier = "UIViewController";
ReportsList reportList;
AddNewReport addnewReport;
public RootTableSource()
{
}
public RootTableSource (IEnumerable<VendorDetails> items)
{
tableItems = items.ToList ();
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
tableView.DeselectRow (indexPath, true);
// Redirect to another UIController....
}
public VendorDetails GetItem (int id)
{
return tableItems [id];
}
}
have you instance UINavigationController in AppDelegate ?
like this...
#property (strong, nonatomic) UINavigationController *navigationViewController;
then you should can access UINavigationController from AppDelegate delegate
#import "AppDelegate.h"
#implementation yourClassName
-(void)functionName{
AppDelegate *appdelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
appdelegate.navigationViewController; //your UINavigationController
[appdelegate.navigationViewController pushViewController:yourUIViewController animated:YES];
}
#end
wish help ~
edit:
Sorry i have never use Xamarin before
so i think this is a bad way to implement ...
but it look work
AppDelegates.cs
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
UIWindow window;
HomeScreen home;
public static UINavigationController navigation;
//set navigation public and static
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
window = new UIWindow (UIScreen.MainScreen.Bounds);
home = new HomeScreen ();
navigation = new UINavigationController(home);
window.RootViewController = navigation;
window.MakeKeyAndVisible ();
return true;
}
}
yourClassName.cs
AppDelegate.navigation
//access navigation
wish help again ...
The way I do this is by passing a reference to the TableViewController when I create my Source. Then the Source can use this reference to access it's parent's NavigationController.
UITableViewController _parent;
public RootTableSource (IEnumerable<VendorDetails> items, UITableViewController parent)
{
tableItems = items.ToList ();
_parent = parent;
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
tableView.DeselectRow (indexPath, true);
_parent.NavigationController.PushViewController(...);
}

What is the best way to switch a UITableView from list to grouped?

I have a requirement where I initially have a list of messages only ordered by date/time. The requirement if for the user to be able to click on a UISegmentedControl (list of 4 buttons) and be able to change the UITableView from a straight list to a grouped list (ie. grouped by category of message).
From what I've read, once the style is set on a UITableView you can not change it. So what is the best approach to satisfy this requirement? Kill the view and re-create with the appropriate style?
Not that it makes a huge difference, I am using Xamarin Studio and C#, targeting Mono 3.2.1 and iOS 6+
Rather than killing the view and re-instantiating, just maintain references to two UITableViews, one of each of the appropriate types. Toggle between them using your Controller class. The following simple example puts the toggling button in the same UIView as the table, which is probably not appropriate, but otherwise shows the technique:
public class ChangeableSource : UITableViewSource
{
public bool Grouped { get; set; }
public override int NumberOfSections(UITableView tableView)
{
if(Grouped)
{
return 4;
}
else
{
return 1;
}
}
public override int RowsInSection(UITableView tableview, int section)
{
return 3;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = tableView.DequeueReusableCell("Default");
if(cell == null)
{
cell = new UITableViewCell(UITableViewCellStyle.Default, "Default");
}
cell.TextLabel.Text = String.Format("IndexPath {0} {1}", indexPath.Section, indexPath.Row);
return cell;
}
}
public class ToggleTableView : UIView
{
UITableView ungroupedView;
UITableView groupedView;
ChangeableSource changeableSource;
public void SetStyle(bool grouped)
{
changeableSource.Grouped = grouped;
if(changeableSource.Grouped)
{
ungroupedView.RemoveFromSuperview();
AddSubview(groupedView);
}
else
{
groupedView.RemoveFromSuperview();
AddSubview(ungroupedView);
}
}
public bool GetStyle()
{
return changeableSource.Grouped;
}
public ToggleTableView()
{
var btn = new UIButton(new RectangleF(10, 10, 150, 40));
btn.SetTitle("Change", UIControlState.Normal);
btn.TouchUpInside += (s,e) => ToggleStyle(this, new EventArgs());
var tvFrame = new RectangleF(0, 60, UIScreen.MainScreen.Bounds.Width, UIScreen.MainScreen.Bounds.Height - 60);
ungroupedView = new UITableView(tvFrame, UITableViewStyle.Plain);
groupedView = new UITableView(tvFrame, UITableViewStyle.Grouped);
AddSubview(btn);
AddSubview(ungroupedView);
changeableSource = new ChangeableSource();
changeableSource.Grouped = false;
ungroupedView.Source = changeableSource;
groupedView.Source = changeableSource;
}
public event EventHandler<EventArgs> ToggleStyle = delegate {};
}
public class TogglingTableController : UIViewController
{
public TogglingTableController() : base ()
{
}
public override void DidReceiveMemoryWarning()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning();
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
var view = new ToggleTableView();
view.ToggleStyle += (s,e) =>
{
view.SetStyle(! view.GetStyle());
};
this.View = view;
}
}
[Register ("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
UIWindow window;
TogglingTableController viewController;
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
window = new UIWindow(UIScreen.MainScreen.Bounds);
viewController = new TogglingTableController();
window.RootViewController = viewController;
window.MakeKeyAndVisible();
return true;
}
}
public class Application
{
static void Main(string[] args)
{
UIApplication.Main(args, null, "AppDelegate");
}
}

Categories