我正在Xamarin中构建一个应用程序。我刚刚发现了Pixate Freestyle,这真是太棒了。我用它来设置一个默认的按钮类,例如,把基本的默认样式放在我所有的按钮上,这是伟大的。
然而,我还没能弄清楚是否有一种方法可以使用Xamarin.Forms中编写的视图将样式应用于特定对象。我试过设置按钮。StyleId,但这还没有完成。我还尝试将pixatefrestyle DLL添加到基本项目中,但A)不确定我是否可以添加iOS和Android, B)即使添加了,他们也不提供调用(并不惊讶,但我想我会给它一个机会)
有没有办法通过Xamarin.Forms为Freestyle应用样式?可能在iOS项目中使用某种调用来利用.Forms传递的功能来使用Freestyle设置类?
提前感谢任何帮助。
是,也许不是。
Yes:你可以为你想要能够自定义的视图类型创建自定义渲染器,这将为你提供XAML和iOS应用程序之间的链接。在iOS端,你可以执行所有调用所有你需要的库。然后,您可以创建附加属性(例如下面的Style示例),这些附加属性可以保存配置呈现所需的附加信息,并将这些附加属性放入Style资源中,并在项目中使用它们。Xamarin的。Forms目前还不支持合并资源字典,但是你可以编写一些代码来实现这一点,这样你所有的样式就会在一个位置
然而…可能不:在Xamarin中有许多预定义的控件和它们各自的渲染器。窗体,创建一个在所有场景下都能工作的一致的框架插件是很困难的,例如一个按钮在ListView中可能无法正确渲染(给它一个机会)
如果你想尝试一下,一旦你有了基本的渲染器,你就可以把一组属性打包在一起,并使用Style扩展
public class Setter
{
public string Property { get; set; }
public object Value { get; set; }
public string ConverterKey { get; set; }
public object ConverterParameter { get; set; }
}
[ContentProperty ("Children")]
public class Style
{
public ResourceDictionary Resources { get; set; }
public Style ()
{
Children = new List<Setter> ();
}
public List<Setter> Children { get; private set; }
public static readonly BindableProperty StyleProperty =
BindableProperty.CreateAttached<BindableObject, Style> ((bob) => GetStyle (bob), null, BindingMode.OneWay
, propertyChanged: (bindable, oldvalue, newvalue) => {
if (newvalue != null) {
var tinf = bindable.GetType ().GetTypeInfo ();
foreach (var setter in newvalue.Children) {
PropertyInfo pinfo = null;
while (pinfo == null && tinf != null) {
pinfo = tinf.DeclaredProperties.FirstOrDefault (p => p.Name == setter.Property);
if (pinfo == null) {
tinf = tinf.BaseType.GetTypeInfo ();
if (tinf == typeof(object).GetTypeInfo ())
break;
}
}
if (pinfo != null) {
object convertedValue = null;
if (setter.ConverterKey != null && newvalue.Resources != null) {
object valCon;
if (newvalue.Resources.TryGetValue (setter.ConverterKey, out valCon) && valCon != null) {
if (valCon is IValueConverter)
convertedValue = ((IValueConverter)valCon).Convert (setter.Value, pinfo.PropertyType, setter.ConverterParameter, System.Globalization.CultureInfo.CurrentUICulture);
else if (valCon is TypeConverter)
convertedValue = ((TypeConverter)valCon).ConvertFrom (setter.Value);
else
convertedValue = Convert.ChangeType (setter.Value, pinfo.PropertyType);
} else
convertedValue = Convert.ChangeType (setter.Value, pinfo.PropertyType);
} else
convertedValue = Convert.ChangeType (setter.Value, pinfo.PropertyType);
pinfo.SetMethod.Invoke (bindable, new [] { convertedValue });
}
}
}
});
public static Style GetStyle (BindableObject bindable)
{
return (Style)bindable.GetValue (StyleProperty);
}
public static void SetStyle (BindableObject bindable, Style value)
{
bindable.SetValue (StyleProperty, value);
}
}
在XAML中…
<f:Style x:Key="stackStyle">
<f:Style.Resources>
<ResourceDictionary>
<ColorTypeConverter x:Key="colorConverter" />
</ResourceDictionary>
</f:Style.Resources>
<f:Setter Property="BackgroundColor" Value="#3898DC" ConverterKey="colorConverter" />
</f:Style>
...
<StackLayout f:Style.Style="{StaticResource stackStyle}">
...
我更新了这个以使其工作。每个控件都有一个自定义渲染器,在OnElementPropertyChanged、OnElementChanged事件中,样式类和id取自xamarin。窗体控件并转移到本机控件。
public static class StyledRenderer {
public static void UpdateStyle (UIView view, VisualElement model = null) {
var styleId = model.StyleId;
var classId = model.ClassId;
UpdateStyle (view, styleId, classId);
}
public static void UpdateStyle (UIView view, string styleId, string classId) {
Console.WriteLine ("Update style " + styleId + " " + classId + " for " + view);
if (!string.IsNullOrWhiteSpace (styleId)) {
view.SetStyleId (styleId);
}
if (!string.IsNullOrWhiteSpace (classId)) {
view.SetStyleClass(classId);
}
view.UpdateStylesNonRecursivelyAsync ();
}
public static void StyleOnElementPropertyChanged (UIView control, VisualElement element, object sender, PropertyChangedEventArgs e) {
if (e.PropertyName == "ClassId" || e.PropertyName == "StyleId") {
StyledRenderer.UpdateStyle (control, element);
}
}
public static void StyleOnElementChanged ( UIView control, VisualElement element) {
StyledRenderer.UpdateStyle (control, element);
}
}
public class StyledEntryRenderer : EntryRenderer
{
protected override void OnElementPropertyChanged (object sender, PropertyChangedEventArgs e) {
base.OnElementPropertyChanged (sender, e);
StyledRenderer.StyleOnElementPropertyChanged (Control, Element, sender, e);
}
protected override void OnElementChanged (ElementChangedEventArgs<Entry> e) {
base.OnElementChanged (e);
StyledRenderer.StyleOnElementChanged (Control, e.NewElement);
}
}