0
votes

I'm starting my first Xamarin Forms application - little more than Hello World at the moment - however I need to be able to Center the text in the title bar. I'm using a MasterDetailPage which has a ContentPage as Master and a NavigationPage as Detail. From the screen shot below I'd like to be able to center 'Home'.

I've tried markup like the answer from Changing Actionbar Tab Text Size in AppCompact Theme however nothing seems to affect the position of the text. I also tried a custom renderer, however that didn't work.

Has anyone been able to do this?

Updating my question with some code. My MasterDeatil.cs:

public class MasterDetail : MasterDetailPage
    {
        Master master;

        public MasterDetail()
        {
            master = new Master();

            Master = master;
            Detail = new NavigationPage(new Home());

            master.ListView.ItemSelected += ListView_ItemSelected;

            ToolbarItem cart = new ToolbarItem()
            {
                Text = "Test",
                Icon = "shoppingcart.png"
            };

            cart.Clicked += async (object sender, System.EventArgs e) =>
            {
                await DisplayAlert("Done", "Msg", "Ok", "Can");
            };

            ToolbarItems.Add(cart);
        }

        private void ListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
        {
            MasterItem item = e.SelectedItem as MasterItem;

            if (item != null)
            {
                Detail = new NavigationPage((Page)Activator.CreateInstance(item.TargetType));
                master.ListView.SelectedItem = null;
                IsPresented = false;
            }
        }
    }

Code for Master.cs:

public class MasterDetail : MasterDetailPage
    {
        Master master;

        public MasterDetail()
        {
            master = new Master();

            Master = master;
            Detail = new NavigationPage(new Home());

            master.ListView.ItemSelected += ListView_ItemSelected;

            ToolbarItem cart = new ToolbarItem()
            {
                Text = "Test",
                Icon = "shoppingcart.png"
            };

            cart.Clicked += async (object sender, System.EventArgs e) =>
            {
                await DisplayAlert("Done", "Msg", "Ok", "Can");
            };

            ToolbarItems.Add(cart);
        }

        private void ListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
        {
            MasterItem item = e.SelectedItem as MasterItem;

            if (item != null)
            {
                Detail = new NavigationPage((Page)Activator.CreateInstance(item.TargetType));
                master.ListView.SelectedItem = null;
                IsPresented = false;
            }
        }
    }

Code for Detail.cs:

public class Detail : ContentPage
    {
        public Detail()
        {
            Title = "Shaves2U";
            Content = new StackLayout
            {
                Children = {
                    new Label {
                        Text = "Detail data goes here",
                        HorizontalOptions = LayoutOptions.Center,
                        VerticalOptions = LayoutOptions.CenterAndExpand
                    }
                }
            };
        }
    }

style.xml:

<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <!-- Base theme applied no matter what API -->
  <style name="MainTheme" parent="Theme.AppCompat">
    <!--If you are using revision 22.1 please use just windowNoTitle. Without android:-->
    <item name="windowNoTitle">true</item>
    <!--We will be using the toolbar so no need to show ActionBar-->
    <item name="windowActionBar">false</item>
    <!-- Set theme colors from http://www.google.com/design/spec/style/color.html#color-color-palette -->
    <!-- colorPrimary is used for the default action bar background -->
    <item name="windowActionModeOverlay">true</item>

    <item name="android:datePickerDialogTheme">@style/AppCompatDialogStyle</item>
  </style>

  <style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog">
    <item name="colorAccent">#FF4081</item>
  </style>
</resources>

I have tried the following style.xml:

<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <!-- Base theme applied no matter what API -->
  <style name="MainTheme" parent="Theme.AppCompat">
    <!--If you are using revision 22.1 please use just windowNoTitle. Without android:-->
    <item name="windowNoTitle">true</item>
    <!--We will be using the toolbar so no need to show ActionBar-->
    <item name="windowActionBar">false</item>
    <!-- Set theme colors from http://www.google.com/design/spec/style/color.html#color-color-palette -->
    <!-- colorPrimary is used for the default action bar background -->
    <item name="windowActionModeOverlay">true</item>

    <item name="android:datePickerDialogTheme">@style/AppCompatDialogStyle</item>
    <item name="android:actionBarTabTextStyle">@style/CustomTab</item>
  </style>

  <style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog">
    <item name="colorAccent">#FF4081</item>
  </style>
  <style name="CustomTab" parent="@android:style/Widget.AppCompat.ActionBar.TabText">
        <item name="android:gravity">center</item>
    </style>
</resources>

I'm hoping I've just got the XML wrong

enter image description here

2
Could you include some code of how you have constructed your MasterDetailPage? With just a screenshot attached to your question, it is difficult to know how we are to assist you. Also, please do note that Xamarin.Forms uses the default behaviour of the respective platforms. When it comes to the title of a master-detail page for Android, the title is normally always left aligned.Demitrian
@Demitrian, I've updated the question with some source codemarkpirvine
@YuraBabiy, thanks for the reply - however I have read that post and it didn't helpmarkpirvine
Have you solved this case? I've investigated this issue for some days, only I can have a workaround, and this method is not quite elegant to me...The biggest problem I'm facing now is that I can't get the rendered ToolBar's context, I used MainActivity as its context, but seems to be a wrong one.Grace Feng

2 Answers

0
votes

Here I will post my research on this question, so can we keep on digging this issue and avoid making my mistakes again.

Please remember the two important conditions for this case: 1. MasterDetailPage control for mater/detail layout; 2. ContentPage control for detail pages' layout.

  1. The Title is not the title of the Toolbar in android project, it's the title of ContentPage. You can check this by commenting out the code ToolbarResource = Resource.Layout.Toolbar; in the MainActivity's OnCreate method, or by removing the value of Title for each ContentPage. So modifying the style of Toolbar will never work here.

  2. Based on the first result, the idea comes nature that we can remove the the value of Title for each ContentPage, and together modifying the layout of Toolbar like this.

Toolbar.axml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?attr/colorPrimary"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    android:popupTheme="@style/ThemeOverlay.AppCompat.Light">
    <TextView
        android:id="@+id/mytitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_gravity="center"
        android:text="11111"
        android:textColor="@android:color/white"
        android:textSize="20sp"
        android:textStyle="bold" />
</android.support.v7.widget.Toolbar>

It looks well, the title is in the center, but now it comes the second question: how to change the title text when the detail page is selected.

  1. To solve the second problem, I create a customer render for both 3 detail ContentPage and add assemblies for this render.

For the part of custom ContentPage render, you can refer to Customizing a ContentPage, I added assemblies like this:

[assembly: ExportRenderer(typeof(ContactsPage), typeof(MyPageRenderer))]
[assembly: ExportRenderer(typeof(ReminderPage), typeof(MyPageRenderer))]
[assembly: ExportRenderer(typeof(TodoListPage), typeof(MyPageRenderer))]

It solve the problem, we can get the ContentPage's name in the OnElementChanged method like this:

var pageName = e.NewElement.GetType().FullName; 

Seems OK and now comes to our last question: How to set the page name to the title of Toolbar, and this is the exact key problem I'm stick now.

In the MainActivity I coded like this:

var factory = LayoutInflater.From(this);
var bar = factory.Inflate(ToolbarResource, null);
var tv = (TextView)bar.FindViewById(Resource.Id.mytitle);
tv.SetText("sdff", TextView.BufferType.Normal);

It can find the TextView, and the text of TextView is "11111" which is set in xml for test, but the new Text can never be set successfully.

Firstly I thought the UI operation should be done in the UIThread, so I put the code in RunOnUiThread or in new Handler(Looper.MainLooper), but still does it not work. Then I think maybe I get the wrong Toolbar due to the wrong Context: var factory = LayoutInflater.From(this);, but I could never find the right context here. I also tried to find the fragments since the source code of MasterDetailPage used Fragment, all failed.

Then I begin to think, why not we create our toolbar, not use ToolbarResource = Resource.Layout.Toolbar; to create the toolbar. But by check the source code of FormsAppCompatActivity, I found this code:

if (ToolbarResource != 0)
{
    bar = LayoutInflater.Inflate(ToolbarResource, null).JavaCast<AToolbar>();
    if (bar == null)
        throw new InvalidOperationException("ToolbarResource must be set to a Android.Support.V7.Widget.Toolbar");
}
else
    bar = new AToolbar(this);

SetSupportActionBar(bar);

I will never success to set toolbar by our self when our MainActivity is inherited from FormsAppCompatActivity.

Finally I think maybe I can change the MainActivity inherit from global::Xamarin.Forms.Platform.Android.FormsApplicationActivity instead from global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, so can we set the Toolbar by our self, still failed, it will throw a NullReferenceException at the line LoadApplication(new App()); and I'm in a dead end again.

So comes to my workaround, create a custom render for MasterDetailPage, and in the OnElementChanged, create a TextView or something and lay this control in the top center, change the text also from the custom render of ContentPage.

But I would call this a stupid, stubborn idea rather then a workaround, cause by doing all these lot of work, why not build our own view using the native android control instead of using xamarin's MasterDetailPage? Unless we can find a way to set the Text of original Toolbar, creating our own master detail view for android app should also be a workaround, a better one I think.

0
votes

I know this is a pretty old question, I found it when looking for other stuff. The solution is pretty simple in Xamarin Forms. Just add a NavigationPage.TitleView tag to your ContentPage. This way you can add whatever you want with any style to the navigation bar:

ContentPage

<NavigationPage.TitleView>
    <Label Text="Centered Title" Style="{StaticResource TitleStyle}" />
</NavigationPage.TitleView>

Styles can be global (ie: in App.xaml):

<Style TargetType="Label" x:Key="TitleStyle">
  <Setter Property="TextColor" Value="WhiteSmoke" />
  <Setter Property="FontSize" Value="Medium" />
  <Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>