在最新版本之一中,Xamarin.Forms添加了将工具栏放置在底部(ToolBarPlacement
)的可能性,并且通过设置NavigationPage
上的属性BarBackgroundColor
可以更改工具栏的背景颜色。
不幸的是,当工具栏被拆分时(这是Windows 10移动版的默认设置或ToolbarPlacement
在底部时),两个栏具有相同的背景颜色。
在我的应用程序中,我希望实现顶部栏(带有标题和汉堡菜单)具有系统的主题色,底部栏(带有命令和浮出控件)为灰色,因为许多系统应用程序也使用此组合(例如 Windows 10 移动版上的邮件或日历)。 但是,如果不接触Xamarin.Forms中的核心实现,我就无法弄清楚如何做到这一点。我已经尝试了自定义NavigationPageRenderer
和自定义PageRenderer
,但许多相关字段是私有的、密封的或内部的,或者正在访问内部接口。
两个条形的背景颜色似乎绑定到同一属性,因为在 Visual Studio 的 Live XAML 树视图中更改一个条形的背景也会更改另一个条形的颜色。
有关如何实现所需外观的任何帮助将不胜感激。
最后,我达到了预期的结果。
其中一个问题是我的根页面是一个MasterDetailPage
,所以我必须创建一个MasterDetailPageRenderer
。此外,我假设 Xamarin 将使用实际的 UWP 页面的TopAppBar
和BottomAppBar
属性。事实并非如此。
使用以下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;
}
}