Reputation: 781
I'm looking to remove the text from the tabs (and vertically center the icon) on a TabbedPage in my Xamarin Forms app, like this:
I achieved this on iOS by making the TextColor clear and shifting the image down in a custom renderer:
public override void ViewWillLayoutSubviews()
{
base.ViewWillLayoutSubviews();
if (TabBar != null)
{
foreach (var item in TabBar.Items)
{
item.ImageInsets = new UIEdgeInsets(5, 0, -5, 0);
}
}
}
Right now my tabs on Android look like this:
If it matters, it's been set it to the bottom of the screen like so:
public MyTabbedPage()
{
On<Android>().SetToolbarPlacement(ToolbarPlacement.Bottom);
}
How can I remove the text and center the icon on the Android tab bar? I've tried playing around with the styles and axml but I'm not getting anywhere at all.
Thanks!
Upvotes: 1
Views: 3332
Reputation: 17402
There might be some easy way to do that from shared project itself. Here use customrenderer to get it work. First create xaml file in Layout folder in Android project custom_tab_layout.xaml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:orientation="vertical">
<ImageView
android:id="@+id/icon"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp" />
</LinearLayout>
Give height, margins & Color according your preference.
Now add .CS file in your android project say MyTabbedPageRenderer
[assembly: ExportRenderer(typeof(MyTabbedPage), typeof(MyTabbedPageRenderer))]
namespace Myproject.Droid
{
public class MyTabbedPageRenderer : TabbedPageRenderer
{
public MyTabbedPageRenderer(Context context) : base(context)
{
}
protected override void SetTabIcon(TabLayout.Tab tab, FileImageSource icon)
{
base.SetTabIcon(tab, icon);
tab.SetCustomView(Resource.Layout.custom_tab_layout);
var imageview = tab.CustomView.FindViewById<ImageView>(Resource.Id.icon);
imageview.SetBackgroundDrawable(tab.Icon);
}
}
}
The first line of code ExportRenderer(typeof(MyTabbedPage)
have file MyTabbedPage
is your shared project class as you mentioned in your question. In custom_tab_layout.xaml file you can add TextView too & can give text as "" in custom renderer to give a better position to your icons.
Hope it help you.
Upvotes: 1
Reputation: 3074
If anyone is looking for the iOS counterpart to @Alex West's code.
using RedSwipe.iOS;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(TabbedPage), typeof(MyTabbedPageRenderer))]
namespace RedSwipe.iOS
{
public class MyTabbedPageRenderer : TabbedRenderer
{
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
foreach (UITabBarItem item in this.TabBar.Items)
{
item.ImageInsets = new UIEdgeInsets(6, 0, -6, 0);
}
}
}
}
Upvotes: 2
Reputation: 71
Like wrote Alex West, but fix magic padding to this
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams)tab.GetChildAt(0).LayoutParameters;
lp.Height = LayoutParams.MatchParent;
lp.Gravity = GravityFlags.Center;
Also, optionally you can fix GetAllChildView()
method like that:
List<T> GetAllChildViews<T>(Android.Views.View view) where T: Android.Views.View
{
if (!(view is ViewGroup group))
{
if(view is T)
{
return new List<T> { view as T };
}
return new List<T>();
}
var result = new List<T>();
for (int i = 0; i < group.ChildCount; i++)
{
var child = group.GetChildAt(i);
var childList = new List<T>();
if(child is T item)
{
childList.Add(item);
}
else
{
childList.AddRange(GetAllChildViews<T>(child));
}
result.AddRange(childList);
}
return result.Distinct().ToList();
}
And call it like: GetAllChildViews<BottomNavigationMenuView>(ViewGroup)
Upvotes: 1
Reputation: 781
In the end I pieced together a solution similar to how I did iOS, using this renderer:
[assembly: ExportRenderer(typeof(TabbedPage), typeof(MyTabbedPageRenderer ))]
namespace MyApp.Droid.Renderers
{
public class MyTabbedPageRenderer : TabbedPageRenderer
{
public MyTabbedPageRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
{
base.OnElementChanged(e);
var childViews = GetAllChildViews(ViewGroup);
var scale = Resources.DisplayMetrics.Density;
var paddingDp = 9;
var dpAsPixels = (int)(paddingDp * scale + 0.5f);
foreach (var childView in childViews)
{
if (childView is BottomNavigationItemView tab)
{
tab.SetPadding(tab.PaddingLeft, dpAsPixels, tab.PaddingRight, tab.PaddingBottom);
}
else if (childView is TextView textView)
{
textView.SetTextColor(Android.Graphics.Color.Transparent);
}
}
}
List<Android.Views.View> GetAllChildViews(Android.Views.View view)
{
if (!(view is ViewGroup group))
{
return new List<Android.Views.View> { view };
}
var result = new List<Android.Views.View>();
for (int i = 0; i < group.ChildCount; i++)
{
var child = group.GetChildAt(i);
var childList = new List<Android.Views.View> { child };
childList.AddRange(GetAllChildViews(child));
result.AddRange(childList);
}
return result.Distinct().ToList();
}
}
}
This achieves the desired result (centered icon with no text). Haven't tested it on different device sizes yet, so that magic number 9dp might not work universally.
Upvotes: 2