Tag: 布局

在Swift中以编程方式创建UIViews

使用PureLayout具有视图约束 期待什么? 了解iOS屏幕 查看层次结构 何时以编程方式构建视图 如何组织我们的代码(MVC模式) 构建自定义类(UIView) Twitter iOS应用示例 !Massive View控制器 设置约束(PureLayout) 了解iOS屏幕 任何iOS应用程序都有很多视图。 这些视图需要指定四个值才能显示: x,y,width,height 。 有三种不同的方式来构建这些视图: 情节提要 , Nib 文件和Programmatically 。 iOS sdk(UIKit)中有一个框架,其中包含一组标准子类,这些子类的范围从简单的按钮到许多其他视图对象之间的复杂表。 例如,UILabel对象绘制文本字符串,而UIImageView对象绘制图像。 视图可以嵌入其他视图并创建复杂的视觉层次结构。 这将在要嵌入的视图 (称为subview )和进行嵌入的父视图(称为superview )之间创建父子关系。 查看层次结构 视图的组织方式不仅影响应用程序的外观,还影响应用程序对更改和事件的响应方式。 例如,视图层次结构中的父子关系确定哪些对象可以处理特定的触摸事件。 同样,父子关系定义每个视图如何响应界面方向更改。 何时以编程方式构建视图 在满足以下条件时,使用自定义代码通常是一个很好的选择: 动态布局 具有效果,圆角,阴影等的视图 使用情节提要的任何情况都很复杂。 如何组织我们的代码(MVC模式) Model-View-Controller可能是最常用的设计模式。 从iOS开发开始,通常会遇到Massive View Controller问题 :View Controllers常常变得太大,包含难以真正修改或重构的所有功能。 通过遵循这种模式,我们确保项目中的每个类都是Controller,Model或View。 这样可以更轻松地以编程方式创建所有视图,而无需创建意大利面条怪兽。 显然,我们可以有其他组和类,但是应用程序的核心包含在这三个类别中。 入门 启动新项目时,Xcode使用情节提要板对其进行初始化。 为了创建我们的自定义视图,我们需要丢弃情节提要。 接下来,创建两个文件: ProfileView作为View类别下的UIView类,以及ProfileViewController作为Controller类别下的UIViewController类。 […]

为什么我喜欢SnapKit,您也可以

刚开始编码时,我100%参与StoryBoard团队。 很容易看到不同的UIView是如何交互的,您可以将它们精确地放置在所需的位置。 这适用于单个屏幕尺寸,但是随着视图变得越来越复杂并且需要适应各种屏幕尺寸,约束的层次结构变得越来越难以确定。 尽管如此,程序化还是令人恐惧! Swift的内置方法是噩梦。 即使我现在已经全心全意地通过程序设计应用程序,但仅查看这些方法仍然会让我感到恐惧。 幸运的是,令许多程序员感到宽慰的是,SnapKit幸运的灵魂为iOS和OS X设计了一个完全用Swift编写的疯狂简单的自动布局DSL! 首先,只需在pod文件中使用pod ‘SnapKit’安装SnapKit CocoaPod,然后打开项目的.xcworkspace。 以编程方式设计应用程序需要一些设置。 首先转到您应用的“常规设置”,然后在“部署信息”的“主界面”下,删除“ Main所在的位置。 这告诉您的应用不再担心故事板! 尽管如此,应用程序仍需要一个切入点……这就是AppDelegate发挥作用的地方。 在这里,您要声明第一个ViewController的实例。 (如果您使用的是UINavigationController,UITabBarController或ContainerViewController,则也可以在其中进行设置,但现在我们将使用单个ViewController)。 在AppDelegate的func application(… didFinishLaunchingWithOptions…)方法中,将window初始化为具有与UIScreen绑定的框架相同的框架的UIWindow() ,然后初始化主ViewController。 接下来将window?.rootViewController设置为与您新创建的ViewController相等,并使该window可见! 五行代码,您的应用程序将打开您指定的ViewController。 现在,让我们来看看有趣的东西吧! 当然,第一步是导入SnapKit。 (如果它声称不存在这样的模块,请给它旧的Command + B;还要检查您是否在xcworkspace中工作,而不仅仅是xcodeproj)。 通常,我制作的第一个UIView会占据整个屏幕,因此让我们创建一个mainView: UIView!实例mainView: UIView! ,对其进行初始化,然后将其添加到ViewController的view将其设置为等于屏幕的大小。 在mainView.snp.makeContraints方法中,每次您写入$0它只是简单地引用受约束的-view本身! 将边缘设置为equalToSuperview将允许此View扩展到其superView(UIScreen的view )所允许的最大范围。 这是一个简单的介绍,但让我们看看snp.makeConstraints还有哪些其他选项。 现在我们有了背景视图,让我们在可能要显示一些常规信息的地方添加标题。 此新视图将添加到mainView顶部,并将与Screen / SuperView的高度成比例: 请注意,如果属性有所不同,如何将不同的约束链接在一起,并添加新行。 这使得代码非常容易键入和阅读! 在这一点上,我们有一个mainView,大小为UIScreen的青色,还有一个headerView的彩色迷离,它覆盖了屏幕的前25%。 让我们添加一个Label并将其直接放置在headerView : 使用UILabels,您不必将它们设置为特定的高度或宽度。 取决于您选择的文字和字体/大小。 这样,您只需给它一个X / Y轴位置,Xcode就会假定其余的位置。 最终结果应显示3/4青色和1/4蓝色屏幕,其中标签直接位于蓝色部分的中心。 SnapKit中提供了许多其他方法,其中大多数是完全不言自明的。 例如,如果我们希望mainLabel位于屏幕中央,但在蓝色headerView ,则可以删除centerY约束并添加新行,指示$0.top.equalTo(mainHeader.snp.bottom).offset(10) […]

自定义UICollectionViewLayout自动布局和动态类型

Gousto的iOS团队对其所有UI使用自动布局,因此我们能够容纳可变内容,动态类型和不同大小级别的设备。 当我们想将食谱列表切换到中等规模的设备上的网格时,我们很难找到有关如何使用UICollectionView和用于UICollectionViewCells的XIB实现此目的的任何文档。 这篇博客文章讨论了我们遇到的问题以及如何使用自定义UICollectionViewLayout实现它。 为什么? 自从引入动态类型以来,我们认为支持它对我们的用户将是有益的(这意味着响应用户在其设备上设置的字体比例)。 当要求重新设计我们的主要配方列表以添加另一种具有不同高度的电池时,我们认为这是一个绝佳的机会,应该不会太痛苦。 苹果公司说“在开始构建自定义布局之前,请考虑这样做是否真的必要”,这也总是很棒。 在整个这篇文章中,我将展示一些代码,但是我还将附加一个演示项目,以便您可以看到它的工作! 固定约束 以前,我们的单元格都具有相同的高度,而我们的食谱标题标签都具有高度限制,且字体大小最小,因此字体大小会缩小以容纳文本,在极端情况下,标题会被截断。 我们要做的第一件事是删除所有不必要的约束并使所有变量可变。 我们拥有的单元格布局非常复杂,带有许多子视图(有时是不必要的),因此我们对此进行了整理,并尝试使其尽可能平坦,并针对不同的场景使用了不同的单元格。 介绍自定义布局 如果要创建自定义布局,则基本上必须自己做好所有事情,这可能就是Apple不真正推荐它的原因。 在布局中,有三种主要方法: func prepare() 最初,我认为该方法一开始只会被调用一次,但是它被频繁调用,因此,如果layoutAttributesForItems为空(这是我们用于单元的缓存),我们只想计算估计的单元大小。 第一次调用时,我们的缓存为空,因此我们创建了初始布局。 在initialLayout中,我们实际上将执行我们的像元大小估计。 首先确定我们需要多少列,因为根据窗口的宽度,我们有1、2或3。 上面的代码创建了两个数组,对于我们的X和Y单元格位置,我们仅用列数的位置(例如三列)来初始化y数组 yOffset = [0,0,0] 我们基于列再次完成xOffset数组,因此如果我们有一个1024像素宽度的设备和三列,我们将拥有 xOffset = [0,341,682,0,341,682,…],依此类推。 接下来,我们需要遍历每个单元并为每个单元创建布局属性,并将其存储在本地缓存中。 在创建框架的最后,我们需要添加下一个yPosition,以便该列下面的单元格知道它的开始位置。 我们还将为下一遍设置该列。 最后,我们需要用新的高度更新contentHeight属性。 contentHeight + = collectionView.contentInset.bottom var collectionViewContentSize:CGSize 这只是返回我们在prepare方法中刚刚计算出的collectionView内容区域的大小。 func preferredLayoutAttributesFitting(_ layoutAttributes:UICollectionViewLayoutAttributes)-> UICollectionViewLayoutAttributes 这可能是使布局正常工作的最困难的部分。 我们发现没有多少文档对我们有帮助,因此为此进行了大量的尝试和错误。 在准备好布局之后,我们像往常一样将一个单元出队,并会自动调用preferredLayoutAttributesFitting。 这是单元格有机会指示其首选属性(包括尺寸)的位置,我们使用自动布局来计算这些属性。 我们将垂直fittingSize设置为压缩,因为我们希望像元在满足其约束的情况下尽可能达到最小高度。 该方法的关键是systemLayoutSizeFitting…因为我们的collectionView垂直滚动,所以我们可以将水平优先级设置为.required-这意味着它只能与预先计算的宽度一样大。 垂直优先级设置为.defaultLow,因为我们需要单元能够增长。 最初,我们弄错了这一点,最终导致一些单元会增长到1000像素…… 现在,布局将调用invalidate,在其中我们检查自originalAttributes之后单元格的高度是否已更改。 如果没有的话,我们会忽略它,但是如果有…… func […]

Xcode-swift3自动布局

最佳编程工具“ Xcode”中最好的功能之一是“自动布局”,当我们为iPhone应用程序设计场景时,如果您不熟悉前端语言(就像我一样),那将是最困难的部分开发应用程序。 现在,Apple为我们创建了一份礼物,即Xcode中的Auto布局! 第一种做法是在同一水平线上制作三个图像视图,它们必须自动具有相同的高度和相同的宽度,并且width:height应该为1:2,并且到屏幕两边的距离应该分别为20邻居是10岁,你可以看到我在图片中所做的 接下来的做法是让两个按钮并排放置,位于屏幕的垂直中心,彼此之间的距离为10,看我在图片中的操作方式 在这种情况下,我使左按钮在主视图的中心变为-5,右按钮将在中心的5指向中心,以使拖曳按钮彼此之间相距10个点,并且始终位于屏幕的中心。 在下一种情况下,我必须在同一水平线上创建三个按钮,彼此之间以及与屏幕侧之间的距离相同,并且该距离随着设备的大小而增加或减少。 在这种情况下,最棘手的部分是没有直接坐着的东西可以使物品之间的距离相等(只有大小可以做到),为解决此问题,我拖动了四个视图以分离按钮,并将彼此之间的距离设置为0,然后将四个视图的大小设置为自动相同,因此彼此之间的按钮以及屏幕的大小将看起来相同。 请看下面的图片(我对这些视图使用不同的颜色以使其清晰可见) 下图是我以前制作的“唐诗三百首”应用程序,在该应用程序中,我也使用自动布局来控制场景,例如,在文本视图中显示诗人的内容,并且约束以控制其在场景中的高度,宽度和位置。 自动布局确实是Apple编写的给程序员的礼物,它可以帮助我们更轻松地设计自己的应用程序! 现在就尝试学习它!

自动布局Swift 3

Un enquequevíacódigo ¿Quées el自动版式? 在自动布局和手动模式之间,在手动和手动模式下进行可视化。 Hay dos Implementaciones del Autolayout,无需使用Storyboard或Apple llama的InterfaceBuilder,也可以使用基于锚点的方法进行操作 。 安博斯(Ambos)征服了儿子的证明,并证明了他在西班牙的保护性和合法性。 界面生成器 Echemos un vistazo a la manera como funciona Interface Builder。 Cuando abrimos和Storyboard aparece un rearea se de no nos mover las vistas y empezar a jugar con ellas。 阿奎斯·唐德·科多恩扎 弱势群体,维莫斯·辛科·埃尔拉门蒂斯·德·伊基奎尔达·德·雷科查·阿尔·佩雷斯,《现实世界》,《限制条件》,《反对革命》,《反对派》,《 Herramienta podemos reubicarlas。 StackView上的segundo icono es para agrupar las vistas seleccionadas […]

使用Swift探索视觉格式语言

几周前,我开始介绍如何在Objective-C和Swift中使用自动布局的想法,以确保我的应用在所有iOS设备上都能正确显示。 您可以在Interface Builder(IB)中创建约束或以编程方式构建约束。 具有视觉设计的背景,我立即着迷于IB,因为它使我想起了许多设计程序。 实际情况似乎是,构建程序约束的时间往往会被可能与您的项目一起工作的其他人重用和可读性更高。 因此,我很想知道是否可以通过某种方式在视觉上构造程序约束。 使用视觉格式语言输入约束。 视觉格式语言 视觉格式语言允许您使用视觉语法字符串构建程序约束。 想法是文本在视觉上与布局匹配。 这是摘录的Apple文档: 完整的布局线 H:|-[查找]-[findNext]-[findField(> = 20)]-| 让我们分解一下: H :(水平)//水平方向 | (管道)// superview -(破折号)//标准间距(通常为8点) [](方括号)//对象名称(uilabel,unbutton,uiview等) ()(括号)//对象的大小 因此,如果我们要说一句话,我们会说findButton是距超级视图的开头(左边缘)的填充点(空白)为8点,而距findNextButton的开头的填充点为8点。 findNextButton是距findField的开头的8个填充点。 最后,findField的大小至少为20点,并且距超级视图的尾部(右侧)有8个填充点。 上面的代码特别有趣的是,它同时处理(设置)对findButton,findNextButton和findField的所有水平约束。 这里发生了很多魔术,所以我将尽力向您介绍如何在模拟项目中实现此功能的基本示例。 在一个快速的项目中,我们需要向您的超级视图添加一些对象,我们也可以附加约束。 我还喜欢为您的对象添加背景色,以便在测试约束时可以看到它占用的空间: 覆盖func viewDidLoad(){ super.viewDidLoad() //创建四个视图对象以表示我们的超级视图中的元素 让topBar = UIView() 让middleFrameTop = UIView() 让middleFrameBottom = UIView() 让bottomBar = UIView() //设置这些子视图的背景颜色 topBar.backgroundColor = UIColor.grayColor() middleFrameTop.backgroundColor = UIColor.orangeColor() middleFrameBottom.backgroundColor […]

使用EasyPeasy掌握自动版面设计I:简介

欢迎使用本系列教程,这些教程将教您自动布局,从最基础的知识到您可能会发现的布局最复杂的任务。 尽管仅涉及使用NSLayoutConstraints编程工作, NSLayoutConstraints大多数内容都可以推断为使用Interface Builder。 十分简单 我们将使用EasyPeasy代替纯UIKit 。 有很多流行的Auto Layout库,它们提供了使AL更简单的语法糖,例如SnapKit , Cartography或PureLayout ,那么,为什么要使用EasyPeasy? 简单性:提供一种简洁但功能强大的领域特定语言。 类固醇上的自动布局:提供其他一些附加功能,例如冲突解决,有条件地应用约束,特征集支持,在不保留引用的情况下更新约束以及简洁的调试模式。 可靠性:也许由于其在近1年的使用寿命中100%的代码覆盖率,尽管安装了120个CocoaPods和190个存储库克隆(每周编号),但尚未报告任何实际错误。 但是,如果这还不够的话,那就是上述库的简短比较:

UICollectionView:如何轻松处理更新

使用CollectionViews或TableViews时,困难的部分是需要添加,删除,移动某些单元格或更新其内容时。 使用装饰视图时甚至更多。 介绍 查看以下两个数组: let old = [“ A”,“ B”] let new = [“ B”,“ C”] 这些数组之间的差异非常容易计算: Deleted:[0] //旧数组中的索引 已移动:[(从:1,至:0)] 插入的:[1] //在新数组中的索引 重新加载:[] 要计算此差异,我们使用一个键比较两个数组,在这种情况下,这是数组中的值。 使用key,我们可以计算move , delete和inserts 。 删除了位置0的键A 钥匙B从位置1移到位置0 键C插入位置1 当我们要计算两个数组之间的重载索引时,它变得更加复杂。 我们还需要一个key和一个值。 如果值更改,我们需要重新加载该项目。 let old = [(键:“ A”,值:0),(键:“ B”,值:0)] let new = [(键:“ C”,值:0),(键:“ B”,值:1)] 差异的结果: 已删除:[0] //键A已删除 感动:[] 插入:[0] //插入键C 重新加载:[1] // B的值已更改 […]

在没有UIView的情况下构建UI

在约翰·桑德尔(John Sundell)在Scale上播放的精彩视频的鼓舞下,我决定写更多有关组件驱动的UI,为什么要这么做以及如何做(针对iOS)的文章。 我将在另一篇文章中向您介绍LeeGo,并向您展示如何使用它制作组件驱动的本机UI。 但是,现在,我将尝试仅关注最基本的想法。 毕竟,让我们花一分钟… 只需考虑一下我们通常如何在iOS中设置UI。 无论使用或不使用Interface Builder,我们始终需要使用UIView实例。 要么手动设置视图框架,要么使用自动布局,我们总是需要添加一个UIView实例作为子视图。 无论是使用标准的自动布局API还是使用精美的第三方自动布局助手库,我们都始终将UILayout实例设置为自动布局约束。 问题是:在iOS中处理UI时, 总是存在UIView实例,该实例繁重,易变且需要主线程。 作为后果: –我们必须处理一堆冗长的代码或一堆IB文件,或两者。 –很难重复使用该代码,必须一次又一次重复类似的代码或IB文件。 –我们必须经常将UI配置逻辑从同一组件分离到不同的位置:一部分在IB文件中,其余部分在代码中。 随着复杂性的增加,这些问题最终将导致维护的噩梦。 通过摆脱UIView实例,开始重用UI中的所有内容 在讨论如何摆脱` UIView`实例之前,让我们进一步了解一下UI组件。 UI组件剖析 几乎所有UI组件(例如视图,标签,图像视图或其他内容)都可以分离,并分为5部分描述: 1.类型–哪一类? UIView或其子类。 这是定义UI组件所必须要做的唯一一件事。 2.名称-重用组件时的名称是什么? 组件需要一个名称才能重用。 名称可以代表该组件的性质。 例如“标题”,“字幕”,“头像”,“ likeButton”,“ favoriteButton”,“ subscriberButton”,“ date”等。 3.样式–组件本身的外观如何? 它可以是视觉外观,例如“ backgroundColor”,“ numberOfLines”,也可以是非视觉视图属性,例如“ userInteractionEnabled”,“ scrollEnabled”。 样式几乎总是可以键/值转换的,可以轻松地放入字典中。 4.子组件–父组件内部是什么? 它肯定是另一个UI组件,因此也可以以相同的方式递归地对其进行描述。 这意味着我们只需要子组件的名称即可在以后检索它。 5.布局–如何安排孩子? 如果有多个子组件,我们将需要一个布局。 这是棘手的部分。 我们不能通过手动设置框架或使用自动布局来避免UIView实例。 幸运的是,Apple还为我们提供了另一种方式:视觉格式语言。 VFL使我们可以用纯ASCII定义整个布局。 let layout = [“ H:| -20- […]

贴在屏幕底部的视图

今天,我们将看到如何将视图固定在屏幕底部。我们使用自动布局的程序化方法。 首先,我们创建带有一些文本的标签,例如“离线模式”。然后,将其放置在屏幕底部。 var lblOffline = UILabel() 然后在viewDidLoad()方法中,将视图添加到屏幕底部。 fileprivate func setupName(){ 令高度= CGFloat(50) //设置标签属性 lblOffline.text =“离线模式” lblOffline.backgroundColor = .red lblOffline.textAlignment = .center //步骤1 lblOffline.translatesAutoresizingMaskIntoConstraints = false //第2步 view.addSubview(lblOffline) //步骤3 NSLayoutConstraint.activate([ lblOffline.leadingAnchor.constraint(equalTo:view.safeAreaLayoutGuide.leadingAnchor), lblOffline.trailingAnchor.constraint(equalTo:view.safeAreaLayoutGuide.trailingAnchor), lblOffline.topAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor,常数:-height), lblOffline.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor), ]) } 就是这样做的。 谢谢阅读。 请感觉是否有任何疑问。 如果您喜欢这个,请鼓掌并支持我。