我有一个xib文件 - LoaderView.xib和相关的类LoaderView.cs,其中包含一个显示加载文本的视图。当我尝试将它作为 -
加载到主ViewController中时public override void ViewDidAppear()
{
base.ViewDidAppear();
NSBundle.MainBundle.LoadNibNamed("LoaderView", this, out NSArray arr);
var view = Runtime.GetNSObject<LoaderView>(arr.ValueAt(0));
view.Frame = View.Frame;
View.AddSubview(view);
}
我在此行中收到System.InvalidCastException -
var view = Runtime.GetNSObject<LoaderView>(arr.ValueAt(0));
奇怪的是我每次都没有得到例外。当它工作时,我看到加载文本与默认视图重叠 - 与ViewController相关联。
有人可以指出显示加载,错误和空状态的最佳方式是什么。我应该为它们分别使用ViewControllers吗?或者我可以使用单独的xib文件从主视图控制器加载/卸载吗?如何从xib文件加载视图?
答案 0 :(得分:1)
问题在于arr。
在上面的图像中,可以看出方法LoadNibNamed
不是每次都以相同的顺序返回arr
中的顶级对象。这就是代码 -
var view = Runtime.GetNSObject<LoaderView>(arr.ValueAt(0));
每次都无法将arr
的第0项投放到LoaderView
类型。
解决方案是遍历数组以在此处找到您的类型的项目 - LoaderView
。对于我的情况 - 我写了一个静态类,它有一个泛型方法LoadViewFromNib
,它返回一个继承自NSView
的类型为T的视图。
public static class LoadNib
{
static NSArray xibItems;
static nuint index;
public static T LoadViewFromNib<T>(string filename, NSObject owner) where T : NSView
{
NSBundle.MainBundle.LoadNibNamed(filename, owner, out xibItems);
for (nuint i = 0; i < xibItems.Count; i++)
{
NSObject item = xibItems.GetItem<NSObject>(i);
if (item is T)
{
index = i;
break;
}
}
return Runtime.GetNSObject<T>(xibItems.ValueAt(index));
}
}
至于重叠的问题,我发现除非明确设置背景,否则子视图是透明的。
答案 1 :(得分:0)
这是Xamarin的文档问题。他们的文档说使用第0个索引,但现实情况是数组顺序不确定。
Anagh给出的答案是足够的,并且在技术上是最佳的,但是您可以通过使用Linq使其更简洁,并且也很适合扩展方法:
public static class NibLoadingExtension
{
public static T LoadViewFromNib<T>(this T @null) where T : NSView
{
NSBundle.MainBundle.LoadNibNamed(typeof(T).Name, null, out var array);
return NSArray.FromArray<NSObject>(array).OfType<T>().FirstOrDefault();
}
}
不幸的是,由于没有实例就无法在C#中调用扩展方法,因此必须像这样使用它:
var loaderView = default(LoaderView).LoadViewFromNib();
还有一个参数需要支持向每个单独的视图类添加静态Create()方法或其他内容,因为这样您就可以调用私有的初始化方法,如下所示:
public static LoaderView Create(ExampleDependency dependency)
{
var model = dependency ?? throw new ArgumentNullException(nameof(dependency));
NSBundle.MainBundle.LoadNibNamed(nameof(LoaderView), null, out var array);
var view = NSArray.FromArray<NSObject>(array).OfType<LoaderView>().FirstOrDefault();
view.Initialize(model);
return view;
}
private void Initialize(ExampleDependency dependency)
{
_privateField1 = dependency.Value1;
_privateField2 = dependency.Value2;
_privateField3 = dependency.Value3;
}