-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Conversation
Hey thank you! Unfortunately I am not in a position to actually run this for a couple days. I would really appreciate some screenshots however just so I can see how it looks. I will give the code a detailed review tomorrow, however a quick glance looks good. |
|
||
if (width > 0 && height > 0) | ||
((IPageController)Element).ContainerArea = new Rectangle(0, 0, _relativeLayout.MeasuredWidth, _relativeLayout.GetChildAt(0).MeasuredHeight); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without having run it or really grokked everything in here yet this seems wrong. The ContainerArea should be the region of the TabbedPage that does NOT contain the tabs itself. So in general this would be 0, 0, r - l, b - t - bottomTabBarHeight
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's absolutely right. I was doing a bit more test and trying to understand that code a bit better and I realized the same. I'll push a better version, along with some screenshots
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(the OnLayout override is the most mysterious to me right now)
I have a few questions on how to handle the colors for icons and text, in terms of selected/not selected/disabled. |
I'd avoid using I'd expose this property with a name like |
While we are exposing it using the same element (tabbedpage), tabs and bottomnavigation view behave quite differently. My initial implementation was actually using a different control, but then I saw the enhancement proposal and I merged my implementation inside the tabbedpage, which simplified things a lot. |
else if (newTextColor.IsDefault && _defaultColor.HasValue && currentColor != _defaultColor) | ||
_tabLayout.SetTabTextColors(_defaultColor.Value, _defaultColor.Value); | ||
int selectedIndex = item.Order; | ||
if (_bottomNavigationView.SelectedItemId != item.Order && Element.Children.Count > selectedIndex && selectedIndex >= 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think the first condition is meant to be _bottomNavigationView.SelectedItemId != item.ItemId
using Android.Views; | ||
using Xamarin.Forms.Internals; | ||
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific; | ||
|
||
namespace Xamarin.Forms.Platform.Android.AppCompat | ||
{ | ||
public class TabbedPageRenderer : VisualElementRenderer<TabbedPage>, TabLayout.IOnTabSelectedListener, ViewPager.IOnPageChangeListener, IManageFragments | ||
public class TabbedPageRenderer : VisualElementRenderer<TabbedPage>, TabLayout.IOnTabSelectedListener, ViewPager.IOnPageChangeListener, IManageFragments, BottomNavigationView.IOnNavigationItemSelectedListener |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest making modifications to OnPagePropertyChanged to handle when a page's title changes (e.g. via data binding). The current renderer already does this when the native element is a TabLayout. I think the code you'd need for the BottomNavigationView is something like
var page = (Page)sender;
var index = Element.Children.IndexOf(page);
var tab = _bottomNavigationView.Menu.GetItem(index);
tab.SetTitle(page.Title);
i'm interested in this being officially supported by Xamarin.Forms as well. Added some comments/suggestions to the PR |
retriggering builds |
Can you please update the docs? There is a script to do it. Without the update we wont get CI results |
I'm off for a couple of days, will do some work over the weekend
|
{ | ||
public enum TabsPlacement | ||
{ | ||
/// <summary> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please dont use inline docs, they wont get properly updated. Use the mdoc files instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I copy/pasted from the WindowsSpecific\ToolbarPlacement.cs file. Anyway, should I just delete the comments? Also, I couldn't find the mdoc files :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mikescandy yea just delete the comments.. Since you rebased with master you won't need to run the docs file that generates docs anymore. Just make sure the API Changes part of the PR has everything
|
||
int currentColor = _tabLayout.TabTextColors.DefaultColor; | ||
if (!_defaultColor.HasValue) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spaces => Tabs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in next commit.
} | ||
|
||
base.OnLayout(changed, l, t, r, b); | ||
base.OnLayout(changed, l, t, r, b); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spaces => Tabs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in next commit.
viewPagerParams.AddRule(AWidget.LayoutRules.Above, _bottomNavigationView.Id); | ||
|
||
FormsViewPager pager = | ||
_viewPager = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this code be moved to a general CreateFormsViewPager method? Then both the bottom and top navbar would just call that? The way these new up looks to be the same between the two
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in next commit.
@@ -0,0 +1,17 @@ | |||
namespace Xamarin.Forms.PlatformConfiguration.AndroidSpecific | |||
{ | |||
public enum TabsPlacement |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add Default here as well just in case Android changes what Default means in the future
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in next commit. I don't think this has an Android equivalent really, but agree it's right to put a Default here.
|
||
public static void SetTabsPlacement(BindableObject element, TabsPlacement value) | ||
{ | ||
element.SetValue(TabsPlacementProperty, value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we throw an explicit exception here if the user tries to toggle between Top <-> Bottom after the page has already been rendered? This way it's clear to the user that changing the placement after it's been realized isn't supported
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Help here: as this is an enum, my understanding is that this will always have a value (Default), so I probably should not throw on the first value change. Where should I track the value change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you rebase to master you'll see a property on BindableObject now that lets you test if something has been changed from the default
https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Core/BindableObject.cs#L55
Which should be sufficient
My other thought would be to add a Changing event to the bindable property. Then inside the Tab Renderer once the layout call happens it could set a local value indicating this is how it is on the layout. The changing event could then check that... But that's probably overkill and just checking IsSet should be enough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try the rebase. I'm not the best at using GIT, let's see what happens...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be done. Please check if the exception message makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mikescandy Hey mike, looks like your pretty much done with this, when can we mortals expect this as a nuget-package? I suppose its going into pre-release.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error message seems to work just remember to set Default as the defaultValue
public static readonly BindableProperty TabsPlacementProperty =
BindableProperty.Create("TabsPlacement", typeof(TabsPlacement),
typeof(TabbedPage), TabsPlacement.Top);
And then at this point Default and Top will just cause the same behavior
@@ -170,6 +170,69 @@ public void TestReorderTabs () | |||
#endif | |||
} | |||
|
|||
[Preserve(AllMembers = true)] | |||
[Issue(IssueTracker.Github, 1675, "Android: TabbedPage: Bottom Tab Bar", PlatformAffected.Android)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add some Android specific UITests as well modeled after
public class TabbedPageTests : TestTabbedPage
So that we can generate some screen shots of the bottom nav bar and just have some automated ui tests for this
bottomNavigationView.Menu.Add(0, i, i, child.Title).SetEnabled(child.IsEnabled); | ||
} | ||
|
||
if (Element.Children.Count > 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because of how this is implemented if I'm not on the first tab then when I remove a page it'll just navigate me back to the first page. Can this be setup to just remain on the Current Page if that page wasn't removed? Something like
for (var i = 0; i < Element.Children.Count; i++)
{
Page child = Element.Children[i];
var menuItem = bottomNavigationView.Menu.Add(0, i, i, child.Title).SetEnabled(child.IsEnabled);
if(Element.CurrentPage == child)
{
bottomNavigationView.SelectedItemId = menuItem.ItemId;
}
}
if (Element.Children.Count > 0)
{
if(Element.CurrentPage == null || !Element.Children.Contains(Element.CurrentPage))
Element.CurrentPage = Element.Children[0];
}
Also is it necessary to clear out and rebuild the whole menu each time an item is removed/added?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That will do. Not sure how not to rebuild the menu. I should keep some kind of dictionary linking menu item ids and child pages... not really sure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the method is called by OnChildrenCollectionChanged could the NotifyCollectionChangedEventArgs be used for the index of the removed page?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it.
int newTextColorArgb = newTextColor.ToAndroid().ToArgb(); | ||
var color = newTextColor.ToAndroid(); | ||
color.A = 128; | ||
int newTextColorArgbFade = color.ToArgb(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this do? It doesn't seem like this is used later for anything
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Garbage. Also, renaming color -> semiTransparentColor as it's more meaningful and explains what I'm doing there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mikescandy sounds good
I'm also thinking we should either remove setting the ItemIconTintList or add a platform property BarIconTintColor that can be applied to either AppBar. If setting that Tint Color on a top app bar is tricky though maybe just have BottomBarIconTintColor
if (!newTextColor.IsDefault && currentColor != newTextColorArgb) | ||
{ | ||
_bottomNavigationView.ItemTextColor = new ColorStateList(new[] { sChecked, sDefault }, new[] { newTextColorArgb, color }); | ||
_bottomNavigationView.ItemIconTintList = new ColorStateList(new[] { sChecked, sDefault }, new[] { newTextColorArgb, color }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want the BarTextColor to also set the Tint? Can we make the Tint Color a different settable property? Then we could also try applying said tint setting to the top bar as well
hey @mikescandy you need to rebase and remove docs, it's not needed anymore. thanks |
* Adding bottom navigation support to tabbed page
* Adding bottom navigation support to tabbed page * Adding a bottom navigation page to the gallery * Set the default behavior to false to avoid introducing a breaking change * Fixing onlayout, handling collection change and improving color management
Renaming semi transparent color variable, throw when changing tabs placement after setting it
build --uitests |
Test failure is being misreported. All tests ran fine in appcenter |
Hello, I am using the tool bar placement function to set tabs at the bottom of the screen, but I noticed that if we have more than 3 tabs, then we don't see the titles anymore and the selected icon kind of pushes the other icons away. I'd like to know if there is a way to deactivate this behavior and have all titles showing up and the unselected icons not moving at all? Thank you for your help. |
I like to know the above question too... |
@hunii @Fabone248 AFAIK you can currently only do this by adding a custom renderer. See gist here: https://gist.github.com/LynoDesu/64904b6d143892cf14a60a32798a36bb If you have more questions you can also read through #1675 |
@Roshek Thank you for your reply, I will have a look :) |
Description of Change
Adding a flag allowing a tabbed page to be rendered as a Bottom Navigation view on Android. Add the ability to set the tint color of unselected and selected items.
Bugs Fixed
fixes #1675
API Changes
Added:
Allowed the user to define there own ColorStateList relationship as they pertain to the Tabs
PR Checklist