我想为Xamarin应用程序菜单的两个部分添加渐变。我要渐变的地方标有“这里”-现在我只是在ToolBar之后...
为了尝试这一点,我创建了以下类
public class GradientHeaderNavigationPage : NavigationPage
{
public GradientHeaderNavigationPage() { }
public GradientHeaderNavigationPage(Page root) : base(root) { }
public static readonly BindableProperty LeftColorProperty =
BindableProperty.Create(propertyName: nameof(LeftColor),
returnType: typeof(Color),
declaringType: typeof(GradientHeaderNavigationPage),
defaultValue: Color.FromHex("#92CD8C")); //Color.Accent);
public static readonly BindableProperty RightColorProperty =
BindableProperty.Create(propertyName: nameof(RightColor),
returnType: typeof(Color),
declaringType: typeof(GradientHeaderNavigationPage),
defaultValue: Color.FromHex("#17AEC6")); //Color.Accent);
public Color LeftColor
{
get { return (Color)GetValue(LeftColorProperty); }
set { SetValue(LeftColorProperty, value); }
}
public Color RightColor
{
get { return (Color)GetValue(RightColorProperty); }
set { SetValue(RightColorProperty, value); }
}
}
然后用于Android(我们稍后可能会担心iOS)我添加了以下自定义渲染器
[assembly: ExportRenderer(typeof(GradientHeaderNavigationPage), typeof(GradientHeaderNavigationRenderer))]
namespace Drax.Droid.Renderers
{
public class GradientHeaderNavigationRenderer : NavigationRenderer
{
public GradientHeaderNavigationRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<NavigationPage> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null)
return;
var control = (GradientHeaderNavigationPage)Element;
var context = (MainActivity)Context;
context.ActionBar.SetBackgroundDrawable(
new GradientDrawable(GradientDrawable.Orientation.RightLeft,
new int[] { control.RightColor.ToAndroid(), control.LeftColor.ToAndroid() }));
}
}
}
并将文件/Resources/drawable
添加到gradient_header.xml
文件夹
<?xml version="1.0" encoding="utf-8" ?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<gradient
android:angle="180"
android:startColor="#92CD8C"
android:endColor="#17AEC6"
android:type="linear" />
</shape>
并且在/Resources/layout/ToolBar.axml
中我添加了android:background="@drawable/header_gradient"
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/header_gradient"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
现在,在我的App.cs文件中(我将棱镜用于MVVM)
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace Drax
{
public partial class App : PrismApplication
{
public App(IPlatformInitializer initializer) : base(initializer) { }
protected override async void OnInitialized()
{
try
{
InitializeComponent();
var result = await NavigationService.NavigateAsync(
new Uri("/DraxMasterDetailPage/NavigationPage/MapPage"));
if (!result.Success)
SetMainPageFromException(result.Exception);
}
catch (Exception e)
{
Console.WriteLine($"Android DEBUG:: {e.Message}");
}
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
RegisterServices(containerRegistry);
RegisterViews(containerRegistry);
}
private void RegisterServices(IContainerRegistry containerRegistry)
{
containerRegistry.Register<ILoggerFacade, Services.DebugLogger>();
}
private void RegisterViews(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<NavigationPage>();
containerRegistry.RegisterForNavigation<DraxMasterDetailPage>();
containerRegistry.RegisterForNavigation<MapPage>();
}
private void SetMainPageFromException(Exception ex)
{
var layout = new StackLayout
{
Padding = new Thickness(40)
};
layout.Children.Add(new Label
{
Text = ex?.GetType()?.Name ?? "Unknown Error encountered",
FontAttributes = FontAttributes.Bold,
HorizontalOptions = LayoutOptions.Center
});
layout.Children.Add(new ScrollView
{
Content = new Label
{
Text = $"{ex}",
LineBreakMode = LineBreakMode.WordWrap
}
});
MainPage = new ContentPage
{
Content = layout
};
}
}
}
我的DraxMasterDetailPage
为
<MasterDetailPage x:Class="Drax.Views.DraxMasterDetailPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:Controls="clr-namespace:Drax.Controls">
<MasterDetailPage.Master>
<NavigationPage Title="Drax">
<x:Arguments>
<ContentPage Title="Menu">
<StackLayout Padding="40">
</StackLayout>
</ContentPage>
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Master>
</MasterDetailPage>
我尝试将NavigationPage
更改为GradientHeaderNavigationPage
,但这会引发
System.NullReferenceException:对象引用未设置为对象的实例。
在Adroid渲染器的这一行
context.ActionBar.SetBackgroundDrawable(
new GradientDrawable(GradientDrawable.Orientation.RightLeft,
new int[] { control.RightColor.ToAndroid(), control.LeftColor.ToAndroid() }));
ActionBar
为空。
如何修改此代码以显示渐变工具栏?
答案 0 :(得分:1)
您已通过gradient_header.xml
和ToolBar.axml
更改了工具栏的背景。这意味着整个应用程序的工具栏已更改。您可以注释掉Naviagtion渲染器以查看效果。
如果要使用代码进行调整,则应使用ContentPage
的自定义渲染器,而不要使用NavigationPage
的渲染器。
首先,使用MainActivity
中的代码定义一些方法来找到工具栏:
private static MainActivity instance;
public static View RootFindViewById<T>(int id) where T : View
{
return instance.FindViewById<T>(id);
}
public MainActivity()
{
instance = this;
}
然后您可以动态更改工具栏的背景:
[assembly: ExportRenderer(typeof(ContentPage), typeof(CustomPageRenderer))]
namespace PrismDemo.Droid
{
public class CustomPageRenderer : PageRenderer
{
public CustomPageRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
var toolbar = MainActivity.RootFindViewById<Toolbar>(Resource.Id.toolbar);
if (toolbar == null) return;
toolbar.SetBackground(new GradientDrawable(GradientDrawable.Orientation.RightLeft,
new int[] { Color.Red.ToAndroid(), Color.Blue.ToAndroid() }));
}
}
}
在这里,我使用了硬代码来设置颜色,并将自定义渲染器应用于所有内容页面。您可以将其调整为指定的页面并在其中定义可绑定颜色的属性。
或者,我认为您可以利用MessagingCenter来触发工具栏调整代码。
答案 1 :(得分:1)
对我来说,这适用于工具栏:
var toolbar = FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);
if (toolbar == null)
return;
但是,它在OnLayout
内部。我目前还不确定,但是很可能您只能在那里找到工具栏。