我正在使用Xamarin.Forms构建一个应用程序,刚刚发现了Pixate Freestyle,这太棒了。我用它来设置默认按钮类,例如,在我的所有按钮上放置基本默认样式,这很棒。
但是,我还没有弄清楚是否有办法使用Xamarin.Forms编写的视图将样式应用于特定对象。我试过设置button.StyleId,但是还没有完成。我也尝试将PixateFreestyle DLL添加到基础项目中,但是A)不确定我是否可以添加iOS和Android以及B)即使添加它们也没有提供调用(并不惊讶,但是我认为我试了一下)
有没有办法通过Xamarin.Forms为Freestyle应用样式?在iOS项目中可能会进行某种调用以利用通过.Forms来使用Freestyle设置类的功能?
提前感谢您的帮助。
答案 0 :(得分:1)
是的,也许不是。
是的:您可以为希望自定义的视图类型创建custom renderer,这样您就可以在XAML和iOS应用之间建立链接。在iOS端,您可以执行所需的所有库的所有调用。然后,您可以创建附加属性(例如下面的样式示例),这些属性可以包含配置渲染所需的其他信息,并将这些附加属性放在Style资源中,并在项目周围使用它们。 Xamarin.Forms还不支持合并资源字典,但你可以写一些代码来做到这一点,所以你的所有样式都在一个位置
...然而 可能没有:在Xamarin.Forms中有许多预定义控件及其各自的渲染器,很难为在所有场景中工作的框架创建一致的插件,例如ListView中的按钮可能没有正确渲染(试一试)
如果您确实试了一下,一旦您拥有适用于属性的基本渲染器,您就可以将一组属性与样式扩展一起打包
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}">
...
答案 1 :(得分:0)
我更新了this以使其正常运行。每个控件都有一个自定义渲染器,在事件上:OnElementPropertyChanged,OnElementChanged样式类和id取自xamarin.forms控件并转移到本机控件。
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);
}
}
效果很好。