C# 视图已添加到UIViewControllerRapperView,但它没有';不能正确显示

C# 视图已添加到UIViewControllerRapperView,但它没有';不能正确显示,c#,ios,uiview,uiviewcontroller,xamarin.ios,C#,Ios,Uiview,Uiviewcontroller,Xamarin.ios,我试图在UITableViewController上显示加载指示器。因此,我将我的子视图添加到myTableViewController.View.Superview,这是UIViewControllerRapperView。到目前为止,这是有效的,但并非所有情况下都有效。如果第一次在导航堆栈上添加了UITableViewController,我可以随时显示加载指示器。如果我弹出UITableViewController并将其新实例再次推送到导航堆栈上,则加载指示器不会出现。连续呼叫使加载指示器

我试图在
UITableViewController
上显示加载指示器。因此,我将我的子视图添加到
myTableViewController.View.Superview
,这是
UIViewControllerRapperView
。到目前为止,这是有效的,但并非所有情况下都有效。如果第一次在导航堆栈上添加了
UITableViewController
,我可以随时显示加载指示器。如果我弹出
UITableViewController
并将其新实例再次推送到导航堆栈上,则加载指示器不会出现。连续呼叫使加载指示器再次出现

我试图在
UpdateConstraints
LayoutSubviews
中设置约束,但没有效果。不知何故,这架飞机的高度似乎为零。检查框架显示以下内容:

正常情况:

失败案例

因此,在正常情况下,
LayoutSubviews
似乎调用了两次,因为parent:和hud:line在那里输出。-20来自我使用的一个约束,我在接下来的一个步骤中通过使用不同的约束(限制宽度/高度)将其去掉

如果我添加最小高度,我可以在表格视图左上角的导航栏下看到hud,但它是通过导航栏切掉的,没有居中。如果我试图将宽度/高度限制在零和定义的最大尺寸之间,则会发生相同的行为:

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中提供代码示例

您不应该手动将视图添加到
UIViewControllerRapperView
中,因为它是一个内部API。这样做可能导致不可预测的结果

相反,将加载指示器作为子视图添加到
UITableViewController
view
属性中。也许这已经解决了你的问题

还有一件事:如果您的HUD是一个
UIActivityIndicatorView
,您不需要删除它来隐藏它。只需将
hidesWhenStopped
属性设置为
true
;然后,当调用
stop animating
时,指示器将自动隐藏,并在调用
startAnimating
时重新出现

编辑:

正如您所指出的,将HUD直接添加到视图中可能会导致定位问题。解决此问题的一种方法是手动设置承载表格视图和HUD的容器视图(普通的
UIView
):

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()
}

注意,这个例子使用了一个简单的活动指示器,它有一个内在的大小,所以要使它居中,只需要两个约束;对于HUD,您可能需要添加更复杂的约束。

我采用了由建议的方法。我定义了我的新基类
HUDTableViewController
,它是我的新
UITableViewController
。因此,我从
HUDTableViewController
子类化,而不是
UITableViewController

我的HUD显示以下视图:

TableView.Superview
(在我的子类
HUDTableViewController
中)

必须为
UICollectionViewController
添加额外的方法并实现此类基类。这里我将介绍一个
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
后面添加了一个额外的视图。现在,我可以将表格视图的superview用于我的HUD。到目前为止似乎有效

惰性备选方案(具有不同的行为):

  • 使用
    窗口
    属性:

    UIApplication.SharedApplication.Delegate.GetWindow().View

  • 使用导航控制器:

    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();
        }
    }
    
    NavigationController.View


添加到“视图”属性的缺点是HUD不再居中。我必须在每个
UITableView
中实现一个功能,这将更新位置。因此,我认为我可以使用
uiviewcontrollerrapperview
。你有解决办法吗?感谢您提供有关
ui活动指示灯视图的提示。我不知道。因为我还有一个标签在上面,所以我不得不隐藏包括指示器在内的完整包装。我编辑了我的帖子,为这个问题添加了一个解决方案。我希望这有帮助。谢谢你更新答案。您的解决方案有以下缺点:每个
UITableViewController
都必须进行调整,在我的开发环境中,我有更多的精力来确保内存管理。似乎没有解决此问题的其他解决方案(可能是添加到
UIApplication.SharedApplication.Delegate.GetWindow()
视图中,但这里隐藏了完整的视图控制器)。也许你有另一个好主意,那太棒了!您可以创建一个基类来处理HUD的显示/隐藏。如果你有很多这样的控制器,这可能是个好主意。或者,您是否查找过现有的HUD库,例如Cocoapods?有很多这样的类,它们可能只是做你想做的…基类:创建
UITableViewController
的子类,它在
viewDidLoad
中处理HUD的创建/显示(我们称之为
HUDTableViewController
),然后将这个类用作各种表视图控制器的超类。这样,所有控制器都具有HUD功能,无需额外代码。
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();
    }
}