使用Swift以编程方式布局视图的另一种方法

开始学习Swift时,我对自动布局系统感到困惑。 无论是使用情节提要还是程序限制,它都不适合我。 一些约束在运行时会干扰其他约束,而对所有不同的冲突约束进行分类变得令人沮丧。 我承认在Xcode中使用自动布局功能非常强大,但我相信,除了自动解决方案的替代方法会增加计算成本之外,还会增加其他复杂性。 请注意,在我的标题中,我并不是说这是一种布局视图的“更好”方法,只是一种可以促进进一步实验的不同方法

我觉得有一种更简洁,更省钱的布局视图方式,因此我开始着手开发一个名为View Layout的小型项目。 它只是UIView的扩展,您在其中实例化一个结构(ViewLayout),该结构为您计算视图的位置。 您可能会做的所有数学运算都可以使用CGRect和框架布局视图? 所有这些都封装在“视图布局”结构中。 它使用ViewPosition枚举来确定视图相对于“引导视图”的位置。 我不会尝试描述它,而是显示代码。 这是ViewLayout的初始化,包括分解和解释的步骤。

  //您要放置的视图的不同位置选择 
枚举ViewPosition {
 案例底部中心 
 案例底部左 
 案例底部右 
 案例中心 
 案例顶部左 
 案例顶部右 
 案例中心 
 剩下的情况 
 案例权 
  } 
  //通常除非要以根视图为指导进行布局,否则通常要使用withFrame init 
  init(withFrame ofView:UIView,position:ViewPosition,size:CGSize,padding:(CGFloat,CGFloat)){ 
  self.guide = ofView.frame // 1 
  self.position =位置// 2 
  self.size =大小// 3 
  self.padding =填充// 4 
  } 

1:我设置ViewLayout对象在计算其原点时使用的框架

2:我将框架的位置与指南进行了比较

3:我设置要在ViewLayout中创建的框架的大小

4:我使用元组设置视图的水平和垂直填充。 第一项(padding.0)控制垂直填充,正数增加原点的Y坐标,负数减少原点的Y。第二个数与水平填充相同,正数增加X坐标,负数减少了它。

现在,调用此初始化程序后,您将获得一个ViewLayout对象! 不过您还不能使用它。 您只是获得一个自动配置的框架以供视图使用而已,而仅仅是一个函数调用! 您所要做的就是调用以下功能之一:

  //不要忘记在实例化结束时调用它! 
  func makeInnerLayout()-> CGRect { 
 返回CGRect(来源:原点,大小:大小) 
  } 
  func makeOuterLayout()-> CGRect { 
 返回CGRect(来源:outerOrigin,大小:size) 
  } 

那么这是怎么回事? 好吧,我们使用外部或内部原点,并将大小传递给初始化程序,以返回CGRect用作视图的框架。 原点是ViewLayout对象中的计算属性,这些属性通过使用初始化程序的padding,position和guide视图返回视图的原点。 这两个函数之间的区别在于,makeOuterLayout()函数仅将原点计算为位于引导视图之外,而makeInnerLayout()函数将原点计算为在视图内部。 如果您想使用8pt的间距将两个视图彼此相邻地布局,则只需执行以下操作:

 覆盖func viewDidLoad(){ 
  super.viewDidLoad() 
 让viewWidth = self.view.bounds.width / 2-12 
  //在根视图内布置第一个视图 
 让view1Layout = UIView.ViewLayout(withBounds:self.view,position:.topLeft,size:CGSize(width:viewWidth,height:200),padding:(50,0))。makeInnerLayout() 
  view1 = UIView(框架:view1Layout) 
  view1.backgroundColor = .black 
  self.view.addSubview(view1) 
  //以view1为参考,向左8点 
 让view2Layout = UIView.ViewLayout(withFrame:view1,position:.right,size:CGSize(width:viewWidth,height:200),padding:(0,8))。makeOuterLayout() 
  view2 = UIView(框架:view2Layout) 
  view2.backgroundColor = .red 
  self.view.addSubview(view2) 
  } 

此代码产生的布局如下所示:

这种方法的最大缺点是,许多人更喜欢autoLayout而不是CGRect数学,原因是您必须在代码中设置要布局两次的View的框架,至少要设置动画的话。 您可以在ViewDidLoad和didRotate(或类似函数)中进行设置。 我曾经在didLayoutSubviews()中布局视图一次。 但是我后来发现,如果在didLayoutSubviews()中存在与正在动画化的视图相关的布局代码,则在动画过程中会调用此方法,这通常会破坏动画。

我仍在尝试找出如何处理动画以及使用此方法在更困难的环境(如分屏和多任务)中进行布局的方法。 如果您有任何意见或认为可以实现的方式,请随时通过https://github.com/afrench53198/ViewLayout派生或向主项目发送拉取请求。

这是我的第一篇有关开发和实际代码的中级文章,所以请告诉我我的工作方式! 如果不清楚或可以更好地解释,请发表评论。 感谢您的阅读,我希望介绍ViewLayout结构可以激发您创建比AutoLayout程序约束或Visual Formatting Language更好,更有用的功能。