1

我正在 Xamarin.Forms 中构建一个应用程序,并且刚刚发现了 Pixate Freestyle,这太棒了。我用它来设置默认按钮类,例如,将基本默认样式放在我所有的按钮上,这很棒。

但是,我无法弄清楚是否有一种方法可以使用用 Xamarin.Forms 编写的视图将样式应用于特定对象。我尝试过设置 button.StyleId,但还没有做到。我还尝试将 PixateFreestyle DLL 添加到基础项目中,但是 A) 不确定我是否可以同时添加 iOS 和 Android,并且 B) 即使添加了,他们也没有提供调用(并不惊讶,但我想我会试一试)

有没有办法通过 Xamarin.Forms 为 Freestyle 应用样式?可能是 iOS 项目中的某种调用,以利用通过 .Forms 传递的功能来使用 Freestyle 设置类?

提前感谢您的帮助。

4

2 回答 2

1

是的,也许不是。

是的:您可以为想要自定义的视图类型创建自定义渲染器,这将为您提供 XAML 和 iOS 应用程序之间的链接。在 iOS 端,您可以对所需的所有库执行所有调用。然后,您可以创建附加属性(例如下面的样式示例),这些属性可以包含配置渲染所需的附加信息,并将这些附加属性放在样式资源中并在项目中使用它们。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}">
...
于 2014-07-21T16:36:10.853 回答
0

我更新了以使其正常工作。每个控件都有一个自定义渲染器,并且在事件上: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);
    }
}

它工作得很好。

于 2014-11-21T14:27:28.873 回答