视图已添加到 UIViewControllerWrapperView,但显示不正确
View is added to UIViewControllerWrapperView, but it doesn't appear correctly
我正在尝试在 UITableViewController
上显示加载指示器。因此,我将我的子视图添加到 myTableViewontroller.View.Superview
,即 UIViewControllerWrapperView
。到目前为止,这是有效的,但并非在所有情况下都有效。如果 UITableViewController
是第一次添加到导航堆栈中,我可以根据需要随时显示加载指示器。如果我弹出 UITableViewController
并再次将它的新实例推送到导航堆栈,则加载指示器不会出现。连续调用使加载指示器再次出现!
我尝试在 UpdateConstraints
、LayoutSubviews
中设置我的约束,但没有帮助。不知何故,框架的高度似乎为零。检查帧显示如下:
正常情况:
parent:{X=0,Y=0,Width=320,Height=480}
hud:{X=0,Y=0,Width=0,Height=0}
parent - before setting up constraints{X=0,Y=0,Width=320,Height=480}
hud - after hud showing: {X=0,Y=0,Width=279,5,Height=0}
parent:{X=0,Y=0,Width=320,Height=480}
hud:{X=0,Y=0,Width=320,Height=480}
失败案例
parent:{X=0,Y=0,Width=320,Height=480}
hud:{X=0,Y=0,Width=0,Height=0}
parent - before setting up constraints{X=0,Y=0,Width=320,Height=480}
hud - after hud showing: {X=-20,Y=59,Width=279,5,Height=0}
所以 LayoutSubviews
似乎在正常情况下调用了两次,因为 parent: 和 hud: 行在那里输出。 -20 来自我使用的一个约束,我在接下来的步骤之一中通过使用不同的约束(限制 widht/height)摆脱了它。
如果我添加最小高度,我可以在 table 视图左上角的导航栏下方看到 HUD,但它被导航栏截断并且未居中。如果我尝试将 width/height 限制在零和我定义的最大大小之间,则会发生相同的行为:
NSLayoutConstraint widthConstraint1 = NSLayoutConstraint.Create(this.hudContainer, NSLayoutAttribute.Width, NSLayoutRelation.LessThanOrEqual, this, NSLayoutAttribute.Width, 1, -40);
widthConstraint1.Priority = 750;
NSLayoutConstraint widthConstraint2 = NSLayoutConstraint.Create(this.hudContainer, NSLayoutAttribute.Width, NSLayoutRelation.GreaterThanOrEqual, null, NSLayoutAttribute.NoAttribute, 1, 0);
widthConstraint2.Priority = 1000;
NSLayoutConstraint heightConstraint1 = NSLayoutConstraint.Create(this.hudContainer, NSLayoutAttribute.Height, NSLayoutRelation.LessThanOrEqual, this, NSLayoutAttribute.Height, 1, -100);
heightConstraint1.Priority = 750;
NSLayoutConstraint heightConstraint2 = NSLayoutConstraint.Create(this.hudContainer, NSLayoutAttribute.Height, NSLayoutRelation.GreaterThanOrEqual, null, NSLayoutAttribute.NoAttribute, 1, 0);
heightConstraint2.Priority = 1000;
AddConstraints(new NSLayoutConstraint[] { widthConstraint1, widthConstraint2, heightConstraint1, heightConstraint2});
这里不考虑最大宽度。
我使用此代码将 hud 添加为子视图并设置主要约束:
this.TranslatesAutoresizingMaskIntoConstraints = false;
this.parentView.AddSubview(this);
NSMutableDictionary viewsDictionary = new NSMutableDictionary();
viewsDictionary["hud"] = this;
this.parentView.LayoutIfNeeded();
Console.WriteLine("parent - before setting up constraints" + this.parentView.Frame);
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.Width, 1, 0));
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.Height, 1, 0));
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.Top, 1, 0));
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.Right, 1, 0));
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.Bottom, 1, 0));
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.Left, 1, 0));
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.CenterX, 1, 0));
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.CenterY, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.CenterY, 1, 0));
这是删除和隐藏 hud 的代码:
this.Alpha = 0.0f;
RemoveFromSuperview();
我 运行 没主意了。我怎么解决这个问题?也许有人可以给我一个提示,我怎样才能更好地调试它。此处提供的代码使用 C#,但您可以在 Objective-C/Swift!
中提供代码示例
您不应手动向 UIViewControllerWrapperView
添加视图,因为它是内部 API。这样做会导致不可预测的table结果。
相反,将您的加载指示器作为子视图添加到 UITableViewController
的 view
属性。也许这已经解决了您的问题。
还有一件事:如果您的 HUD 是 UIActivityIndicatorView
,则无需移除它即可隐藏它。只需将 hidesWhenStopped
属性 设置为 true
;然后指标会在调用 stopAnimating
时自动隐藏,并在调用 startAnimating
时重新出现。
编辑:
正如您所指出的,将 HUD 直接添加到视图中会导致定位问题。解决这个问题的一种方法是手动设置一个容器视图(一个普通的 UIView
)来承载 table 视图和 HUD:
override func viewDidLoad() {
super.viewDidLoad()
let tableView = self.tableView
let containerView = UIView(frame: self.view.bounds)
containerView.addSubview(tableView)
containerView.addSubview(spinner)
view = containerView
spinner.translatesAutoresizingMaskIntoConstraints = false
view.addConstraint(NSLayoutConstraint(item: spinner, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: spinner, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: 0))
spinner.startAnimating()
}
请注意,这个例子使用了一个简单的 activity 指标,它有一个固有的大小,所以要让它居中只需要两个约束;对于您的 HUD,您可能需要添加更复杂的约束。
我采用了 dr_barto 建议的方法。我定义了我的新基地classHUDTableViewController
,也就是我的新基地UITableViewController
。所以我从 HUDTableViewController
而不是 UITableViewController
.
子 classing
我的 HUD 获得以下视图:
TableView.Superview
(在我的子classed HUDTableViewController
里面)
必须添加额外的方法并为 UICollectionViewController
实现这样的基础 class。在这里,我举了一个 UITableViewController
:
的例子
public class HUDTableViewController : UIViewController, IUITableViewDataSource, IUITableViewDelegate, IDisposable
{
private UITableView tableView;
public UITableView TableView
{
get
{
return this.tableView;
}
set
{
this.tableView = value;
}
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.tableView = new UITableView();
this.tableView.TranslatesAutoresizingMaskIntoConstraints = false;
this.tableView.WeakDelegate = this;
this.tableView.WeakDataSource = this;
UIView parentView = new UIView();
parentView.AddSubview(this.tableView);
View = parentView;
NSMutableDictionary viewsDictionary = new NSMutableDictionary();
viewsDictionary["parent"] = parentView;
viewsDictionary["tableView"] = this.tableView;
parentView.AddConstraints(NSLayoutConstraint.FromVisualFormat("H:|[tableView]|", (NSLayoutFormatOptions)0, null, viewsDictionary));
parentView.AddConstraints(NSLayoutConstraint.FromVisualFormat("V:|[tableView]|", (NSLayoutFormatOptions)0, null, viewsDictionary));
}
[Foundation.Export("numberOfSectionsInTableView:")]
public virtual System.nint NumberOfSections(UIKit.UITableView tableView)
{
throw new NotImplementedException();
}
public virtual System.nint RowsInSection(UIKit.UITableView tableview, System.nint section)
{
throw new NotImplementedException();
}
public virtual UIKit.UITableViewCell GetCell(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
{
throw new NotImplementedException();
}
[Foundation.Export("tableView:didSelectRowAtIndexPath:")]
public virtual void RowSelected(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
{
throw new NotImplementedException();
}
[Foundation.Export("tableView:heightForHeaderInSection:")]
public virtual System.nfloat GetHeightForHeader(UIKit.UITableView tableView, System.nint section)
{
throw new NotImplementedException();
}
[Foundation.Export("tableView:viewForHeaderInSection:")]
public virtual UIKit.UIView GetViewForHeader(UIKit.UITableView tableView, System.nint section)
{
throw new NotImplementedException();
}
[Foundation.Export("tableView:willDisplayCell:forRowAtIndexPath:")]
public virtual void WillDisplay(UIKit.UITableView tableView, UIKit.UITableViewCell cell, Foundation.NSIndexPath indexPath)
{
throw new NotImplementedException();
}
}
正如大家所见,我在 UITableView
后面添加了一个额外的视图。现在我可以为我的 HUD 使用 table 视图的超级视图。到目前为止似乎有效。
懒惰的替代品(具有不同的行为):
使用Window
属性:
UIApplication.SharedApplication.Delegate.GetWindow().View
使用NavigationController
:
NavigationController.View
我正在尝试在 UITableViewController
上显示加载指示器。因此,我将我的子视图添加到 myTableViewontroller.View.Superview
,即 UIViewControllerWrapperView
。到目前为止,这是有效的,但并非在所有情况下都有效。如果 UITableViewController
是第一次添加到导航堆栈中,我可以根据需要随时显示加载指示器。如果我弹出 UITableViewController
并再次将它的新实例推送到导航堆栈,则加载指示器不会出现。连续调用使加载指示器再次出现!
我尝试在 UpdateConstraints
、LayoutSubviews
中设置我的约束,但没有帮助。不知何故,框架的高度似乎为零。检查帧显示如下:
正常情况:
parent:{X=0,Y=0,Width=320,Height=480}
hud:{X=0,Y=0,Width=0,Height=0}
parent - before setting up constraints{X=0,Y=0,Width=320,Height=480}
hud - after hud showing: {X=0,Y=0,Width=279,5,Height=0}
parent:{X=0,Y=0,Width=320,Height=480}
hud:{X=0,Y=0,Width=320,Height=480}
失败案例
parent:{X=0,Y=0,Width=320,Height=480}
hud:{X=0,Y=0,Width=0,Height=0}
parent - before setting up constraints{X=0,Y=0,Width=320,Height=480}
hud - after hud showing: {X=-20,Y=59,Width=279,5,Height=0}
所以 LayoutSubviews
似乎在正常情况下调用了两次,因为 parent: 和 hud: 行在那里输出。 -20 来自我使用的一个约束,我在接下来的步骤之一中通过使用不同的约束(限制 widht/height)摆脱了它。
如果我添加最小高度,我可以在 table 视图左上角的导航栏下方看到 HUD,但它被导航栏截断并且未居中。如果我尝试将 width/height 限制在零和我定义的最大大小之间,则会发生相同的行为:
NSLayoutConstraint widthConstraint1 = NSLayoutConstraint.Create(this.hudContainer, NSLayoutAttribute.Width, NSLayoutRelation.LessThanOrEqual, this, NSLayoutAttribute.Width, 1, -40);
widthConstraint1.Priority = 750;
NSLayoutConstraint widthConstraint2 = NSLayoutConstraint.Create(this.hudContainer, NSLayoutAttribute.Width, NSLayoutRelation.GreaterThanOrEqual, null, NSLayoutAttribute.NoAttribute, 1, 0);
widthConstraint2.Priority = 1000;
NSLayoutConstraint heightConstraint1 = NSLayoutConstraint.Create(this.hudContainer, NSLayoutAttribute.Height, NSLayoutRelation.LessThanOrEqual, this, NSLayoutAttribute.Height, 1, -100);
heightConstraint1.Priority = 750;
NSLayoutConstraint heightConstraint2 = NSLayoutConstraint.Create(this.hudContainer, NSLayoutAttribute.Height, NSLayoutRelation.GreaterThanOrEqual, null, NSLayoutAttribute.NoAttribute, 1, 0);
heightConstraint2.Priority = 1000;
AddConstraints(new NSLayoutConstraint[] { widthConstraint1, widthConstraint2, heightConstraint1, heightConstraint2});
这里不考虑最大宽度。
我使用此代码将 hud 添加为子视图并设置主要约束:
this.TranslatesAutoresizingMaskIntoConstraints = false;
this.parentView.AddSubview(this);
NSMutableDictionary viewsDictionary = new NSMutableDictionary();
viewsDictionary["hud"] = this;
this.parentView.LayoutIfNeeded();
Console.WriteLine("parent - before setting up constraints" + this.parentView.Frame);
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.Width, 1, 0));
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.Height, 1, 0));
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.Top, 1, 0));
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.Right, 1, 0));
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.Bottom, 1, 0));
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.Left, 1, 0));
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.CenterX, 1, 0));
this.parentView.AddConstraint(NSLayoutConstraint.Create(this, NSLayoutAttribute.CenterY, NSLayoutRelation.Equal, this.parentView, NSLayoutAttribute.CenterY, 1, 0));
这是删除和隐藏 hud 的代码:
this.Alpha = 0.0f;
RemoveFromSuperview();
我 运行 没主意了。我怎么解决这个问题?也许有人可以给我一个提示,我怎样才能更好地调试它。此处提供的代码使用 C#,但您可以在 Objective-C/Swift!
中提供代码示例您不应手动向 UIViewControllerWrapperView
添加视图,因为它是内部 API。这样做会导致不可预测的table结果。
相反,将您的加载指示器作为子视图添加到 UITableViewController
的 view
属性。也许这已经解决了您的问题。
还有一件事:如果您的 HUD 是 UIActivityIndicatorView
,则无需移除它即可隐藏它。只需将 hidesWhenStopped
属性 设置为 true
;然后指标会在调用 stopAnimating
时自动隐藏,并在调用 startAnimating
时重新出现。
编辑:
正如您所指出的,将 HUD 直接添加到视图中会导致定位问题。解决这个问题的一种方法是手动设置一个容器视图(一个普通的 UIView
)来承载 table 视图和 HUD:
override func viewDidLoad() {
super.viewDidLoad()
let tableView = self.tableView
let containerView = UIView(frame: self.view.bounds)
containerView.addSubview(tableView)
containerView.addSubview(spinner)
view = containerView
spinner.translatesAutoresizingMaskIntoConstraints = false
view.addConstraint(NSLayoutConstraint(item: spinner, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: spinner, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: 0))
spinner.startAnimating()
}
请注意,这个例子使用了一个简单的 activity 指标,它有一个固有的大小,所以要让它居中只需要两个约束;对于您的 HUD,您可能需要添加更复杂的约束。
我采用了 dr_barto 建议的方法。我定义了我的新基地classHUDTableViewController
,也就是我的新基地UITableViewController
。所以我从 HUDTableViewController
而不是 UITableViewController
.
我的 HUD 获得以下视图:
TableView.Superview
(在我的子classed HUDTableViewController
里面)
必须添加额外的方法并为 UICollectionViewController
实现这样的基础 class。在这里,我举了一个 UITableViewController
:
public class HUDTableViewController : UIViewController, IUITableViewDataSource, IUITableViewDelegate, IDisposable
{
private UITableView tableView;
public UITableView TableView
{
get
{
return this.tableView;
}
set
{
this.tableView = value;
}
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.tableView = new UITableView();
this.tableView.TranslatesAutoresizingMaskIntoConstraints = false;
this.tableView.WeakDelegate = this;
this.tableView.WeakDataSource = this;
UIView parentView = new UIView();
parentView.AddSubview(this.tableView);
View = parentView;
NSMutableDictionary viewsDictionary = new NSMutableDictionary();
viewsDictionary["parent"] = parentView;
viewsDictionary["tableView"] = this.tableView;
parentView.AddConstraints(NSLayoutConstraint.FromVisualFormat("H:|[tableView]|", (NSLayoutFormatOptions)0, null, viewsDictionary));
parentView.AddConstraints(NSLayoutConstraint.FromVisualFormat("V:|[tableView]|", (NSLayoutFormatOptions)0, null, viewsDictionary));
}
[Foundation.Export("numberOfSectionsInTableView:")]
public virtual System.nint NumberOfSections(UIKit.UITableView tableView)
{
throw new NotImplementedException();
}
public virtual System.nint RowsInSection(UIKit.UITableView tableview, System.nint section)
{
throw new NotImplementedException();
}
public virtual UIKit.UITableViewCell GetCell(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
{
throw new NotImplementedException();
}
[Foundation.Export("tableView:didSelectRowAtIndexPath:")]
public virtual void RowSelected(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
{
throw new NotImplementedException();
}
[Foundation.Export("tableView:heightForHeaderInSection:")]
public virtual System.nfloat GetHeightForHeader(UIKit.UITableView tableView, System.nint section)
{
throw new NotImplementedException();
}
[Foundation.Export("tableView:viewForHeaderInSection:")]
public virtual UIKit.UIView GetViewForHeader(UIKit.UITableView tableView, System.nint section)
{
throw new NotImplementedException();
}
[Foundation.Export("tableView:willDisplayCell:forRowAtIndexPath:")]
public virtual void WillDisplay(UIKit.UITableView tableView, UIKit.UITableViewCell cell, Foundation.NSIndexPath indexPath)
{
throw new NotImplementedException();
}
}
正如大家所见,我在 UITableView
后面添加了一个额外的视图。现在我可以为我的 HUD 使用 table 视图的超级视图。到目前为止似乎有效。
懒惰的替代品(具有不同的行为):
使用
Window
属性:UIApplication.SharedApplication.Delegate.GetWindow().View
使用
NavigationController
:NavigationController.View