I have a settings dialog that I want to be full screen and cover the tab bar at the bottom of the screen. I used this SO answer and added HidesBottomBarWhenPushed to my view controller and it does hide the tab bar. Unfortunately it leaves behind the little triangle indicator subview that is displayed by the UITabBarController subclass.
I'm assuming there is some form of notification that I can subscribe to in order to hide the indicator but I don't know what that is. A little help here?
Maybe you could post a NSNotification when you set the bar to hidden using the method described here?
Can't access TabBarController from ImageView
I'm going to answer this myself because I think it's worth recording for future reference. I have a SettingsDialogViewController I wire up in the ViewDidLoad() method of my HomeDialogViewController:
NavigationItem.LeftBarButtonItem = new UIBarButtonItem("Settings", UIBarButtonItemStyle.Plain, (e, sender) => {
ActivateController (_settingsDvc());
});
The SettingsDialogViewController is created with HidesBottomBarWhenPushed = true. So when the settings dialog is activated, the bottom bar is hidden which causes the ViewWillLayoutSubviews() method of the CustomTabBarController to be called. By overriding that method I can set the visibility of my indicator based on whether the visible view controller (e.g. SettingsDialogViewController) hides the bottom bar when pushed. When that view controller is popped the indicator will automatically reappear.
public override void ViewWillLayoutSubviews () {
base.ViewWillLayoutSubviews ();
var selectedVc = SelectedViewController as UINavigationController;
indicator.Hidden = selectedVc != null && selectedVc.VisibleViewController.HidesBottomBarWhenPushed;
}
A final note, I found that the animation that occurred when activating the new settings view would display a black band across the screen below the status bar. I resolved this by setting the AutoResizingMask in the "from" view controller.
public override void ViewDidLoad () {
base.ViewDidLoad ();
NavigationItem.LeftBarButtonItem = new UIBarButtonItem("Settings", UIBarButtonItemStyle.Plain, (e, sender) => {
ActivateController (_settingsDvc());
});
View.AutoresizingMask = UIViewAutoresizing.FlexibleHeight;
}
Related
I use PTCardTabBarController like custom tab bar. I want to hide tab bar in my ViewController. I trying to use in storyboard Hide Bottom Bar on Push or in code: self.tabBarController?.tabBar.isHidden = true. But it not helped me.
When I stat to use PTCardTabBar I have next scheme in storyboard:
TabBarController (with class PTCardTabBarController and module PTCardTabBar) -> NavigationBarController -> ViewController.
Next I launch my app and I see under my PTCardTabBar system iOS tab bar. I use in storyboard Hide Bottom Bar on Push but it is hide only system tab bar and not PTCardTabBar. How to fix it and hide both tab bars?
Taking a quick look at that PTCardTabBar library...
What you see on-screen is not a UITabBar ... it is a UIView. So, any normal actions on a standard Tab Bar Controller's TabBar will not be related.
To hide it, you need to edit PTCardTabBarController.swift and make its customTabBar available to your code:
// make this "open"
open lazy var customTabBar: PTCardTabBar = {
return PTCardTabBar()
}()
Then, when you want to hide the tab bar (for example, in viewDidLoad() in your view controller:
if let ptcTBC = tabBarController as? PTCardTabBarController {
ptcTBC.customTabBar.isHidden = true
}
You'll also (obviously) need to set .isHidden back to false to show it again.
Probably, though, you want to do more than just have it showing or hidden... in which case you could further modify PTCardTabBarController.swift to add a function to animate it into or out-of view (for example).
I'm creating a temporary UIWindow, on top of the main window, to show some small amount of data overlaid on the rest of my app. This information should not affect the status bar in any way. Note that the overlay window can be launched from a non-view controller context, meaning that the current view controller at the top of the stack of the main window might not be aware of the existence of the overlay window.
Unfortunately, as soon as I do overlayWindow.isHidden = false, it transfers control of the status bar (its style and whether it's hidden) to the root view controller of my overlay window, and I can't work out how to stop it.
Alternatively, I could just "remember" the previous state of the status bar and have my overlay root view controller output those, but there doesn't seem to be a good method to find out the current state and visibility of the status bar in iOS 13, at least which takes into account modally presented view controllers using the new sheet effect.
How can I have my overlay UIWindow reliably not affect the status bar?
Edit: I've prepared a small test case: https://github.com/Aquilosion/TestWindowView
The test case shows a view controller which changes its status bar appearance every second. You can open the same view controller again in a modal, and despite it also requesting status bar changes, iOS correctly locks the status bar white because the view controller never reaches it in sheet mode. Opening the window overlay currently always shows a black status bar, despite whether there's a modal presented or not. I attempt to set the status bar child to be the main window's root view controller's status bar child. Ideally, iOS would respect this and continue to change the status bar style while the overlay window was visible.
You can override a property childForStatusBarStyle of the root view controller of the overlay window.
class YourRootController { // root of the overlay window
var controllerToInheritStatusAttributesFrom: UIViewController?
override var childForStatusBarStyle: UIViewController? {
return controllerToInheritStatusAttributesFrom
}
}
// Call this from any place of the app, where you show the overlay window
if let controller = overlayWindow.rootViewController as? YourViewController {
controller.controllerToInheritStatusAttributesFrom = // needed controller, which lies underneath
controller.setNeedsStatusBarAppearanceUpdate()
}
I'm not sure it will help, considering that controllers will be in different windows, but it's worth a try.
I made your case work, just update the code:
private func updateStyle() {
styleIndex += 1
setNeedsStatusBarAppearanceUpdate()
overlayWindow?.rootViewController?.setNeedsStatusBarAppearanceUpdate()
}
Add this to MainViewController:
required init?(coder: NSCoder) {
super.init(coder: coder)
modalPresentationCapturesStatusBarAppearance = true
}
override var preferredStatusBarStyle: UIStatusBarStyle {
if self.presentingViewController != nil {
return .lightContent
}
return Self.styles[styleIndex % Self.styles.count]
}
I have FormViewController that I made full programmatically with Eureka form builder (link). I dont have view controller in storyboard for that. Class name of that view controller is NewPasswordVC. When I click od add bar button I open NewPasswordVC with this code:
let newPasswordVC = NewPasswordVC()
self.navigationController?.pushViewController(newPasswordVC, animated: true)
I open NewPasswordVC but when I go back in root view controller my bottom toolbar disappear. Why? How to fix this?
This is storyboard:
This is my problem in gif:
Can't speak about Eureka specifically, but chances are the UIViewController being pushed in has hidesBottomBarWhenPushed set to true.
So I would look into setting it to false, which can be done programmatically.
The solution to my problem I found here: link
override func willMove(toParent parent: UIViewController?){
super.willMove(toParent: parent)
if parent == nil{
self.navigationController?.isToolbarHidden = false
}
}
We are using MvvmCross 4.4.0 on the our iOS project and I faced the following problem:
I need to implement "Item" page with reference to the other
"Item" page;
I need an instant back navigation from any "Item" page to the previous controller ("Catalogue" controller).
Diagram:
Catalogue --ConcreteItem--> Item1 --MoreItems--> Item2 --MoreItems-->
Item3 --BackNavButton--> Catalogue.
I am doing the following thing in the Custom ViewPresenter:
var topViewController = ParentRootViewController.TopViewController;
ParentRootViewController.PushViewController(currentViewController, needAnimation);
if (topViewController.GetType() == currentView.GetType()
&& /*Logic to determine if its correct view types*/)
{
topViewController.RemoveFromParentViewController();
topViewController.Dispose();
}
And actually it works until I didn't return to the "Catalogue" page.
The problem is that I need to click back button so many times I had clicked "More" button on "Item" page. Also if we use custom back button with such code in both "Catalogue" and "Item" pages:
if (NavigationController?.NavigationBar?.BackItem != null)
{
var backbutton = new UIBarButtonItem(" ",
UIBarButtonItemStyle.Plain,
(sender, e) => { NavigationController?.PopViewController(true); })
{
Image = UIImage.FromBundle("BackButtonImage")
};
NavigationItem.LeftBarButtonItem = backbutton;
}
then app crashes when clicking "Back" NavButton on "Catalogue" page with in lambda
(sender, e) => { NavigationController?.PopViewController(true);
The disposed object ItemPageViewController.
The question is : How to correctly implement "SingleTop" page in MvvmCross?
Or
How to fix this problem?
P.S.: If from MvxPresenter remove line
topViewController.Dispose();
then in custom lambda would throw NullReferenceException.
P.P.S.: I believe it the problem that I don't remove controller from navigation stack. I have tried to remove controllers in Custom View Presenter, but, firstly, it is null there sometimes, and even with null check nothing helped.
UINavigationController has a function PopToViewController(UIViewController viewController, bool animated);
Instead of removing every ViewController when the views are of the same type, you could pop to the ViewController Catalogue when the backbutton is pressed.
UINavigationController has a property ViewControllers that we can use to find CatalogueViewController.
Since you're using MvvmCross we'll check for the ViewModel type.
var catalogueController = NavigationController.ViewControllers.First(c =>
((IMvxIosView)c).ViewModel.GetType() == typeof(CatalogueViewModel));
Now you can use the function PopToViewController to close all the views untill CatalogueController
CurrentNavigationController.PopToViewController(catalogueController, true);
Is it possible such that I can have a navigation controller in each of my tabs of a TabBarController while using Xamarin iOS? I've currently setup my storyboard like so (for simplicity, I'm using a single tab)
TabBarController -> NavigationController -> UITableViewController
In my UITableViewController, the following code in my ViewDidLoad method does not change the title nor add the desired button to the top navigation. Have I set up something wrong?
public override void ViewDidLoad()
{
base.ViewDidLoad();
Console.WriteLine("view did load");
Title = "My custom title";
NavigationItem.SetRightBarButtonItem(
new UIBarButtonItem(UIBarButtonSystemItem.Add, (sender, args) =>
{
PerformSegue("CreateRecordSegue", this);
})
, true);
}
Image of storyboard is here: https://ibb.co/m7qq85
The solution is to:
1) Remove the navigation controller that leads into the tab bar controller
2) Create a segue from the home page into the tab bar controller, making the segue type to replace (instead of push)