Xamarin Forms: How to set title for tabbedpage? - xamarin.forms

I implement TabbedPage with 3 tabs like the following picture.
On top of these 3 tabs, I am trying to set a title, which will be common for all the 3 tabs. Tried title property of tabbedpage, but not worked.
MyTabbedpage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Myapp;assembly=Myapp"
BarBackgroundColor="#1C7DB4"
BarTextColor="White"
x:Class="Myapp.MyTabbedPage">
</TabbedPage>
MyTabbedpage.xaml.cs
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Myapp
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MyTabbedPage : TabbedPage
{
public MyTabbedPage(bool value)
{
InitializeComponent();
Children.Add(new Topics());
Children.Add(new Group());
Children.Add(new Menu());
}
protected override bool OnBackButtonPressed()
{
return false;
}
}
}
Please suggest a solution.

I don't think you can do it without a custom renderer.
You may try this prebuilt form control - TabView - found at:
https://github.com/gruan01/XFControls
You can find it also on NuGet.
You can set image onto the tabs and other enhancements.
But I strongly recommend a custom renderer as a final solution.

public class MainPageCS : TabbedPage
{
public MainPageCS ()
{
var navigationPage = new NavigationPage (new SchedulePageCS ());
navigationPage.Icon = "schedule.png";
navigationPage.Title = "Schedule";
Children.Add (new TodayPageCS ());
Children.Add (navigationPage);
}
}
This is the code snippet from the official documentation. On line number 7 you can see how the title is set.
After you edited your question, it seems that you want to wrap your TabbedPage by a NavigationPage and set a Title for the NavigationPage. Example:
new NavigationPage(new MyTabbedPage()) { Title = "Common Title" };
Alternatively, one of your TabbedPage children can be a NavigationPage as well, depends on your needs.

Related

How could I change the Navigastion's page arrow in Xamarin Forms?

I'm creating an app using xamarin Forms (multiplatform), I'm using a Navigation page, but I want to change the arrow ("<-") to text ("back")
Do you know how could i do it?
Thanks
(I'm going to use it in an Android App, but I'm creating the app using Xamarin forms)
You could use custom renderer to remove the navigation icon and set it with text. But, when you do that, you need to capture the click of the text and simulate the back event.
Create the interface:
public class CustomNavigationPage : NavigationPage
{
public CustomNavigationPage(Page startupPage) : base(startupPage)
{
}
}
The implementation of Android:
[assembly: ExportRenderer(typeof(CustomNavigationPage),
typeof(NavigationPageRenderer_Droid))]
namespace NavigationPageDemo.Droid
{
public class NavigationPageRenderer_Droid : NavigationPageRenderer
{
public Android.Support.V7.Widget.Toolbar toolbar;
public Activity context;
public NavigationPageRenderer_Droid(Context context) : base(context)
{
}
protected override Task<bool> OnPushAsync(Page view, bool animated)
{
var retVal = base.OnPushAsync(view, animated);
context = (Activity)Forms.Context;
toolbar = context.FindViewById<Android.Support.V7.Widget.Toolbar>(Droid.Resource.Id.toolbar);
if (toolbar != null)
{
//if (toolbar.NavigationIcon != null)
//{
//toolbar.NavigationIcon = Android.Support.V7.Content.Res.AppCompatResources.GetDrawable(context, Resource.Drawable.back);
//toolbar.NavigationIcon = null;
toolbar.NavigationIcon = null;
toolbar.Title = "back";
toolbar.SetOnClickListener(new OnClick());
//}
}
return retVal;
}
protected override Task<bool> OnPopViewAsync(Page page, bool animated)
{
return base.OnPopViewAsync(page, animated);
}
}
public class OnClick : Java.Lang.Object, IOnClickListener
{
void IOnClickListener.OnClick(Android.Views.View v)
{
App.Current.MainPage.Navigation.PopAsync();
}
}
In the custom renderer, use the OnClickListener to capture the click on text.
when you are working with xamarin forms it is suggested make use of common components and make least use of custom renderer.
Now for your requirement you want to create custom navigation bar
so here is how you can do it.
Create BaseContent Page
Create a Control Template inside your base page your can follow this link
Inside your control template using a grid view place your label with text binding (Back),also your can place a label in center to show title of page again u can make use of template binding which u would come to know when u go through the link
Now inherit your main page with your basecontentpage page
add your control template inside your main page
turn off your navigation bar of your main page
and you are done, this would give u more power to add more things like image or toolbar in your navbar
also to dynamically handle your back button u can check the count from navigationstack if its 0 u can show Humburger Icon or if its more than 0 u can show your label using IsVisible True/False

How to add a SearchBar to the top of page like toolbaritems icon with Xamarin.Forms

I am using masterdetail page within this page i am using tabbed page now i want to show toolbar icon and search bar on the top of page.i am able to place toolbar icon but struggling with search bar.how to place it at the top its behavior should match with the search bar in whatsapp app and in youtube app
The WhatsApp search bar is just that, a SearchBar control which you can add to your XAML layout as follows:
<StackLayout>
<SearchBar Placeholder="Search" Text="{Binding Filter}" />
<ListView ItemSource="{Binding Items}">
...
</ListView>
</StackLayout>
Ensure you have a backing property for the filter. You can use the setter of this property to intercept people filtering the data and filter the Items property accordingly.
The YouTube search behaves a bit differently. The toolbar item pops a new screen modally where the search is handled similar to a UISearchController (on iOS). There is no Xamarin Forms drop-in control (that I'm aware of) that does this for you so you'll probably have to roll your own.
We can create a custom renderer on both Xamarin.iOS and Xamarin.Android to accomplish it.
Here's a sample application for reference:
https://github.com/brminnick/GitTrends
And here's a blog post that shows how to add a search bar to a Xamarin.Forms app for both Xamarin.iOS & Xamarin.Android: https://www.codetraveler.io/2019/08/10/adding-a-search-bar-to-xamarin-forms-navigationpage/
App.cs
Use a Xamarin.Forms Platform-Specific to use LargeTitles on the Xamarin.iOS app.
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
public class App : Xamarin.Forms.Application
{
public App()
{
var navigationPage = new Xamarin.Forms.NavigationPage(new MyContentPage());
navigationPage.On<iOS>().SetPrefersLargeTitles(true);
MainPage = navigationPage;
}
}
ISearchPage Interface
Create an Interface that can be used across the Xamarin.Forms, Xamarin.Android and Xamarin.iOS projects.
public interface ISearchPage
{
void OnSearchBarTextChanged(in string text);
event EventHandler<string> SearchBarTextChanged;
}
Xamarin.Forms Page
public class MyContentPage : ContentPage, ISearchPage
{
public MyContentPage()
{
SearchBarTextChanged += HandleSearchBarTextChanged
}
public event EventHandler<string> SearchBarTextChanged;
public void OnSearchBarTextChanged(in string text) => SearchBarTextChanged?.Invoke(this, text);
void HandleSearchBarTextChanged(object sender, string searchBarText)
{
//Logic to handle updated search bar text
}
}
iOS Custom Renderer
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UIKit;
using MyNamespace;
using MyNamespace.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(MyContentPage), typeof(SearchPageRenderer))]
namespace MyNamespace.iOS
{
public class SearchPageRenderer : PageRenderer, IUISearchResultsUpdating
{
readonly UISearchController _searchController;
public SearchPageRenderer()
{
_searchController = new UISearchController(searchResultsController: null)
{
SearchResultsUpdater = this,
DimsBackgroundDuringPresentation = false,
HidesNavigationBarDuringPresentation = false,
HidesBottomBarWhenPushed = true
};
_searchController.SearchBar.Placeholder = string.Empty;
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
if (ParentViewController.NavigationItem.SearchController is null)
{
ParentViewController.NavigationItem.SearchController = _searchController;
DefinesPresentationContext = true;
//Work-around to ensure the SearchController appears when the page first appears https://stackoverflow.com/a/46313164/5953643
ParentViewController.NavigationItem.SearchController.Active = true;
ParentViewController.NavigationItem.SearchController.Active = false;
}
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
ParentViewController.NavigationItem.SearchController = null;
}
public void UpdateSearchResultsForSearchController(UISearchController searchController)
{
if (Element is ISearchPage searchPage)
searchPage.OnSearchBarTextChanged(searchController.SearchBar.Text);
}
}
}
Xamarin.Android Menu XML
In the Xamarin.Android project, in the Resources folder, create a new folder called menu (if one doesn't already exist).
Note: the folder, menu, has a lowercase 'm'
In the Resources > menu folder, create a new file called MainMenu.xml.
Open Resources > menu > MainMenu.xml
In MainMenu.xml add the following code:
<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/ActionSearch"
android:title="Filter"
android:icon="#android:drawable/ic_menu_search"
app:showAsAction="always|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView"/>
</menu>
Xamarin.Android CustomRenderer
Uses the Plugin.CurrentActivity NuGet Package.
using Android.Content;
using Android.Runtime;
using Android.Support.V7.Widget;
using Android.Text;
using Android.Views.InputMethods;
using Plugin.CurrentActivity;
using MyNamespace;
using MyNamespace.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(MyContentPage), typeof(SearchPageRenderer))]
namespace MyNamespace.Droid
{
public class SearchPageRenderer : PageRenderer
{
public SearchPageRenderer(Context context) : base(context)
{
}
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
if (Element is ISearchPage && Element is Page page && page.Parent is NavigationPage navigationPage)
{
//Workaround to re-add the SearchView when navigating back to an ISearchPage, because Xamarin.Forms automatically removes it
navigationPage.Popped += HandleNavigationPagePopped;
navigationPage.PoppedToRoot += HandleNavigationPagePopped;
}
}
//Adding the SearchBar in OnSizeChanged ensures the SearchBar is re-added after the device is rotated, because Xamarin.Forms automatically removes it
protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
{
base.OnSizeChanged(w, h, oldw, oldh);
if (Element is ISearchPage && Element is Page page && page.Parent is NavigationPage navigationPage && navigationPage.CurrentPage is ISearchPage)
{
AddSearchToToolbar(page.Title);
}
}
protected override void Dispose(bool disposing)
{
if (GetToolbar() is Toolbar toolBar)
toolBar.Menu?.RemoveItem(Resource.Menu.MainMenu);
base.Dispose(disposing);
}
//Workaround to re-add the SearchView when navigating back to an ISearchPage, because Xamarin.Forms automatically removes it
void HandleNavigationPagePopped(object sender, NavigationEventArgs e)
{
if (sender is NavigationPage navigationPage
&& navigationPage.CurrentPage is ISearchPage)
{
AddSearchToToolbar(navigationPage.CurrentPage.Title);
}
}
void AddSearchToToolbar(string pageTitle)
{
if (GetToolbar() is Toolbar toolBar
&& toolBar.Menu?.FindItem(Resource.Id.ActionSearch)?.ActionView?.JavaCast<SearchView>().GetType() != typeof(SearchView))
{
toolBar.Title = pageTitle;
toolBar.InflateMenu(Resource.Menu.MainMenu);
if (toolBar.Menu?.FindItem(Resource.Id.ActionSearch)?.ActionView?.JavaCast<SearchView>() is SearchView searchView)
{
searchView.QueryTextChange += HandleQueryTextChange;
searchView.ImeOptions = (int)ImeAction.Search;
searchView.InputType = (int)InputTypes.TextVariationFilter;
searchView.MaxWidth = int.MaxValue; //Set to full width - http://stackoverflow.com/questions/31456102/searchview-doesnt-expand-full-width
}
}
}
void HandleQueryTextChange(object sender, SearchView.QueryTextChangeEventArgs e)
{
if (Element is ISearchPage searchPage)
searchPage.OnSearchBarTextChanged(e.NewText);
}
Toolbar GetToolbar() => CrossCurrentActivity.Current.Activity.FindViewById<Toolbar>(Resource.Id.toolbar);
}
}
Sample App
Here's a sample app for reference:
https://github.com/brminnick/GitTrends
And a blog post that shows how to add a search bar for both Xamarin.iOS and Xamarin.Android: https://www.codetraveler.io/2019/08/10/adding-a-search-bar-to-xamarin-forms-navigationpage/
Used User Control for Navbar. and hide Navigarionbar using
NavigationPage.SetHasNavigationBar (this, false);
Check following link may be it's help you. and i think it's for your requirement.
http://blog.xhackers.co/xamarin-forms-contentpage-with-searchbar-in-the-navigation-bar/
Placing a SearchBar in the top/navigation bar
How to include view in NavigationBar of Xamarin Forms?
install or update Android support repository, google play service and Google USB driver
if you'r using shell app you can use Shell.TitleView instead of Navigation.TitleView as the following :
<Shell.TitleView>
<SearchBar x:Name="search" Margin="10,10,10,10"
HorizontalOptions="FillAndExpand"/>
</Shell.TitleView>

Not being able to change Title in a Caliburn.Micro Conductor View using MahApps MetroWindow

I'm doing like so:
<Controls:MetroWindow x:Class="BS.Expert.Client.App.Views.ShellView"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ShowTitleBar="True"
Title="My Title">
The thing is that this is at the same time a defined main conductor on the main window with which I control navigation through other windows, so I'm not able to inherit from MetroWindow to at least trying change the title in the ViewModel:
public class ShellViewModel : Conductor<IScreen>.Collection.OneActive, IShell
{
public ShellViewModel()
{
#region mahApps Theme Loading
var theme = ThemeManager.DetectAppStyle(Application.Current);
var appTheme = ThemeManager.GetAppTheme(App.Configuration.Theme);
ThemeManager.ChangeAppStyle(Application.Current, theme.Item2, appTheme);
#endregion
//TODO: Changing Title here is not possible ((MetroWindow)this).Title = "No way";
// Tudo bem na seguinte liña
LocalizeDictionary.Instance.Culture = new System.Globalization.CultureInfo("pt-BR");
ShowPageOne();
}
public void ShowPageOne()
{
ActivateItem(new PageOneViewModel());
}
}
How should I change the title?
When using the MVVM pattern you should never try to set anything on the view directly in the view model like this. Instead using data binding to accomplish this.
So you would have a property on your ShellViewModel with something like:
public string MyTitle
{
get { return _myTitle; }
set
{
_myTitle = value;
//Insert your property change code here (not sure of the caliburn micro version)
}
}
and in your window xaml it would be something like:
<Controls:MetroWindow
Title="{Binding MyTitle}"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
...
>

Xamarin.Forms Add NavigationBar

I want to manage the nav bar appearence in the xaml?
And how can I manage the nav bar appearence in a Tabbed Page?
NavigationBar.SetHasNavigationBar(tabPage,true) seems not working.
Thank you all,
Ilenia
Maybe check that your mainpage is wrapped with NavigationPage in the public App() function:
MainPage = new NavigationPage(new LoginPage());
Changing the color of your navigation bar
To change the color of your navigation bar generically using Xamarin.Forms so that you only need to change the properties in one place, I'd suggest you add the following to your App.cs file like mentioned in this post on the Xamarin Forums.
Changing the color of the tab bar
Unfortunately, changing the color of the Tab Bar is currently not supported in xaml.
You will although need to write a customer renderer for iOS like so:
[assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTabbedPageRenderer))]
namespace JetAdvice_Free.iOS.Renderers
{
class CustomTabbedPageRenderer : TabbedRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
TabBar.TintColor = MonoTouch.UIKit.UIColor.Black;
TabBar.BarTintColor = MonoTouch.UIKit.UIColor.FromRGB(255, 128, 0);
}
}
}
Then, whenever you use a TappedPage on iOS, the background color will be applied to your tab bar.
You can set the navigationbar color only when you initialize your navigationpage like so:
new NavigationPage(your page here)
{
BarBackgroundColor = Color.Green,
BarTextColor = Color.White
};
For the issue of setting the tintcolor of the tabbar I recommend using a renderer like so:
public class TabPage_iOS : TabbedRenderer
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
this.TabBar.TintColor = Color.Blue.ToUIColor();
UITableView tableView = (UITableView)this.MoreNavigationController.TopViewController.View;
tableView.TintColor = this.TabBar.TintColor;
}
}

Xamarin.Forms UserControl using XAML and Custom Renderer

There are a few good examples already of how to create a "custom control" by -
Deriving a Class from View or an existing built-in control and then creating a custom renderer for it per platform.
http://blog.xamarin.com/using-custom-controls-in-xamarin.forms-on-android/
http://developer.xamarin.com/guides/cross-platform/xamarin-forms/custom-renderer/
I want to create a "compound custom control OR usercontrol" which contains multiple elements which are defined in XAML (in the shared code), and then customised with a renderer (to say tweak the styling per platform).
Does anyone have an example of doing this please? A simple example with a view that has a bindable label and an entry box should be enough to show the main principles.
Here is what I have so far -
Defined a ContentView to represent our usercontrols layout and contents.
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="News.Forms.VisualNewsContentView">
<ContentView.Content>
<StackLayout>
<Label x:Name="MyLabel" Text="Label"></Label>
<Entry x:Name="MyEntry" Text="Entry"></Entry>
</StackLayout>
</ContentView.Content>
</ContentView>
with codebehind -
public partial class VisualNewsContentView : ContentView
{
public VisualNewsContentView ()
{
InitializeComponent ();
}
// Not sure if I need this to access Entry ...
public Entry GetEntry ()
{
return MyEntry;
}
}
Add an Android Custom Renderer for that ContentView, how do I access and customise natively parts / controls of the ContentView?
[assembly:ExportRenderer (typeof(VisualNewsContentView), typeof(VisualNewsRenderer))]
namespace News.Forms.Android
{
public class VisualNewsRenderer: ViewRenderer
{
public VisualNewsRenderer () { }
protected override void OnModelChanged (VisualElement oldModel, VisualElement newModel)
{
base.OnModelChanged (oldModel, newModel);
if (newModel != null) {
VisualNewsContentView newsContentView = newModel as VisualNewsContentView;
// i.e. How could I get hold of EditText etc so I could natively customise its appearance? When you use a built in renderer like EntryRenderer you can use Control to access native control.
Console.WriteLine (newsContentView.GetLabel ().Text);
EditText ed = (EditText)newsContentView.GetEntry ().???
}
}
}
}
Just can't quite get the pieces together to work, the ContentView seems to render fine on page but cannot work out how to access its Child Native controls in the viewrenderer.
Be nice to also show how you can use Binding for the Label and Entry Text values.
I do not want to have to define a custom renderer for each single label / entry etc of the usercontrol.
Is this what you meant?
Some properties to access the Xamarin.Forms controls:
public partial class VisualNewsContentView : ContentView
{
public VisualNewsContentView()
{
InitializeComponent();
}
public Label Label
{
get
{
return MyLabel;
}
set
{
MyLabel = value;
}
}
public Entry Entry
{
get
{
return MyEntry;
}
set
{
MyEntry = value;
}
}
}
Some magic inside the Renderer to customize the controls on the page:
[assembly:ExportRenderer (typeof(VisualNewsContentView), typeof(VisualNewsRenderer))]
namespace News.Forms.Android
{
public class VisualNewsRenderer: ViewRenderer
{
public VisualNewsRenderer () { }
protected override void OnModelChanged (VisualElement oldModel, VisualElement newModel)
{
base.OnModelChanged (oldModel, newModel);
if (newModel != null) {
VisualNewsContentView newsContentView = newModel as VisualNewsContentView;
newsContentView.Label.Text = "It´s some kind of..";
newsContentView.Entry.Text = "MAGIC!";
newsContentView.Entry.BackgroundColor = Color.Blue;
newsContentView.Entry.RotationX = 180;
newsContentView.Entry.Focus();
}
}
}
}
EDIT:
I don't know if it's possible to map your controls from the XAML-page to native controls. You could add the controls which you want to customize natively # the renderer.
[assembly:ExportRenderer (typeof(VisualNewsContentView), typeof(VisualNewsRenderer))]
namespace News.Forms.Android
{
public class VisualNewsRenderer: NativeRenderer
{
public VisualNewsRenderer () { }
protected override void OnModelChanged (VisualElement oldModel, VisualElement newModel)
{
base.OnModelChanged (oldModel, newModel);
if (newModel != null) {
LinearLayout layout = new LinearLayout (Application.Context);
layout.Orientation = Orientation.Vertical;
TextView tv = new TextView (Application.Context);
tv.Ellipsize = TextUtils.TruncateAt.Middle;
tv.Text = "It´s some kind of..";
EditText et = new EditText (Application.Context);
et.SetTextColor (Graphics.Color.Chocolate);
et.Text = "MAGIC!";
layout.AddView (tv);
layout.AddView (et);
SetNativeControl (layout);
}
}
}
}
But like this you won't be using your ContentView.. I'm sorry, I have nothing better than this..
My solution for customizing compound user control is make a custom control for each control used in compound user control.
For example, which this control:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="News.Forms.VisualNewsContentView">
<ContentView.Content>
<StackLayout>
<Label x:Name="MyLabel" Text="Label"></Label>
<Entry x:Name="MyEntry" Text="Entry"></Entry>
</StackLayout>
</ContentView.Content>
</ContentView>
I will do something like this:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:CustomControls="clr-namespace:App.CustomControls;assembly=App" x:Class="News.Forms.VisualNewsContentView">
<ContentView.Content>
<CustomControls:StackLayout>
<CustomControls:Label x:Name="MyLabel" Text="Label"></CustomControls:Label>
<CustomControls:Entry x:Name="MyEntry" Text="Entry"></CustomControls:Entry>
</CustomControls:StackLayout>
</ContentView.Content>
</ContentView>
Example class for CustomControls:StackLayout is:
(in StackLayout.cs)
using Xamarin.Forms;
namespace App.CustomControls
{
public class StackLayout : Xamarin.Forms.StackLayout
{
}
}
(in StackLayoutRenderer.cs for android project)
[assembly: ExportRenderer(typeof(App.CustomControls.StackLayout), typeof(App.Droid.CustomRenderers.StackLayoutRenderer))]
namespace App.Droid.CustomRenderers.MapView
{
public class StackLayoutRenderer : ViewRenderer<StackLayout, Android.Widget.LinearLayout>
{
protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
{
base.OnElementChanged(e);
}
}
}

Resources