如何在 Xamarin.Forms 中拥有不同颜色的顶部和底部工具栏



在最新版本之一中,Xamarin.Forms添加了将工具栏放置在底部(ToolBarPlacement)的可能性,并且通过设置NavigationPage上的属性BarBackgroundColor可以更改工具栏的背景颜色。

不幸的是,当工具栏被拆分时(这是Windows 10移动版的默认设置或ToolbarPlacement在底部时),两个栏具有相同的背景颜色。

在我的应用程序中,我希望实现顶部栏(带有标题和汉堡菜单)具有系统的主题色,底部栏(带有命令和浮出控件)为灰色,因为许多系统应用程序也使用此组合(例如 Windows 10 移动版上的邮件或日历)。 但是,如果不接触Xamarin.Forms中的核心实现,我就无法弄清楚如何做到这一点。我已经尝试了自定义NavigationPageRenderer和自定义PageRenderer,但许多相关字段是私有的、密封的或内部的,或者正在访问内部接口。

两个条形的背景颜色似乎绑定到同一属性,因为在 Visual Studio 的 Live XAML 树视图中更改一个条形的背景也会更改另一个条形的颜色。

有关如何实现所需外观的任何帮助将不胜感激。

最后,我达到了预期的结果。

其中一个问题是我的根页面是一个MasterDetailPage,所以我必须创建一个MasterDetailPageRenderer。此外,我假设 Xamarin 将使用实际的 UWP 页面的TopAppBarBottomAppBar属性。事实并非如此。

使用以下MasterDetailPageRenderer顶部栏(带有汉堡菜单按钮和标题)为绿色,而底部栏保持默认灰色(基本上渲染器只是删除表示顶部栏的 StackPanel 的Background绑定并将其设置为绿色)。一个问题是,FindName 和 FindByName 方法不起作用(总是返回 null),所以我不得不使用 VisualTreeHelper 来滚动我自己的实现。

[assembly: ExportRenderer(typeof(MasterDetailPage), typeof(CustomMasterDetailPageRender))]
public class CustomMasterDetailPageRender : MasterDetailPageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<MasterDetailPage> e)
{
base.OnElementChanged(e);
if (Element != null)
{                
Element.Appearing += Element_Appearing;                         
}
}
private void Element_Appearing(object sender, EventArgs e)
{
(sender as MasterDetailPage).Appearing -= Element_Appearing;
if (Control != null)
{
var topBarArea = FindElementByName(Control, "TopCommandBarArea");
if (topBarArea != null)
{
var topContent = FindElementByType<StackPanel>(topBarArea);
if (topContent != null)
{
topContent.Background = new SolidColorBrush(Colors.Green);
}
}          
}
}
static DependencyObject FindElementByName(DependencyObject parent, string name)
{            
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
var sub = VisualTreeHelper.GetChild(parent, i);
if (sub is FrameworkElement)
{
if (((FrameworkElement)sub).Name == name)
{
return sub;
}
}
var r = FindElementByName(sub, name);
if (r != null)
return r;
}
return null;
}
static T FindElementByType<T>(DependencyObject parent)
where T: DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
var sub = VisualTreeHelper.GetChild(parent, i);
if (sub is T)
{
return (T)sub;
}
var r = FindElementByType<T>(sub);
if (r != null)
return r;
}
return null;
}
}

最新更新