【问题标题】:Xamarin iOS custom viewXamarin iOS 自定义视图
【发布时间】:2016-02-23 10:37:14
【问题描述】:

我创建了一个自定义视图(从 UIView 派生的新类)。此视图旨在用作我的 iOS 应用程序中的标题,并且基本上包含两个标签,称为“标题”和“子标题”。我创建了两个匹配的字符串属性,可用于设置“标题”和“子标题”标签的文本。

我的问题是,将提供给属性的字符串值分配给标签的 .text 属性的最佳位置是什么?

我知道当我覆盖Draw(CGRect rect) 方法并在此处分配值时它会起作用(并在属性值更改时调用SetNeedsDisplay() 方法)。然而,打电话给Draw(CGRect rect) 对我来说是错误的。任何帮助将不胜感激。

目前我有以下代码:

[Register("MenuHeaderView"), DesignTimeVisible(true)]
public class MenuHeaderView : UIView
{
    private const int _margin = 5;

    private UILabel _title;
    private UILabel _subTitle;


    public MenuHeaderView()
    {
        Initialize();
    }

    public MenuHeaderView(CGRect frame)
        : base(frame)
    {
        Initialize();
    }

    public MenuHeaderView(IntPtr p)
        : base(p)
    {
        Initialize();
    }

    [Export("Title"), Browsable(true)]
    public string Title { get; set; }
    [Export("SubTitle"), Browsable(true)]
    public string SubTitle { get; set; }

    private void Initialize()
    {
        AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;

        // Create 'Title' label
        _title = new UILabel()
        {
            BackgroundColor = UIColor.Clear,
            Font = UIFont.BoldSystemFontOfSize(UIFont.SystemFontSize),
            TextAlignment = UITextAlignment.Left,
            TextColor = UIColor.White,
            Text = "Verbeterapp",
            TranslatesAutoresizingMaskIntoConstraints = false
        };

        // Create 'SubTitle' label
        _subTitle = new UILabel()
        {
            BackgroundColor = UIColor.Clear,
            Font = UIFont.SystemFontOfSize(UIFont.SystemFontSize),
            TextAlignment = UITextAlignment.Left,
            TextColor = UIColor.White,
            Text = "JCI",
            TranslatesAutoresizingMaskIntoConstraints = false
        };

        this.AddSubviews(new UIView[] { _title, _subTitle });

        SetNeedsUpdateConstraints();
    }

    public override void UpdateConstraints()
    {
        if (NeedsUpdateConstraints())
            SetupContraints();

        base.UpdateConstraints();
    }

    private void SetupContraints()
    {
        var constraints = new List<NSLayoutConstraint>();

        var viewMetrics = new Object[] { 
            "titleLabel", _title,
            "subTitleLabel", _subTitle,
            "margin", _margin
        };

        constraints.AddRange(
            NSLayoutConstraint.FromVisualFormat(
                "V:[titleLabel]-margin-[subTitleLabel]", 
                NSLayoutFormatOptions.AlignAllLeading, 
                viewMetrics
            )
        ); 

        constraints.Add(
            NSLayoutConstraint.Create (
                _title,
                NSLayoutAttribute.Left,
                NSLayoutRelation.Equal,
                this,
                NSLayoutAttribute.Left,
                1,
                8
            )
        );

        constraints.Add (
            NSLayoutConstraint.Create(
                _title,
                NSLayoutAttribute.CenterY,
                NSLayoutRelation.Equal,
                this,
                NSLayoutAttribute.CenterY,
                1,
                -_subTitle.Frame.Height 
            )
        );


        AddConstraints(constraints.ToArray());
    }
}

【问题讨论】:

    标签: ios uiview xamarin


    【解决方案1】:

    一如既往:这取决于您的要求(一个平台的小型应用程序/原型或多个平台的大型应用程序)。因此,您的问题有点基于意见。

    您想只分配文本一次吗?然后选择 Designer 或在代码中设置 Text 属性。剩下的问题是,您在每个受支持的平台上都复制了文本值。你必须在 iOS、Android、UWP、Windows Phone 中设置它......而且如果你想改变它,那就很痛苦了。

    我更喜欢使用 MvvMCross 进行数据绑定。我们几乎在每个项目中都使用 MvvMCross(从 3 年开始),因为它提供了视图、数据和服务的严格分离(使用 IoC、MvvM、数据绑定、插件、ViewModel 到 ViewModel 导航等现代方法)以及许多抽象平台特定元素。数据绑定机制允许您轻松更改查看的值。如果你想改变一个静态字符串,你只需要做一次。如果您是 Xamarin、Mobile 和/或 MvvM 的新手,它当然会增加一个可能难以理解的额外级别,但这是完全值得的。

    【讨论】:

    • 抱歉反应迟了,感谢您的回复。但是我的问题更多的是关于自定义视图的内部(因为这应该是一个可重用的控件/视图)。主要是如果自定义视图本身的“绘制”方法是设置文本属性的正确位置。从外部我肯定会使用 MvvmCross 绑定到控件。我问的原因是,不知何故我觉得'Draw'方法更适合真正做图形(但这只是一种感觉)。
    • 好的,而不是像这样简单地实现属性:public string SubTitle { get { return _subTitle.Text; } set { _subTitle.Text = value; } }
    • 当值改变时这是否也会自动更新视图?
    • 是的,如果您使用数据绑定并且不通过一次性绑定进行绑定。在带有 Fluent 绑定 github.com/MvvmCross/MvvmCross/wiki/Databinding#fluent 的 MvvMCross 中,它看起来类似于:bindig.Bind(myHeader).For(v =&gt; v.SubTitle).To(vm =&gt; vm.SubTitle)
    • 非常感谢您的帮助!
    【解决方案2】:

    对于 Xamarin.iOS,您可以尝试类似 this.

    【讨论】: