Xamarin.iOS 自定义控件不遵守高度限制
Xamarin.iOS custom control does not respect height constraint
我按照以下指南使用 Xamarin.iOS 创建了一个自定义控件:https://developer.xamarin.com/recipes/ios/general/templates/using_the_ios_view_xib_template/
然而,当我在我的一个视图中使用控件时,它忽略了我在运行时分配给它的高度和正确的自动布局约束,在设计时一切看起来都很好。 (约束是使用设计器设置的)。
我的自定义控件代码如下:
using Foundation;
using System.ComponentModel;
using UIKit;
using System;
using CoreGraphics;
namespace RidderCRM.iOS
{
[DesignTimeVisible(true)]
public partial class RidderDetailBigToSmall : UIView, IComponent
{
public RidderDetailBigToSmall(IntPtr handle) : base(handle)
{
}
#region IComponent implementation
public ISite Site { get; set; }
public event EventHandler Disposed;
#endregion IComponent implementation
#region Icon properties
[Export("Icon"), Browsable(true)]
public UIImage Icon { get; set; }
#endregion Icon properties
#region Title properties
[Export("Title"), Browsable(true)]
public string Title { get; set; }
[Export("TitleColor"), Browsable(true)]
public UIColor TitleColor { get; set; }
#endregion Title properties
#region Subtitle properties
[Export("Subtitle"), Browsable(true)]
public string Subtitle { get; set; }
[Export("SubtitleColor"), Browsable(true)]
public UIColor SubtitleColor { get; set; }
#endregion Subtitle properties
public override CGSize IntrinsicContentSize
{
get { return new CGSize(NoIntrinsicMetric, 56f); }
}
public new static bool RequiresConstraintBasedLayout()
{
return true;
}
public override void AwakeFromNib()
{
base.AwakeFromNib();
if ((Site != null) && Site.DesignMode)
{
// Bundle resources aren't available in DesignMode
return;
}
NSBundle.MainBundle.LoadNib("RidderDetailBigToSmall", this, null);
// At this point all of the code-behind properties should be set, specifically rootView which must be added as a subview of this view
this.AddSubview(this.RootView);
this.TitleLabel.Text = Title;
this.TitleLabel.TextColor = TitleColor;
this.SubtitleLabel.Text = Subtitle;
this.SubtitleLabel.TextColor = SubtitleColor;
this.IconImageView.Image = Icon;
}
}
}
这是之后在设计时放置在视图上的控件的屏幕截图以及应用约束的屏幕截图(注意标签和图标不显示,但我读到这是预期的行为):
这是运行时包含我的自定义控件的视图的屏幕截图(请注意,该控件将占用所有 space 到视图底部):
如有任何帮助,我们将不胜感激。
在 Xamarin 社区(@cheesebaron、@diegoxleon 和@nmilcoff)的帮助下,我设法解决了这个问题。
他们首先向我指出了以下指南:https://developer.xamarin.com/guides/ios/user_interface/designer/ios_designable_controls_overview/
其次他们建议忽略 .xib 文件并在代码中创建控件(按照上面的指南)。
最后,他们就在何处以及如何为自定义控件中使用的所有子视图设置自动布局约束提出了一些建议。
我得到了以下代码:
using System;
using UIKit;
using System.ComponentModel;
using Foundation;
using CoreGraphics;
namespace RidderCRM.iOS.CustomControls
{
[Register("RidderDetailLabel")]
public class RidderDetailLabel
: UIView, IComponent
{
private UIImageView _iconImageView;
private UILabel _titleLabel;
private UILabel _subtitleLabel;
private bool _didSetupConstraints = false;
public RidderDetailLabel() { }
public RidderDetailLabel(IntPtr handle) : base(handle) { }
#region IComponent implementation
public ISite Site { get; set; }
public event EventHandler Disposed;
#endregion
[Export("TitlePosition"), Browsable(true)]
public TitlePosition TitlePosition { get; set; }
[Export("Icon"), Browsable(true)]
public UIImage Icon { get; set; }
[Export("Title"), Browsable(true)]
public string Title { get; set; }
[Export("TitleTextColor"), Browsable(true)]
public UIColor TitleTextColor { get; set; }
[Export("Subtitle"), Browsable(true)]
public string Subtitle { get; set; }
[Export("SubtitleTextColor"), Browsable(true)]
public UIColor SubtitleTextColor { get; set; }
public override void AwakeFromNib()
{
base.AwakeFromNib();
Initialize();
}
private void Initialize()
{
_iconImageView = new UIImageView
{
Image = Icon,
ContentMode = UIViewContentMode.ScaleToFill,
TranslatesAutoresizingMaskIntoConstraints = false
};
_titleLabel = new UILabel
{
Text = Title,
TextColor = TitleTextColor,
Font = UIFont.SystemFontOfSize(17),
TranslatesAutoresizingMaskIntoConstraints = false
};
_subtitleLabel = new UILabel
{
Text = Subtitle,
TextColor = SubtitleTextColor,
Font = UIFont.SystemFontOfSize(12),
TranslatesAutoresizingMaskIntoConstraints = false
};
AddSubview(_iconImageView);
AddSubview(_titleLabel);
AddSubview(_subtitleLabel);
}
public override void UpdateConstraints()
{
if (!_didSetupConstraints)
{
SetupConstraints();
_didSetupConstraints = true;
}
base.UpdateConstraints();
}
private void SetupConstraints()
{
// Add Icon constraints
AddConstraint(_iconImageView.RightAnchor.ConstraintEqualTo(RightAnchor, -16));
AddConstraint(_iconImageView.CenterYAnchor.ConstraintEqualTo(CenterYAnchor));
AddConstraint(_iconImageView.WidthAnchor.ConstraintEqualTo(25));
AddConstraint(_iconImageView.HeightAnchor.ConstraintEqualTo(25));
// Add Title constraints
AddConstraint(_titleLabel.TopAnchor.ConstraintEqualTo(TopAnchor, 12));
AddConstraint(_titleLabel.LeftAnchor.ConstraintEqualTo(LeftAnchor, 16));
AddConstraint(_titleLabel.RightAnchor.ConstraintEqualTo(_iconImageView.RightAnchor, -16));
AddConstraint(_titleLabel.HeightAnchor.ConstraintEqualTo(20));
// Add Subtitle constraints
AddConstraint(_subtitleLabel.TopAnchor.ConstraintEqualTo(_titleLabel.BottomAnchor, 3));
AddConstraint(_subtitleLabel.LeftAnchor.ConstraintEqualTo(LeftAnchor, 16));
AddConstraint(_subtitleLabel.RightAnchor.ConstraintEqualTo(_iconImageView.RightAnchor, -16));
AddConstraint(_subtitleLabel.HeightAnchor.ConstraintEqualTo(15));
}
}
}
我按照以下指南使用 Xamarin.iOS 创建了一个自定义控件:https://developer.xamarin.com/recipes/ios/general/templates/using_the_ios_view_xib_template/
然而,当我在我的一个视图中使用控件时,它忽略了我在运行时分配给它的高度和正确的自动布局约束,在设计时一切看起来都很好。 (约束是使用设计器设置的)。
我的自定义控件代码如下:
using Foundation;
using System.ComponentModel;
using UIKit;
using System;
using CoreGraphics;
namespace RidderCRM.iOS
{
[DesignTimeVisible(true)]
public partial class RidderDetailBigToSmall : UIView, IComponent
{
public RidderDetailBigToSmall(IntPtr handle) : base(handle)
{
}
#region IComponent implementation
public ISite Site { get; set; }
public event EventHandler Disposed;
#endregion IComponent implementation
#region Icon properties
[Export("Icon"), Browsable(true)]
public UIImage Icon { get; set; }
#endregion Icon properties
#region Title properties
[Export("Title"), Browsable(true)]
public string Title { get; set; }
[Export("TitleColor"), Browsable(true)]
public UIColor TitleColor { get; set; }
#endregion Title properties
#region Subtitle properties
[Export("Subtitle"), Browsable(true)]
public string Subtitle { get; set; }
[Export("SubtitleColor"), Browsable(true)]
public UIColor SubtitleColor { get; set; }
#endregion Subtitle properties
public override CGSize IntrinsicContentSize
{
get { return new CGSize(NoIntrinsicMetric, 56f); }
}
public new static bool RequiresConstraintBasedLayout()
{
return true;
}
public override void AwakeFromNib()
{
base.AwakeFromNib();
if ((Site != null) && Site.DesignMode)
{
// Bundle resources aren't available in DesignMode
return;
}
NSBundle.MainBundle.LoadNib("RidderDetailBigToSmall", this, null);
// At this point all of the code-behind properties should be set, specifically rootView which must be added as a subview of this view
this.AddSubview(this.RootView);
this.TitleLabel.Text = Title;
this.TitleLabel.TextColor = TitleColor;
this.SubtitleLabel.Text = Subtitle;
this.SubtitleLabel.TextColor = SubtitleColor;
this.IconImageView.Image = Icon;
}
}
}
这是之后在设计时放置在视图上的控件的屏幕截图以及应用约束的屏幕截图(注意标签和图标不显示,但我读到这是预期的行为):
这是运行时包含我的自定义控件的视图的屏幕截图(请注意,该控件将占用所有 space 到视图底部):
如有任何帮助,我们将不胜感激。
在 Xamarin 社区(@cheesebaron、@diegoxleon 和@nmilcoff)的帮助下,我设法解决了这个问题。
他们首先向我指出了以下指南:https://developer.xamarin.com/guides/ios/user_interface/designer/ios_designable_controls_overview/
其次他们建议忽略 .xib 文件并在代码中创建控件(按照上面的指南)。
最后,他们就在何处以及如何为自定义控件中使用的所有子视图设置自动布局约束提出了一些建议。
我得到了以下代码:
using System;
using UIKit;
using System.ComponentModel;
using Foundation;
using CoreGraphics;
namespace RidderCRM.iOS.CustomControls
{
[Register("RidderDetailLabel")]
public class RidderDetailLabel
: UIView, IComponent
{
private UIImageView _iconImageView;
private UILabel _titleLabel;
private UILabel _subtitleLabel;
private bool _didSetupConstraints = false;
public RidderDetailLabel() { }
public RidderDetailLabel(IntPtr handle) : base(handle) { }
#region IComponent implementation
public ISite Site { get; set; }
public event EventHandler Disposed;
#endregion
[Export("TitlePosition"), Browsable(true)]
public TitlePosition TitlePosition { get; set; }
[Export("Icon"), Browsable(true)]
public UIImage Icon { get; set; }
[Export("Title"), Browsable(true)]
public string Title { get; set; }
[Export("TitleTextColor"), Browsable(true)]
public UIColor TitleTextColor { get; set; }
[Export("Subtitle"), Browsable(true)]
public string Subtitle { get; set; }
[Export("SubtitleTextColor"), Browsable(true)]
public UIColor SubtitleTextColor { get; set; }
public override void AwakeFromNib()
{
base.AwakeFromNib();
Initialize();
}
private void Initialize()
{
_iconImageView = new UIImageView
{
Image = Icon,
ContentMode = UIViewContentMode.ScaleToFill,
TranslatesAutoresizingMaskIntoConstraints = false
};
_titleLabel = new UILabel
{
Text = Title,
TextColor = TitleTextColor,
Font = UIFont.SystemFontOfSize(17),
TranslatesAutoresizingMaskIntoConstraints = false
};
_subtitleLabel = new UILabel
{
Text = Subtitle,
TextColor = SubtitleTextColor,
Font = UIFont.SystemFontOfSize(12),
TranslatesAutoresizingMaskIntoConstraints = false
};
AddSubview(_iconImageView);
AddSubview(_titleLabel);
AddSubview(_subtitleLabel);
}
public override void UpdateConstraints()
{
if (!_didSetupConstraints)
{
SetupConstraints();
_didSetupConstraints = true;
}
base.UpdateConstraints();
}
private void SetupConstraints()
{
// Add Icon constraints
AddConstraint(_iconImageView.RightAnchor.ConstraintEqualTo(RightAnchor, -16));
AddConstraint(_iconImageView.CenterYAnchor.ConstraintEqualTo(CenterYAnchor));
AddConstraint(_iconImageView.WidthAnchor.ConstraintEqualTo(25));
AddConstraint(_iconImageView.HeightAnchor.ConstraintEqualTo(25));
// Add Title constraints
AddConstraint(_titleLabel.TopAnchor.ConstraintEqualTo(TopAnchor, 12));
AddConstraint(_titleLabel.LeftAnchor.ConstraintEqualTo(LeftAnchor, 16));
AddConstraint(_titleLabel.RightAnchor.ConstraintEqualTo(_iconImageView.RightAnchor, -16));
AddConstraint(_titleLabel.HeightAnchor.ConstraintEqualTo(20));
// Add Subtitle constraints
AddConstraint(_subtitleLabel.TopAnchor.ConstraintEqualTo(_titleLabel.BottomAnchor, 3));
AddConstraint(_subtitleLabel.LeftAnchor.ConstraintEqualTo(LeftAnchor, 16));
AddConstraint(_subtitleLabel.RightAnchor.ConstraintEqualTo(_iconImageView.RightAnchor, -16));
AddConstraint(_subtitleLabel.HeightAnchor.ConstraintEqualTo(15));
}
}
}