Maui
Maui copied to clipboard
[Proposal] Android-Specific Navigation Bar Effect
NavigationBarEffect
- [x] Proposed
- [ ] Prototype: Not Started
- [ ] Implementation: Not Started
- [ ] iOS Support
- [ ] Android Support
- [ ] macOS Support
- [ ] Windows Support
- [ ] Unit Tests: Not Started
- [ ] Sample: Not Started
- [ ] Documentation: Not Started
Summary
Android-specific implementation allowing the user to customize the Navigation Bar
Detailed Design
NavigationBarEffect.cs
namespace Xamarin.CommunityToolkit.PlatformConfiguration.AndroidSpecific
{
[Preserve(Conditional = true)]
public static class NavigationBarEffect
{
static NavigationBarEffect()
{
#region Required work-around to prevent linker from removing the platform-specific implementation
#if __ANDROID__
if (System.DateTime.Now.Ticks < 0)
_ = new PlatformNavigationBarEffect();
#endif
#endregion
}
public static readonly BindableProperty ColorProperty = BindableProperty.CreateAttached(
"Color", typeof(Color), typeof(NavigationBarEffect), Color.Default, propertyChanged: TryGenerateEffect);
public static readonly BindableProperty StyleProperty = BindableProperty.CreateAttached(
"Style", typeof(NavigationBarStyle), typeof(NavigationBarEffect), NavigationBarStyle.Default, propertyChanged: TryGenerateEffect);
public static Color GetColor(BindableObject bindable) =>
(Color)bindable.GetValue(ColorProperty);
public static void SetColor(BindableObject bindable, Color value) =>
bindable.SetValue(ColorProperty, value);
public static NavigationBarStyle GetStyle(BindableObject bindable) =>
(NavigationBarStyle)bindable.GetValue(StyleProperty);
public static void SetStyle(BindableObject bindable, NavigationBarStyle value) =>
bindable.SetValue(StyleProperty, value);
public static IPlatformElementConfiguration<XFP.Android, FormsElement> SetNavigationBarColor(this IPlatformElementConfiguration<XFP.Android, FormsElement> config, Color color)
{
SetColor(config.Element, color);
return config;
}
public static Color GetNavigationBarColor(this IPlatformElementConfiguration<XFP.Android, FormsElement> config) =>
GetColor(config.Element);
public static IPlatformElementConfiguration<XFP.Android, FormsElement> SetNavigationBarStyle(this IPlatformElementConfiguration<XFP.Android, FormsElement> config, NavigationBarStyle style)
{
SetStyle(config.Element, style);
return config;
}
public static NavigationBarStyle GetNavigationBarStyle(this IPlatformElementConfiguration<XFP.Android, FormsElement> config) =>
GetStyle(config.Element);
static void TryGenerateEffect(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is not FormsElement page)
return;
DetachEffect(page);
AttachEffect(page);
}
static void AttachEffect(FormsElement element)
{
IElementController controller = element;
if (controller is null || controller.EffectIsAttached(EffectIds.NavigationBar))
return;
element.Effects.Add(Effect.Resolve(EffectIds.NavigationBar));
}
static void DetachEffect(FormsElement element)
{
IElementController controller = element;
if (controller is null || !controller.EffectIsAttached(EffectIds.NavigationBar))
return;
var toRemove = element.Effects.FirstOrDefault(e => e.ResolveId == Effect.Resolve(EffectIds.NavigationBar).ResolveId);
if (toRemove != null)
element.Effects.Remove(toRemove);
}
}
}
Usage Syntax
XAML Usage
<Setter Property="droid:NavigationBarEffect.Color" Value="{StaticResource NavBarColor}" />
C# Usage
var navigationPage = new NavigationPage();
NavigationBarEffect.SetColor(navigationPage, Colors.Blue);
On hold, pending results of https://github.com/dotnet/maui/pull/2049
Would like to implement this, in case issue is unblocked
dotnet/maui#2049 is now closed, can we move forward with thins issue?
This is still blocked by #124
Since it seems like https://github.com/CommunityToolkit/Maui/issues/85#issuecomment-1239441230 is getting some traction, could this one be moved forward as well?
@maxkoshevoi we will vote to champion this after the Status bar implementation
Any update? Thanks
@pictos @brminnick What is exactly the status of this issue? Thanks
I don't have any additional information for you than what is already provided.
On the Project Board this Proposal is in the Project Submitted column.
It currently has the https://github.com/CommunityToolkit/Maui/labels/new label.
As noted in our Submitting a New Feature guidelines, the Proposal Submitted column indicates the following:
Once you have a fully fleshed out proposal describing a new feature in syntactic and semantic detail, please open an issue for it, and it will be labeled as a Proposal. The comment thread on the issue can be used to hash out or briefly discuss details of the proposal, as well as pros and cons of adopting it into the .NET MAUI Toolkit. If an issue does not meet the bar of being a full proposal, we may move it to a discussion, so that it can be further matured. Specific open issues or more expansive discussion with a proposal will often warrant opening a side discussion rather than cluttering the comment section on the issue.
It is not actively being worked by any member of the community.
I am inclined to close this Proposal as it overlaps with our existing feature, StatusBarBehavior.
I am inclined to close this Proposal as it overlaps with our existing feature, StatusBarBehavior.
This is different though. Status bar is at the top while the navigation bar is at the bottom (where navigation buttons are). Or do you mean that this functionality can be included in the StatusBarBehavior somehow?
This is different though. Status bar is at the top while the navigation bar is at the bottom (where navigation buttons are).
Thank you for clarifying. I will keep this Proposal open.
Thank you for clarifying. I will keep this Proposal open.
Thank you. Can I move forward with porting it from XCT? There was something blocking that when MCT was under development, but should be no blockers now I think
Thanks Max! I will present this Proposal to the team at our Monthly Standup on Friday: https://www.youtube.com/watch?v=a6LBam_9q-0
Assuming at least 50% of the maintainers approve, we'll move to it Approved and I'll assign it to you 👍
Alright let's get this party started! I think we have all the ingredients to get this going. Thanks for taking this up @maxkoshevoi.
A few things:
- We're going to implement this as a Behavior because effects are not a thing anymore in .NET MAUI. For inspiration look at #617
- This is specific to only Android, I'm not sure if we have anything like that already in the .NET MAUI Toolkit?
- The name is a bit confusing, Brandon thought it was about the navigation bar in the top of the screen. Is there any better name that we can come up with maybe? Is navigation bar really the name that Android has for that bar as well?
- Other than that I think it would be good to keep the API as close as the XCT one as much as possible so transitioning will be easier.
Let me know if there are any issues or questions!
Names of system bars on android:
- status bar: https://developer.android.com/design/ui/mobile/guides/foundations/system-bars#status-bar
- navigation bar: https://developer.android.com/design/ui/mobile/guides/foundations/system-bars#navigation-bar
I do wonder if we should have named StatusBarBehavior as SystemBarBehavior and then have properties for the 2 concepts. Possibly a bit late now though
Anybody working on this? About naming, what is your decision?
@tranb3r @maxkoshevoi expressed interest but I don't think much has happened since then. So as far as I am concerned you're free to take this up.
For naming... BottomNavigationBar so that it's clear its that bottom one? SystemNavigationBar? I'm open to suggestions.
@tranb3r , yes sorry, got unexpectedly busy. You can take this
No problem. I'll try to do it today. Should not be very long, since it's basically copy/paste from StatusBar. About naming: I think SystemNavigationBar is better. It's how android is naming it in the docs. And it avoids confusion with any application navbar (top, bottom, tabs, whatever).
Sounds good to me!
@pictos I can move both properties of the behavior to android specific. But the behavior itself has to be cross-platform, right?
Is this the usage you want?
<Page.Behaviors>
<OnPlatform x:TypeArguments="Behavior">
<On Platform="Android">
<mct:SystemNavigationBarBehavior
android:SystemNavigationBarBehavior.SystemNavigationBarColor="{Binding ...}"
android:SystemNavigationBarBehavior.SystemNavigationBarStyle="{Binding ...}" />
</On>
</OnPlatform>
</Page.Behaviors>
On<Android>().SetSystemNavigationBarColor(Colors.Red);
@tranb3r that shouldn't be Behaviors, but AttachedProperties. Behaviors aren't a good approach for a feature that's available for 1 platform
@tranb3r that shouldn't be Behaviors, but AttachedProperties. Behaviors aren't a good approach for a feature that's available for 1 platform
@jfversluis wrote "We're going to implement this as a Behavior. For inspiration look at Statusbar color". If this is not relevant anymore, maybe you guys should clarify first how you want this feature to be implemented. Then I can work on it.
@tranb3r sorry, for the confusion... The OnPlatform API was implemented as Effect, like all OnPlatform stuff, on XCT, but on .NET MAUI that concept is obsolete and we moved all Effects for the PlatformBehavior API. And this is the first feature like that we will implement here, so we're learning in the path.
Talking about this feature, it's a way to expose a property for a single platform in a shared layer, so in the end, isn't the same, and the PlatformBehavior could not fit very well, because it will hide from users that Behavior will just work for a specific platform...
As I mentioned in the PR, the best solution is to follow how .NET MAUI implements it. I know that could be frustrating, to spend time and be asked to change a go amount of it, so if you want, I can jump in and finish the implementation. I'll do above your PR so the credit is still yours, for taking time to help us
@pictos I understand. No problem. I'm just looking forward for this simple feature to be implemented (and I really do not care about the credit). So please go ahead if you have the time to work on it. It's not a big change anyway. Thanks!
@tranb3r I can jump in or guide you, I'll let you choose what's more fun for you.
For me, since you're doing OSS at your free time, you should choose what is more fun for you
@pictos
Ok, I'm happy to do it, although there is something I do not understand.
Let's assume we implement two AttachedProperties (SystemNavigationBarColor and SystemNavigationBarStyle).
I guess they would be attached to the Page, right?
I easily understand how to create the properties, in android-specific platformConfiguration. This would be similar to what has been done in dotnet maui for UseSafeArea.
However this is not enough. The code needs to react to the properties change. For StatusBarColor this is done in the Behavior, but we said we do not want to use a Behavior for SystemNavigationBar. For UseSafeArea in dotnet maui, this is done in the PageRenderer itself. Where should we put this code in our case?
@pictos Ok, I'm happy to do it, although there is something I do not understand. Let's assume we implement two AttachedProperties (
SystemNavigationBarColorandSystemNavigationBarStyle). I guess they would be attached to thePage, right? I easily understand how to create the properties, in android-specific platformConfiguration. This would be similar to what has been done in dotnet maui for UseSafeArea. However this is not enough. The code needs to react to the properties change. For StatusBarColor this is done in the Behavior, but we said we do not want to use a Behavior for SystemNavigationBar. For UseSafeArea in dotnet maui, this is done in thePageRendereritself. Where should we put this code in our case?
TBH I don't know, we need to test a couple of approaches, but my first attempt will be to use the Handlers mappings to attach the behavior that we want for on the propertiesChanges that we want... Another possibility, (that I don't like too much) is to use the PropertyChanged on the attached property to listen for the changes that will happen on Page