I'm refactoring a project to the new navigation with shell that was released with Xamarin.Forms 4.0 and now I was migrating a tabbedPage that had an effect
applied to hide the title of the children from the tabbedPage leaving the icons only visible, with Shell it is no longer necessary that the page inherits from TabbedPage if not that the own class of Shell allows you to implement the tabbedPage, masterPage ... the problem is that now I do not know how I can apply the effect I used previously since I can not refer to the tabbedPage.
Note: In this case I use Flyout since I need a design with a hamburger menu and also tabbedPage, that's why I do not use only the TabBar.
<FlyoutItem Route="home"
Title="TEST"
Icon="home_icon"
FlyoutDisplayOptions="AsMultipleItems">
<ShellContent Route="bottomtab1"
Title="TEST1"
Icon="target_icon"
ContentTemplate="{DataTemplate views:x}" />
<ShellContent Route="bottomtab2"
Title="TEST2"
Icon="user_login"
ContentTemplate="{DataTemplate views:y}" />
</FlyoutItem>
TabbedPage Image
MasterPage Image
Thanks to the pfedotovsky user of GitHub I have found an alternative solution until the Xamarin team officially resolves this, in this article he explains it.
There's a workaround for Android with custom renderers. The key is to set
_bottomView.LabelVisibilityMode = LabelVisibilityMode.LabelVisibilityAuto; or
_bottomView.LabelVisibilityMode = LabelVisibilityMode.LabelVisibilityUnlabeled;
using Android.OS;
using Android.Support.Design.BottomNavigation;
using Android.Support.Design.Widget;
using Android.Views;
using Xamarin.Forms.Platform.Android;
namespace App.Droid
{
public class AndroidShellItemRenderer : ShellItemRenderer
{
BottomNavigationView _bottomView;
public AndroidShellItemRenderer(IShellContext shellContext) : base(shellContext)
{
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var outerlayout = base.OnCreateView(inflater, container, savedInstanceState);
_bottomView = outerlayout.FindViewById<BottomNavigationView>(Resource.Id.bottomtab_tabbar);
_bottomView.LabelVisibilityMode = LabelVisibilityMode.LabelVisibilityAuto;
return outerlayout;
}
}
}
To use this renderer, you need to create custom ShellRenderer as well:
using System;
using Android.Content;
using Conference.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(Shell), typeof(AndroidShellRenderer))]
namespace App.Droid
{
public class AndroidShellRenderer : ShellRenderer
{
public AndroidShellRenderer(Context context)
: base(context)
{
}
protected override IShellItemRenderer CreateShellItemRenderer(ShellItem shellItem)
{
return new AndroidShellItemRenderer(this);
}
}
}
Related
I would like to use Rg.Plugins.Popup for Xamarin.Forms but unfortunately I cannot add PopupPage to the project. I am using VIsual Studio 2017. In AddNewItem window there is no PopupPage at all.
I tried to add ContentPage instead like this:
public partial class CustomPopupPage : ContentPage
{
public CustomPopupPage ()
{
InitializeComponent ();
}
}
but whenever i try to change type ContentPage to PopupPage I get following error: Partial declarations of 'CustomPopupPage' must not specify different base classes.
The problem is that second partial class is in auto-generated file CustomPopupPage.xaml.g.cs and I cannot modify that file because each time application is compiling it rewrites that file.
I think I am missing something obvious here because demo is working fine.
PopupPage is a subclass of ContentPage .So you have to add a new ContentPage and change the superclass both in xaml and code benind .
Firstly , install the package Rg.Plugins.Popup from nuget in share project and specific platform (iOS and Android).
The plugin requires to be initialized. To use a PopupPage inside an application, each platform application must initialize the Rg.Plugins.Popup. This initialization step varies from platform to platform and is discussed in the following sections.
iOS ->AppDelegate.cs
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
Rg.Plugins.Popup.Popup.Init();
global::Xamarin.Forms.Forms.Init ();
LoadApplication (new App ());
return base.FinishedLaunching (app, options);
}
Android->MainActivity
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
Rg.Plugins.Popup.Popup.Init(this, bundle);
Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication (new App ());
}
xaml
<?xml version="1.0" encoding="utf-8" ?>
<pages:PopupPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup"
xmlns:animations="clr-namespace:Rg.Plugins.Popup.Animations;assembly=Rg.Plugins.Popup"
x:Class="MyProject.MyPopupPage">
<!--You can set an animation in the xaml file or in the csharp code behind-->
<pages:PopupPage.Animation>
<animations:ScaleAnimation
PositionIn="Center"
PositionOut="Center"
ScaleIn="1.2"
ScaleOut="0.8"
DurationIn="400"
DurationOut="300"
EasingIn="SinOut"
EasingOut="SinIn"
HasBackgroundAnimation="True"/>
</pages:PopupPage.Animation>
<!--You can use any elements here which are extended from Xamarin.Forms.View-->
<StackLayout
VerticalOptions="Center"
HorizontalOptions="Center"
Padding="20, 20, 20, 20">
<Label
Text="Test"/>
</StackLayout>
</pages:PopupPage>
in code behind
public partial class MyPopupPage : Rg.Plugins.Popup.Pages.PopupPage
{
public MyPopupPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
}
}
Update
It seems an existing issue of vs 2017 , on VS 2019 it works fine . And I will post this issue to product teams .
I'm using Xamarin.Forms and Prism to create my mobile app.
I have a screen with 2 entries. When entering the screen, I'd like to set the focus on the first entry.
Then after the user entered data in this entry and validated it, I'd like to set the focus to the second entry.
Based on first answer:
I should do something wrong. I've created a small new Prism project to test it :
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:testEntry"
x:Class="testEntry.Views.MainPage"
Title="{Binding Title}">
<StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
<Label Text="Welcome to Xamarin Forms and Prism!" />
<local:MyEntry Placeholder="" x:Name="entry1" />
<Button Text="set focus on entry1" Clicked="Button_Clicked"/>
</StackLayout>
</ContentPage>
MainPage.xaml.cs
using Xamarin.Forms;
namespace testEntry.Views
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
entry1.Focus(); //Not Working
}
private void Button_Clicked(object sender, EventArgs e)
{
entry1.Focus(); //Working
}
}
}
MyEntry.cs (in Main project)
using Xamarin.Forms;
namespace testEntry
{
public class MyEntry : Entry
{
}
}
MyEntryRenderer.cs (in Android Project)
using Android.Content;
using Android.Views;
using Android.Views.Accessibility;
using Xamarin.Forms.Platform.Android;
namespace testEntry.Droid
{
public class MyEntryRenderer : EntryRenderer
{
public MyEntryRenderer(Context context) : base(context)
{
}
public static void Focus(View view)
{
view.SendAccessibilityEvent(EventTypes.ViewFocused);
}
}
}
Unfortunately, still nofocus on my field :'(
Finally, and thanks to Saamer, I found another way of doing it by using EventAggregator.
public class FocusChanged : PubSubEvent<String> { }
Then in my view model :
IEventAggregator _ea;
public MainPageViewModel(INavigationService navigationService, IEventAggregator eventAggregator) : base(navigationService)
{
_ea = eventAggregator;
}
In the viewModel, whenever I want to set the focus to a field, I'm sending an event :
_ea.GetEvent<FocusChanged>().Publish("Source");
And in my view's code behind, I handle this event:
IEventAggregator _ea;
public MainPage(IEventAggregator eventAggregator)
{
InitializeComponent();
_ea = eventAggregator;
_ea.GetEvent<FocusChanged>().Subscribe(SetFocusOnControl); //Name of method which will handle this event
}
/// set the focus on entry based on parameter
/// each event value will set focus on a specific entry (example: source is linked to entry txtScanSrc)
private async void SetFocusOnControl(String fieldName)
{
Entry l_view;
switch(fieldName)
{
case "source": l_view = this.FindByName<Entry>("txtScanSrc"); break;
case "quantity": l_view = this.FindByName<Entry>("txtQty"); break;
case "tote": l_view = this.FindByName<Entry>("txtScanTote"); break;
case "pallet": l_view = this.FindByName<Entry>("txtScanPalout"); break;
case "destination": l_view = this.FindByName<Entry>("txtScanDest"); break;
default: l_view = this.FindByName<Entry>("txtScanSrc"); break;
}
await WaitAndExecute(500, () => { l_view.Focus(); });
}
There's a way of doing this using the Accessibility APIs of each of the platforms. Xamarin forms doesn't have all the platform features of accessibility yet so you d have to create a custom renderer and then call the focus method in a life cycle event of the page.
So calling this Focus function would cause the app to focus on that element. You generally don't want to do it because the app purposefully focuses on what it does so accessible users have a consistent experience. But if you really want to override the default behavior, in Android it's something like this
public static void Focus(View view)
{
view.SendAccessibilityEvent(EventTypes.ViewFocused);
}
And in iOS, you have to use the PostNotification apis which will be some variation of this
UIAccessibility.PostNotification(UIAccessibilityPostNotification.ScreenChanged, entry element)
You can look more into Accessibility Focus to get the exact answer
How do I enable iOS 11 prefersLargeTitles throughout my Xamarin.Forms app?
I tried creating a custom renderer derived from PageRenderer for NavigationPage, setting:
ViewController.NavigationController.NavigationBar.PrefersLargeTitles = true;
This didn't have any effect, however.
Voila
[assembly: ExportRenderer(typeof(NavigationPage), typeof(NavBarRenderer))]
namespace LargeTitleSample.iOS
{
public class NavBarRenderer : NavigationRenderer
{
protected override void OnElementChanged(Xamarin.Forms.Platform.iOS.VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
NavigationBar.PrefersLargeTitles = true;
}
}
}
You have to create a custom renderer for the NavigationPage inheriting the NavigationRenderer. Then set the PrefersLargeTitles property on the NavigationBar to true.
It seems that when you add some scrollable control to the page, it will automatically have to 'big to small' effect when scrolling up, at least for a ListView.
Working example repo is here: https://github.com/jfversluis/LargeTitleSample
For XAML:
<NavigationPage Title="..." xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core" ios:NavigationPage.PrefersLargeTitles="true">
How to Remove Navigation Bar Shadow and Line of content page in Xamarin.forms.
Is it possible to do this without rendering.
For just Xamarin Forms, iOS. Add this to your AppDelegate
UINavigationBar.Appearance.ShadowImage = new UIImage(); //No line under the navigation
Add this render class inside you xamarin ios project
[assembly: ExportRenderer(typeof(NavigationPage), typeof(CustomNavigationRenderer))]
namespace YOUR_IOS_NAMESPACE
{
public class CustomNavigationRenderer : NavigationRenderer
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
NavigationBar.ShadowImage = new UIImage();
}
}
}
I'm working on a multiplatform app with Xamarin.Forms for Android, iOS and UWP. One of the requirements is to apply a corporate custom font on the title of all pages, which are instances of NavigationPage. I've got this working for iOS but I can't get it to work for Android or UWP.
What I've done is to create custom renderers for each platform. For iOS this is working with the following code:
using System.ComponentModel;
using UIKit;
using MyNameSpace.iOS.Renderers
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRendererAttribute(typeof(NavigationPage), typeof(MyNavigationPageRenderer))]
namespace MyNameSpace.iOS.Renderers
{
public class MyNavigationPageRenderer : NavigationRenderer
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
var page = this.Element as NavigationPage;
if (page == null) return;
this.NavigationBar.TitleTextAttributes = new UIStringAttributes
{
Font = UIFont.FromName("MyFont", 18),
ForegroundColor = page.BarTextColor.ToUIColor()
};
}
}
}
I know how to get the correct font in the OnElementChanged-method for the Android and the UWP platform but how do I apply them? I can't find a property to set.
I can partially answer my own question. For Android, there are a lot of solutions in Java and translating them to Xamarin is not always easy. But I have found a reasonable and easy to understand solution, based on Getting ActionBar Title TextView with AppCompat v7 r21.
First, add a TextView to Resources/layout/toolbar.axml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways">
<TextView
style="#style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Toolbar Title"
android:gravity="center_vertical"
android:id="#+id/toolbar_title" />
</android.support.v7.widget.Toolbar>
Then create a custom NavigationPage renderer:
using System;
using System.ComponentModel;
using Android.Graphics;
using Android.Widget;
using MyNameSpace.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms.Platform.Android.AppCompat;
using Support = Android.Support.V7.Widget;
[assembly: ExportRenderer(typeof(NavigationPage), typeof(MyNavigationPageRenderer))]
namespace MyNameSpace.Droid.Renderers
{
public class MyNavigationPageRenderer : NavigationPageRenderer
{
private Support.Toolbar _toolbar;
public override void OnViewAdded(Android.Views.View child)
{
base.OnViewAdded(child);
if (child.GetType() == typeof(Support.Toolbar))
_toolbar = (Support.Toolbar)child;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
var page = this.Element as NavigationPage;
if (page != null && _toolbar != null)
{
Typeface tf = Typeface.CreateFromAsset(Android.App.Application.Context.Assets, "MyFont.ttf");
TextView title = (TextView)_toolbar.FindViewById(Resource.Id.toolbar_title);
title.SetText(page.CurrentPage.Title, TextView.BufferType.Normal);
title.SetTypeface(tf, TypefaceStyle.Normal);
}
}
}
}
In the OnViewAdded-event, we get a reference to the toolbar. In the OnElementPropertyChanged-event, we get the custom font from the assets and with a FindViewById() we retrieve the defined TextView. Then we can set the Title and Typeface (font) of the Textview of the Toolbar.
So far so good. Anyone an idea to accomplish the same in the UWP-project?