簡體   English   中英

如何在沒有ViewController的情況下初始化內置於Interface Builder(由Xib支持)中的可重用NSView

[英]How to Initialize a Reusable NSView Built in Interface Builder (Backed by a Xib) Without a ViewController

我試圖建立一個可重用的視圖,以便可以以編程方式實例化一個超級視圖中的多個副本。 但是,我想在Interface Builder中處理此可重用視圖的約束和基本布局。 對於我的NSViewController視圖,我有一個NSViewController子類,一個NSView子類和一個xib文件。 在我的ViewController的ViewDidLoad中,我有如下代碼來實例ViewDidLoad視圖:

public override void ViewDidLoad()
{
    base.ViewDidLoad();

    var exampleView = new NSView();

    View.AddSubview(exampleView);
    View.AddConstraints(CreateExampleViewConstraints(exampleView, View));

    NSView lastView = null;
    foreach(var item in ExampleCollection)
    {
            var reuseableView = ReusableView.Create(item);
            reuseableView.TranslatesAutoresizingMaskIntoConstraints = false;

            exampleView.AddSubview(reuseableView);
            var xPosConstraint = NSLayoutConstraint.Create(reuseableView, NSLayoutAttribute.Left, NSLayoutRelation.Equal, exampleView, NSLayoutAttribute.Left, 1, 0);
            NSLayoutConstraint yPosConstraint = null;
            if(lastView != null)
            {
                yPosConstraint = NSLayoutConstraint.Create(reuseableView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, lastView, NSLayoutAttribute.Bottom, 1, 0);
            }
            else
            {
                yPosConstraint = NSLayoutConstraint.Create(reuseableView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, exampleView, NSLayoutAttribute.Top, 1, 0);
            }
            var widthConstraint = NSLayoutConstraint.Create(reuseableView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, exampleView, NSLayoutAttribute.Width, 1, 0);
            var heightConstraint = NSLayoutConstraint.Create(reuseableView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1, 142);
            exampleView.AddConstraint(xPosConstraint);
            exampleView.AddConstraint(yPosConstraint);
            exampleView.AddConstraint(widthConstraint);
            exampleView.AddConstraint(heightConstraint);

            lastView = reuseableView;
        }
    }

    if(lastView != null)
    {
        var bottomPinConstraint = NSLayoutConstraint.Create(exampleView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, lastView, NSLayoutAttribute.Bottom, 1, 0);
        exampleView.AddConstraint(bottomPinConstraint);
    }
}

對於我要解決的問題而言,約束並不重要。 ReusableViewNSView的子NSView ,具有3個NSTextField插座,分別名為TitleLabelDateLabelLocationLabel

public partial class ReusableView : AppKit.NSView
{
    string _title;
    string _date;
    string _location;

    public ReusableView(IntPtr handle) : base(handle)
    {
    }

    [Export("initWithCoder:")]
    public ReusableView(NSCoder coder) : base(coder)
    {
    }

    public static ReusableView Create(ExampleDependency dependency)
    {
        var model = dependency ?? throw new ArgumentNullException(nameof(dependency));
        NSBundle.MainBundle.LoadNibNamed(nameof(ReusableView), null, out var array);
        var view = NSArray.FromArray<NSObject>(array).OfType<ReusableView>().FirstOrDefault();
        view.Initialize(model);
        return view;
    }

    private void Initialize(ExampleDependency dependency)
    {
        _title = dependency.name;
        _date = dependency.date;
        _location = $"{dependency.eventCity}, {dependency.eventState}";
    }

    public void UpdateControls()
    {
        TitleLabel.StringValue = _title;
        DateLabel.StringValue = _date;
        LocationLabel.StringValue = _location;
    }
}

我遇到的問題是:在顯示之前,ViewController的生命周期方法中的任何時候都不會鈎住ReusableView的IBOutlets /而不是將其設為null。 如您所見,我有一個名為UpdateControls()的公共方法,該方法嘗試根據在Create()期間初始化的私有字段來設置標簽的初始值。 Create()方法確實可以成功加載xib並返回ReusableView的實例; 我什至可以在運行時看到視圖和占位符值。 但是,我嘗試在AwakeFromNib()視圖的視圖控制器的AwakeFromNib()ViewWillAppear()方法期間調用UpdateControls() ,但始終會得到null引用異常,因為顯然沒有實例化這些插座。

顯然,我可以完全以編程方式創建ReusableView並在代碼中設置控件的約束,但是我試圖利用接口構建器。 有沒有辦法做到這一點?

如果不為可重用視圖添加視圖控制器,就無法使它正常工作。 在Xamarin中,我使用了Mac > View with Controller模板,並在生成的xib文件中列出了所有約束。 然后,在代碼中,我進行了更改:

var reuseableView = ReusableView.Create(item);
reuseableView.TranslatesAutoresizingMaskIntoConstraints = false;

exampleView.AddSubview(reuseableView);

至:

var reusableViewController = new ReuseableViewController(item);
var reuseableView = reusableViewController.View;
reuseableView.TranslatesAutoresizingMaskIntoConstraints = false;

exampleView.AddSubview(reuseableView);

訪問強類型View的財產ReuseableViewController確保我的廈門國際銀行將被載入和出口連接。 ReuseableViewController代碼中,我具有以下內容:

// Call to load from the XIB/NIB file
public ReuseableViewController(ExampleDependency dependency) : base("ReuseableViewController", NSBundle.MainBundle)
{
    _dependency = dependency;
}

public override void ViewDidLoad()
{
    base.ViewDidLoad();

    if(_dependency != null)
    {
        TitleLabel.StringValue = _dependency.name;
        DateLabel.StringValue = _dependency.date;
        LocationLabel.StringValue = $"{_dependency.eventCity}, {_dependency.eventState}";
    }
}

我對這個答案不是100%滿意,因為我認為View Controller對於代碼重用來說不是必需的,因此,如果其他人有更好的答案,請繼續進行響應。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM