创建自定义主题
-
PDF用于离线使用
让我们知道你对此的感受
除了从Nuget软件包(如Light and Dark主题)添加主题之外 ,您还可以创建自己的资源字典主题,您可以在应用程序中引用它。
例
主题页面 上BoxView
显示的三个样式根据两个可下载主题中定义的三个类型进行样式化。
要了解这些工作原理,以下标记将创建一个相当于您可以直接添加到App.xaml的样式。
请注意,Class
对于属性Style
(而不是在 x:Key
早期版本Xamarin.Forms可用的属性)。
<ResourceDictionary>
<!-- DEFINE ANY CONSTANTS -->
<Color x:Key="SeparatorLineColor">#CCCCCC</Color>
<Color x:Key="iOSDefaultTintColor">#007aff</Color>
<Color x:Key="AndroidDefaultAccentColorColor">#1FAECE</Color>
<OnPlatform
x:TypeArguments="Color"
x:Key="AccentColor"
Android="{ StaticResource AndroidDefaultAccentColorColor }"
iOS="{ StaticResource iOSDefaultTintColor }"
/>
<!-- BOXVIEW CLASSES -->
<Style TargetType="BoxView" Class="HorizontalRule">
<Setter Property="BackgroundColor" Value="{ StaticResource SeparatorLineColor }" />
<Setter Property="HeightRequest" Value="1" />
</Style>
<Style TargetType="BoxView" Class="Circle">
<Setter Property="BackgroundColor" Value="{ StaticResource AccentColor }" />
<Setter Property="WidthRequest" Value="34"/>
<Setter Property="HeightRequest" Value="34"/>
<Setter Property="HorizontalOptions" Value="Start" />
<Setter Property="local:ThemeEffects.Circle" Value="True" />
</Style>
<Style TargetType="BoxView" Class="Rounded">
<Setter Property="BackgroundColor" Value="{ StaticResource AccentColor }" />
<Setter Property="HorizontalOptions" Value="Start" />
<Setter Property="BackgroundColor" Value="{ StaticResource AccentColor }" />
<Setter Property="local:ThemeEffects.CornerRadius" Value="4" />
</Style>
</ResourceDictionary>
你会注意到,Rounded
该类引用一个自定义的效果CornerRadius
。下面给出了这个效果的代码 - 要正确引用,xmlns
必须将自定义 值添加到App.xaml的根元素中:
xmlns:local="clr-namespace:ThemesDemo;assembly=ThemesDemo"
PCL或共享项目中的C#代码
用于创建圆角的代码BoxView
使用效果。使用a应用拐角半径,BindableProperty
并通过应用效果来实现。该效果需要iOS和Android项目中的平台特定代码(如下所示)。
namemspace ThemesDemo
{
public static class ThemeEffects
{
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.CreateAttached("CornerRadius", typeof(double), typeof(ThemeEffects), 0.0, propertyChanged: OnChanged<CornerRadiusEffect, double>);
private static void OnChanged<TEffect, TProp>(BindableObject bindable, object oldValue, object newValue)
where TEffect : Effect, new()
{
var view = bindable as View;
if (view == null)
{
return;
}
if (EqualityComparer<TProp>.Equals(newValue, default(TProp)))
{
var toRemove = view.Effects.FirstOrDefault(e => e is TEffect);
if (toRemove != null)
{
view.Effects.Remove(toRemove);
}
}
else
{
view.Effects.Add(new TEffect());
}
}
public static void SetCornerRadius(BindableObject view, double radius)
{
view.SetValue(CornerRadiusProperty, radius);
}
public static double GetCornerRadius(BindableObject view)
{
return (double)view.GetValue(CornerRadiusProperty);
}
private class CornerRadiusEffect : RoutingEffect
{
public CornerRadiusEffect()
: base("Xamarin.CornerRadiusEffect")
{
}
}
}
}
iOS项目中的C#代码
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using CoreGraphics;
using Foundation;
using XFThemes;
namespace ThemesDemo.iOS
{
public class CornerRadiusEffect : PlatformEffect
{
private nfloat _originalRadius;
protected override void OnAttached()
{
if (Container != null)
{
_originalRadius = Container.Layer.CornerRadius;
Container.ClipsToBounds = true;
UpdateCorner();
}
}
protected override void OnDetached()
{
if (Container != null)
{
Container.Layer.CornerRadius = _originalRadius;
Container.ClipsToBounds = false;
}
}
protected override void OnElementPropertyChanged(System.ComponentModel.PropertyChangedEventArgs args)
{
base.OnElementPropertyChanged(args);
if (args.PropertyName == ThemeEffects.CornerRadiusProperty.PropertyName)
{
UpdateCorner();
}
}
private void UpdateCorner()
{
Container.Layer.CornerRadius = (nfloat)ThemeEffects.GetCornerRadius(Element);
}
}
}
Android项目中的C#代码
using System;
using Xamarin.Forms.Platform;
using Xamarin.Forms.Platform.Android;
using Android.Views;
using Android.Graphics;
namespace ThemesDemo.Droid
{
public class CornerRadiusEffect : BaseEffect
{
private ViewOutlineProvider _originalProvider;
protected override bool CanBeApplied()
{
return Container != null && (int)Android.OS.Build.VERSION.SdkInt >= 21;
}
protected override void OnAttachedInternal()
{
_originalProvider = Container.OutlineProvider;
Container.OutlineProvider = new CornerRadiusOutlineProvider(Element);
Container.ClipToOutline = true;
}
protected override void OnDetachedInternal()
{
Container.OutlineProvider = _originalProvider;
Container.ClipToOutline = false;
}
protected override void OnElementPropertyChanged(System.ComponentModel.PropertyChangedEventArgs args)
{
base.OnElementPropertyChanged(args);
if (!Attached)
{
return;
}
if (args.PropertyName == ThemeEffects.CornerRadiusProperty.PropertyName)
{
Container.Invalidate();
}
}
private class CornerRadiusOutlineProvider : ViewOutlineProvider
{
private Xamarin.Forms.Element _element;
public CornerRadiusOutlineProvider(Xamarin.Forms.Element element)
{
_element = element;
}
public override void GetOutline(Android.Views.View view, Outline outline)
{
var pixles =
(float)ThemeEffects.GetCornerRadius(_element) *
view.Resources.DisplayMetrics.Density;
outline.SetRoundRect(new Rect(0, 0, view.Width, view.Height), (int)pixles);
}
}
}
}
概要
可以通过为需要自定义外观的每个控件定义样式来创建自定义主题。应该通过Class
资源字典中的不同属性来区分控件的多种样式,然后通过StyleClass
在控件上设置属性来应用。
风格还可以利用效果来进一步定制控件的外观。
隐式样式 (不带任何一个x:Key
或Style
属性)继续应用于与之匹配的所有控件TargetType
。