Getting navigation bar height in dependency service - Xamarin Forms - xamarin.forms

i have this issue wherein i need to get the navigation bar height in my Dependency Service.
Currently I am stuck on what to follow here. I tried everything i find in stackoverflow and google but no one works for me.
Heres my code:
[assembly: Dependency(typeof(DeviceInfo))]
namespace Wicket.App.Mobile.iOS.Framework
{
public class DeviceInfo : IDeviceInfo
{
public float StatusBarHeight => (float)UIApplication.SharedApplication.StatusBarFrame.Size.Height;
public float NavigationBarHeight => GetNavigationBarHeight();
public static UINavigationController NavigationController { get; set; }
public float GetNavigationBarHeight()
{
//Get navigation bar height
return 0;
}
}
}
I already completed the android part and it works good. The only problem now is in iOS. I have tried getting the instance of navigationcontroller in AppDelegate so that I can just get the bar frame like this NavigationBar.Bounds.Height;

I think this should work:
var navheight = GetTopViewController().NavigationController.NavigationBar.Frame.Height;
public static UIViewController GetTopViewController()
{
var window = UIApplication.SharedApplication.KeyWindow;
var vc = window.RootViewController;
while (vc.PresentedViewController != null)
vc = vc.PresentedViewController;
if (vc is UINavigationController navController)
vc = navController.ViewControllers.Last();
return vc;
}

Solution:
How about pass an instance of viewController as parameter in the function inside the IDeviceInfo?
Try this:
public void getNaviHeight(ContentPage vc)
{
var renderer = Platform.GetRenderer(vc);
if (renderer == null)
{
renderer = RendererFactory.GetRenderer(vc);
Platform.SetRenderer(vc, renderer);
}
var viewController = renderer.ViewController;
var h = viewController.NavigationController?.NavigationBar.Frame.Height;
}
And use the dependency:
public MainPage ()
{
DependencyService.Get<IDeviceInfo>().getNaviHeight(this);
}

this worked to me:
var navigationBar = UIApplication.SharedApplication.KeyWindow.RootViewController.View.Subviews[0].Subviews.OfType<UINavigationBar>().FirstOrDefault();
if(navigationBar != null)
{
// continue here...
}

Related

Xamarin Forms check is page is Modal

So basically I'm try to to find out if a page was pushed modally.
Here is the code I have for my extension method:
public static bool IsModal(this Page page)
{
return page.Navigation.ModalStack.Any(p => page == p);
}
The issue is; p never equals page due to the fact p changes to NavigationPage during runtime although intellisense reports it as a type of Page at compile time.
I've tried casting p to a Page but the type does not change at runtime and intellisense just moans that the cast is redundant.
I call this extension by using CurrentPage.IsModal in my View Model. CurrentPage is a type of Page at compile time but then changes to NavigationPage at runtime.
The confusing thing is that during debugging, p has properties such as CurrentPage and RootPage which show in the debugger, but these are not accessible by using p.CurrentPage as the compiler complains they don't exist !?! I was going to try an compare these but I can't access them but can view them in the debugger.
You need to check the type of page first, a page without navigationbar can also be pushed modally:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
private async void Button_Clicked(object sender, EventArgs e)
{
Page1 p = new Page1();
await this.Navigation.PushModalAsync(p, true);
bool b = PageExtensions.IsModal(p);
Console.WriteLine(b);
}
}
public static class PageExtensions
{
public static bool IsModal(this Page page)
{
if (page.GetType() == typeof(NavigationPage))
{
return page.Navigation.ModalStack.Any(p => ((NavigationPage)p).CurrentPage.Equals(page));
}
else
{
return page.Navigation.ModalStack.Any(p => p.Equals(page));
}
}
}
So this code works:
public static class PageExtensions
{
public static bool IsModal(this Page page)
{
return page.Navigation.ModalStack.Any(p=> ((NavigationPage) p).CurrentPage.Equals(page));
}
}
I'm concerned that is not safe as it assumes p is a Type of NavigationPage.
Can you try this, there could be typos, I wrote this freehand
public static bool IsModal(this Page page)
{
if (page.Navigation.ModalStack.Count > 0)
{
foreach (var thisPage in page.Navigation.ModalStack)
{
if (thisPage.Equals(page))
return true;
}
return false;
}
else
return false;
}
This is what I made to check the last pushed modal. Hope it helps to someone.
public async Task NewModalPagePushAsync(Page pageToOpen)
{
var lastModalPage = Application.Current.MainPage.Navigation.ModalStack;
if (lastModalPage.Count >= 1)
{
if (lastModalPage.Last().GetType().Name == pageToOpen.GetType().Name)
return;
}
await Application.Current.MainPage.Navigation.PushModalAsync(pageToOpen);
}

Navigation service from forms to iOS

I need to acmes view controller from forms page. Is there anything like this for IOS
is there any version of this in droid in iOS
public class NavigationImplementation : INavigationContract
{
public void Push()
{
var second = new Intent(MainActivity.activity, typeof(ScannerActivity));
MainActivity.activity.StartActivity(second);
}
}
In Xamarin iOS, there are two ways to navigate to next page.
One is NavigationController Push, another is Model Push.
NavigationController Push:
public void Push()
{
//SecondViewController secondViewController = this.Storyboard.InstantiateViewController("SecondViewController") as SecondViewController;
SecondViewController secondViewController = new SecondViewController();
if (secondViewController!= null) {
this.NavigationController.PushViewController(secondViewController , true);
}
}
Model Push:
//SecondViewController secondViewController = this.Storyboard.InstantiateViewController("SecondViewController") as SecondViewController;
SecondViewController secondViewController = new SecondViewController();
this.PresentViewController(secondViewController , true, () => { Console.WriteLine("Push completely"); });

Can I use ClassId in tabbedpage to differentiate their content

I'm trying to use the same page for 3 tabs in TabbedPage. But each tab has to display different data in the listview. Is there a way to set a parameter for each tab?
Example
<local:Sales Title="Pending"
Icon="ic_shortcut_home.png"
ClassId="pending"/>
<local:Sales Title="Posted"
Icon="ic_shortcut_home.png"
ClassId="posted"/>
<local:Sales Title="Uploaded"
Icon="ic_shortcut_home.png"
ClassId="uploaded"/>
I tried using ClassId, and Title to get their difference but I'm having trouble retrieving the ClassId in the Sales class constructor, are there any other ways to get the output I want?
public Sales()
{
InitializeComponent();
BindingContext = this;
salesCollection = new ObservableCollection<Head>();
initLvw();
Console.WriteLine(Title); //returns null
Console.WriteLine(ClassId); // returns null
}
You can load data in OnAppearing method:
protected override void OnAppearing()
{
base.OnAppearing();
Console.WriteLine(ClassId + "OnAppearing");
BindingContext = this;
salesCollection = new ObservableCollection<Head>();
initLvw();
}
Or load data with a little delay in constructor:
public AboutPage()
{
InitializeComponent();
Task.Run(async () =>
{
await Task.Delay(200);
Console.WriteLine(ClassId + "AboutPage");
BindingContext = this;
salesCollection = new ObservableCollection<Head>();
initLvw();
});
}

Xamarin Forms and FreshMVVM android UI issue

I use to XF and FreshMVVM framework and I have a UI issue
My code is:
App.cs
public const string NAVIGATION_LOGIN = "NavigationContainerLogin";
public const string NAVIGATION_MASTER_DETAIL = "NavigationContainterMasterDetail";
private FreshMasterDetailNavigationContainer _mainNav;
private FreshNavigationContainer _loginNav;
public App()
{
//prepare two navigation container
_mainNav = CreateMasterDetailNavigation();
_loginNav = CreateLoginNavigation();
if (Settings.IsSignedIn)
{
MainPage = _mainNav;
}
else
{
MainPage = _loginNav;
}
}
private FreshMasterDetailNavigationContainer CreateMasterDetailNavigation()
{
var masterDetailNav = new FreshMasterDetailNavigationContainer(NAVIGATION_MASTER_DETAIL);
masterDetailNav.Init("eDocine", "hamburger.png");
masterDetailNav.Master = FreshPageModelResolver.ResolvePageModel<MenuPageModel>();
masterDetailNav.Detail = new FreshNavigationContainer(FreshPageModelResolver.ResolvePageModel<HomePageModel>())
{
BarBackgroundColor = Settings.IsDoctorUser ? DataHelper.GreenCoor : DataHelper.BlueColor,
BarTextColor = Color.White
};
return masterDetailNav;
}
private FreshNavigationContainer CreateLoginNavigation()
{
return new FreshNavigationContainer(FreshPageModelResolver.ResolvePageModel<ChooseUserTypePageModel>(), NAVIGATION_LOGIN);
}
public MasterDetailPage RootPage
{
get
{
return MainPage as MasterDetailPage;
}
}
It line appears only on Android 5+
How can I solve this issue?
I found solution of this issue here

Caliburn Micro: How to add text to the bottom of a list box and display it

I'm trying to figure out how to add text to the bottom of a list box and display it. In WPF with code behind, I would grab the ScrollViewer and manipulate it, but I can't figure out how to do it with Caliburn...
You have a couple options.
1) In your ViewModel you can call GetView and cast it to your view type and get a reference to the ScrollViewer. Something like:
var myView = this.GetView() as MyView;
var myScrollView = myView.MyScrollView;
That works fine but isn't ideal if you're trying to not couple the view to the view model.
Option 2) is to implement IResult, see docs here.
public class ScrollViewResult : IResult
{
public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
private ScrollViewResult ()
{
}
public void Execute (ActionExecutionContext context)
{
var view = context.View as FrameworkElement;
var scrollViewer = FindVisualChild<ScrollViewer>(view);
//do stuff to scrollViewer here
Completed (this, new ResultCompletionEventArgs { });
}
private static TChildItem FindVisualChild<TChildItem> (DependencyObject obj)
where TChildItem : DependencyObject
{
for (var i = 0; i < VisualTreeHelper.GetChildrenCount (obj); i++)
{
var child = VisualTreeHelper.GetChild (obj, i);
if (child != null && child is TChildItem)
return (TChildItem)child;
var childOfChild = FindVisualChild<TChildItem> (child);
if (childOfChild != null)
return childOfChild;
}
return null;
}
//this isn't required of course but comes in handy for
//having a static method and passing parameters to the
//ctor of the IResult
public static IResult DoSomething ()
{
return new ScrollViewResult ();
}
Then you can call it like:
public IEnumerable<IResult> SomeAction()
{
yield return ScrollViewResult.DoSomething();
}

Resources