創建自定義主題
- 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
。