Tag: swift

如何使用Swift 2.2设置BLE

BLE与iPhone配合使用时,需要遵循一个特定的顺序。 Apple的文档被截断了,似乎没有为这些步骤提供清晰的流程。 在线上有摘要,您可以参考其他人的应用程序,但没有任何内容可以解释我所看到的每个步骤中正在发生的事情。 希望这篇文章可以帮助解释它,并避免您遇到与我同样的问题。 与往常一样,有不同的实现方式,所以请让我知道是否存在更有效的处理方式。 步骤1:将CoreBluetooth添加到您的应用程序 首先,为了使用蓝牙,您需要向您的应用程序添加CoreBluetooth库。 要添加CoreBluetooth,您需要选择父Xcode文件。 在“使用库链接二进制文件”部分中,单击“ +”按钮,搜索CoreBluetooth,选择并添加它。 现在,在您的ViewController中,您需要导入CoreBluetooth。 与“导入UIKit”一起添加“导入CoreBluetooth”。 步骤2:利用CoreBluetooth的CBCentral和CBPeripheral 您想从CoreBluetooth中在类中使用CBCentralManagerDelegate和CBPeripheralDelegate协议,因为这将允许您使用委托必须采用的方法,从而可以管理充当蓝牙连接的中心和外围设备的对象。 将CBCentralManagerDelegate和CBPeripheralDelegate添加到“ ViewController”类后,您需要将委托的对象存储在变量中,以便可以调用每个对象的方法。 到目前为止看起来应该像这样: 步骤3:运行CBCentralManager 您的电话将充当中心。 要启动您的中央管理器,您可以将其放置在viewDidLoad()函数中并将其委派给自己。 但是,我将其放置在其自己的功能(“ startManager”)中,以便我们可以控制手机何时启动其顺序,稍后我将对此进行解释。 步骤4:检查BLE是否开启,然后开始扫描 接下来,在我们开始扫描之前,我们需要确保设备的蓝牙电源已打开。 为此,您可以使用预设函数,如果状态已更新,则该函数将被调用并传入CBCentralManager对象。 一旦确定它已开机,就可以调用该函数以开始扫描(scanForPeripheralsWithServices)。 步骤5:找到您的BLE设备并连接到它 要查看所有可用的设备(外围设备),您可以使用didDiscoverPeripheral监听发现的外围设备。 如果这样,它将返回可以存储的每个外围对象。 与其存储每台设备,我只专注于我想要的设备。 找到后,您应该将该外围设备保存到变量中,以备后用。 要连接到发现的外围设备,可以使用centralManager的connectPeripheral方法并引用外围设备。 我添加了该选项以通知我是否断开连接。 连接后,您将要停止扫描。 添加CentralManager侦听器didDisconnectPeripheral非常重要,这样如果断开连接就可以重新启动扫描(这就是为什么我将开始扫描分为一个单独的函数)。 步骤6:获取服务,特征并向设备发送价值 连接到外围设备后,即可找到其服务和特性。 对于外围设备,可以有很多服务,对于服务可以有很多特征。 如果要在BLE设备上写一个值或进行任何更改,则需要确保您正在写正确的服务或特性。 对于我想做的事情,我需要写出我们在BLE设备上拥有的服务的特定特征。 因此,现在使用的是保存的外围对象中的功能,而不是使用centralManager对象中的功能。 要找到服务,您可以在连接后调用discoverServices。 然后,查看didDiscoverServices侦听的外围设备上的服务。 发现后,您可以在该服务上调用discoverCharacteristics。 进行didDiscoverCharacteristicsForService侦听后,将与特征对象一起返回。 我循环浏览这些特征以找到所需的特征,然后可以将其保存在变量中以供以后写入。 在下面,我立即将其写入特征,但在完整的应用程序中将其保存并稍后使用。 要写入外设,您可以在外设对象上调用方法writeValue并传入编码后的值,并调出要写入的特征。 奖励:RSSI 对于我想与该应用程序一起做的事情,我想大致了解一下我离该设备有多远,外围设备的RSSI读取非常适合。 Apple已弃用RSSI功能,因此您需要创建解决方法。 为此,我使用了一个计时器(如果您找到更好的方法来处理此问题,请告诉我)。 当您找到外围设备时,它将为您提供一次RSSI;当您连接到外围设备时,它将再次为您提供RSSI。 为了保持流式传输,您需要继续调用相同的函数。 要读取RSSI,可以在外围对象上调用函数readRSSI。 […]

应用生命周期事件处理

今天的话题是关于Apps的生命周期的,当我们创建一个新项目时,在Appelegate中编写了五个主要事件处理程序。 func application(_ application:UIApplication,didFinishLaunchingWithOptions launchOptions:[NSObject:AnyObject]?)->布尔{ //应用程序启动后进行自定义的替代点。 返回真 } func applicationWillResignActive(_ application:UIApplication){ 打印(“ \(#功能)”) //当应用程序即将从活动状态变为非活动状态时发送。 对于某些类型的临时中断(例如打来的电话或SMS消息),或者当用户退出应用程序并开始过渡到后台状态时,可能会发生这种情况。 //使用此方法可以暂停正在进行的任务,禁用计时器并使图形渲染回调无效。 游戏应使用此方法暂停游戏。 } func applicationDidEnterBackground(_ application:UIApplication){ 打印(“ \(#功能)”) //使用此方法释放共享资源,保存用户数据,使计时器无效以及存储足够的应用程序状态信息,以防您的应用程序在以后终止时恢复到当前状态。 //如果您的应用程序支持后台执行,则在用户退出时将调用此方法,而不是applicationWillTerminate:。 } func applicationWillEnterForeground(_ application:UIApplication){ 打印(“ \(#功能)”) //作为从后台到活动状态的过渡的一部分调用; 在这里,您可以撤消输入背景时所做的许多更改。 } func applicationDidBecomeActive(_应用程序:UIApplication){ 打印(“ \(#功能)”) //重新启动应用程序处于非活动状态时已暂停(或尚未启动)的所有任务。 如果该应用程序以前在后台运行,则可以选择刷新用户界面。 } func applicationWillTerminate(_ application:UIApplication){ 打印(“ \(#功能)”) //在应用程序即将终止时调用。 如果合适,保存数据。 另请参阅applicationDidEnterBackground:。 } 我将通过使用NotificationCenter方法编写一些代码来监视“ ApplicationDidEnterBackground”和“ ApplicationDidBecomeActive”,我想做的是计算应用程序进入后台的次数以及回到前台的次数,何时应用程序转到后台,中间标签的值将减为1,当它回到最前面时加2,以下是我的代码,我写了一些注释来解释这些代码的作用。 导入UIKit 类ViewController:UIViewController […]

戴夫·托马斯(Dave Thomas)的数据整理卡塔(Kata)的快速解决方案,第2部分

戴夫·托马斯(Dave Thomas)的数据整理卡塔(Kata)的快速解决方案,第2部分 如果您还没有阅读我对Dave数据处理kata的第1部分的解决方案,请首先进行检查。 第2部分要求我们清理分析英超联赛足球(您知道,足球)结果的数据集。 文件football.dat包含2001/2英超联赛​​的结果。 标记为“ F”和“ A”的列包含该赛季每个球队得分和对阵球队的进球总数(因此,阿森纳对阵对手的进球为79球,对阵对手的进球为36)。 编写一个程序,以在“达成”和“反对”目标中差异最小的团队的名字打印出来。 此练习与第1部分非常相似,并且可以重复使用许多原始代码。 这篇文章将重点讨论第1部分和第2部分之间的区别。[GitHub上的完整代码]。 模型 我们需要的是FootballResult模型,而不是WeatherRecord。 在计算/反对增量变量的目标时,我们需要它们的差的绝对值。 这是因为使用WeatherRecord时,最高温度始终高于最低温度,但在这种情况下,任一变量都可以更高。 在将充满字符串的表转换为模型对象时,我还采用了另一种方法。 对于天气记录,可以将所有三个值建模为整数(月日索引,maxTemp,minTemp)。 在本练习中,我们需要一个teamName:String,GoalScoredFor:Int和GoalScoredAgainst:Int。 我选择为我的结构编写一个自定义init,该结构接受三个字符串并将目标字符串转换为Ints。 原因是模型负责将值转换为特定类型。 执行者不应该承担这项责任。 数据变压器 第一个区别是足球数据都不是“脏”的,因此我们可以删除cleanData步骤。 其次,如“模型”部分所述,我们在FootballResult上有一个自定义的init方法,因此我们不需要.convertStringsToInts()方法。 在“天气”数据集中,我们只需要获取前三列,因此我们遍历了所有行,并且对于每行,i .. <3用于获取前三列。 我对此解决方案不满意,因此在这里重新设计以使用flatMap。 #somuchcleaner 静态函数removeUnneededColumns(fromTable表:[[String]])-> [[String]] { 返回table.flatMap {(行:[String])在 返回[行[1],行[6],行[8]] }} .flatMap()最出名的是将数组数组“展平”,从而使[[“ a”,“ b”],[“ c”,“ d”]展平为[“ a”,“ b”,“ c”,“ d”]。 但是.flatMap()也可以映射并返回一个数组,该数组包含的元素要少于传递给它的元素(.map()不能做到的事情)。 在这种情况下,我们将取出需要保留的列的单元格并返回它们。 *快乐的舞蹈* 然后在适当的时候将名称从天气更改为足球,这就是第1部分和第2部分之间的所有差异。正如Dave所建议的那样,我没有偷看kata的第3部分,但我想我们会做点什么更通用。

Xcode中的Info.plist文件

在本文中,我将解释您的Xcode项目中的Info.plist文件是什么,它在做什么以及如何使用它。 在我们开始之前,有一些术语需要熟悉。 捆绑包:您可以将捆绑包视为项目的目录。 这是所有文件的有组织的文件夹。 当您需要在项目中访问和归档时,可以通过调用Bundle类的属性和方法来实现。 (苹果文档) 元数据: “一组描述并提供有关其他数据的信息的数据” 属性列表:属性列表基本上是键和值的字典,可以将其以.plist文件扩展名存储在文件系统中,这意味着可以通过Bundle类进行访问。 属性列表用作存储少量数据的轻量级便携式方法。 它们通常用XML编写,但是Xcode很漂亮,并且能够将XML文件转换为您在项目中看到的干净且可编辑的版本。 (苹果文档) 信息属性列表 现在我们了解一些术语,我们可以更好地了解什么是Info.plist文件以及为什么需要它。 从苹果文档: 信息属性列表文件是结构化的文本文件,其中包含捆绑的可执行文件的基本配置信息。 文件本身通常使用Unicode UTF-8编码进行编码,内容使用XML进行结构化。 XML根节点是一个字典,其内容是描述捆绑软件不同方面的一组键和值。 系统使用这些键和值来获取有关您的应用及其配置方式的信息。 因此,所有捆绑的可执行文件(插件,框架和应用程序)都应具有信息属性列表文件。 那么这是什么意思? —每个应用程序都应具有一个Info.plist文件,以便系统可以读取该文件并根据其包含的值进行工作。 创建新项目时,将为您提供一个Info.plist文件,其中包含默认设置,所有这些都可以自定义。 在每一列的顶部,您可以看到“键”,“类型”和“值”。 听起来像字典吧? 键是一个字符串值,并且该值是在type列上指定的类型。 关于Xcode显示文件的方式的一些注意事项,如果尝试使用Info.Plist文件中可见的键访问值,则会收到错误消息。 在文件的XML版本中可以找到正确的密钥。 您可以通过在文本编辑器(例如Sublime Text或Atom)中打开文件来查看plist的XML版本。 *编辑-您也可以右键单击Info.plist文件,然后选择“另存为”>“源代码”。 让我们看一下“主故事板文件的基本名称”。 我们可以使用以下代码在程序中访问它的值: 让exampleValue = Bundle.main.object(forInfoDictionaryKey:“ UIMainStoryboardFile”)为! 串 打印(exampleValue) 运行此代码会将“ Main”打印到控制台,这是Info.pList文件中列出的值。 请注意,键是“ UIMainStoryboardFile”,而不是“ Main Storyboard File base name”。 能够读取XML文件很方便-您可以在第25行找到正确的密钥。 将鼠标悬停在现有属性上时,通过单击“ +”号将其他属性添加到plist也很容易。 这将为您的plist添加一个新密钥,并且将提示您从一长串可以自定义的内容中选择一个密钥-或根据需要创建唯一的密钥。 然后,您可以使用与上述相同的方法访问该值。 完整的按键列表及其作用

Java(和JavaScript)中的枚举

枚举是一个看似简单的概念。 作为Java中自己的数据类型,它们允许开发人员用语义代码表示相关的抽象项目集,而不会冒着选择使用字符串可能带来的风险。 与抽象项目集相关的一些示例是: 方向 调色板中的颜色 交通灯颜色 季节 卡组中的卡片 您可能会想,“为什么这些项目在尝试用代码表示时可能会引起麻烦?”,但重要的问题是:“这些项目的最逻辑表示是哪种数据类型?”如果您回答整数,考虑到通过以整数表示交通信号灯颜色,您还可以对它们进行数学运算: 现在,TrafficLightColor.YELLOW + TrafficLightColor.GREEN =3。这看起来合乎逻辑吗? 此外,通过将它们存储为整数,它们不是唯一的,这意味着它们可能会与另一个整数值混合; 同样的问题也会在调试时引起问题。 如果将它们存储为枚举,则它们的值是人类可读的: 从本质上讲,Java中的枚举有助于防止使用无效常量进行比较,使用不必要且可能有错误的字符串或整数比较,并保持代码更干净。 JavaScript中的枚举 JavaScript中的枚举在本质上与Java中的枚举相同,但是它们不是本机的,必须从诸如Enumify之类的库中导入。 在Enumify中,每个枚举都有两个属性:枚举值的名称,其序数或枚举值在enumValues数组中的位置。 JavaScript是一种弱类型语言,在声明数据类型时不具有与Java相同的刚性,因此具有更高的灵活性(并且通常具有更大的语义),但完全由开发人员决定导入诸如Enumify之类的库的决定,但取决于您正在编写的程序,可以节省大量时间。 为此,我发现关于JavaScript枚举最有用的一件事是,在点和括号符号方面,它们与对象没有相同的约束。 将项目存储为枚举而不是字符串值使您可以使用点表示法访问它们。 这是一个很小的余地,但是肯定可以使代码更易于阅读和浏览。

我想在2017年参加5个iOS会议..

去年,我与一群朋友和同事一起去了旧金山在wwdc和altconf举行的两次iOS大会。 不幸的是我没有被选中参加wwdc,所以我只能看altconf谈话。 幸运的是,苹果稍后会提供会议的所有视频。 在这个特殊的星期里,旧金山欢迎来自世界各地的许多开发商。 毫无疑问,这是一年中最美好的时光之一,至少对于那些挖掘技术领域的人而言。 参加技术会议真是太了不起了,这是结识新朋友,接触新想法,学习,共享和扩大您的舒适区域的巨大机会。 几天前,我在Ray Wenderlich很棒的博客上看到了一篇有关2017年10个iOS会议的帖子。 所以我想在这里写一篇我想在2017年参加的5个会议的帖子。 会议: 尝试! 迅速 尝试! Swift是一系列相当新的会议,由去年的机器人Natasha发起。 第一版是在日本,日本是一个社区众多但国际活动很少的国家。 在社区的帮助下,第一届活动非常成功,以至于明年将举行三场会议:东京,纽约和班加罗尔。 尝试! 迅捷会议 尝试! Swift是一个沉浸式社区,汇集了有关Swift语言最佳实践和Swift中的应用程序开发的信息…… www.tryswift.co 迅捷的阿尔卑斯山 他们在自己的媒体“雨燕阿尔卑斯山”上写了一篇文章。 这个事件是关于社区的 。 期。 主要目标是与所有其他参与者一起尝试使用Swift编程语言,尝试在失败的前提下尽可能多地学习。 Ash Furrow写了两篇有关“规范化斗争”和后来有关“共情文明”的惊人文章,对于有兴趣加入我们参加此活动的人来说,这是两篇很棒的读物。 这两篇文章都总结了Swift Alps想要解决的问题以及即将发生的事情。 迅捷的阿尔卑斯山 每个导师将有一群人,对他们准备的主题进行实验,也许最终目标是… theswiftalps.com AltConf AltConf确实是一个很棒的会议,去年我在这里度过了如此美好的时光,可以肯定的是,我想多次参加。 AltConf展示了我们社区的精华。 优秀的人会自愿投入时间和技能,为每个希望参加WWDC周狂潮但又买不到Apple活动的门票的人提供一个包容性的,可访问的活动。 人们只能希望苹果公司感谢由于AltConf的持续存在而在每年六月在整个旧金山传播的热情和善意。 —乔·齐普林斯基 AltConf 2016 AltConf是一个社区驱动的活动,旨在服务于开发人员和产品驱动的社区。 在圣市区举行… altconf.com 世界发展中心 没有wwdc,没有iOS会议列表之类的东西。 这是一年中最大也是最重要的会议,也是唯一可以完全改变iOS游戏功能的会议。 不相信我吗? 到2014年,他们推出了Swift并颠倒了社区,情况如何呢? 为了更好, 为了更好 .. =) WWDC […]

面向协议的编程:一种快速的OOP头痛解决方案

为什么OOP如此受欢迎? 面向对象编程(OOP)是数十年来编写模块化代码的经典策略,并且有充分的理由。 可重用性:编写良好的对象是可以插入其他程序的独立实体。 如果实现了优化的树,则可以在现有项目的任何部分或全新的树中使用它,而无需编写更多代码。 跳过细节 :另一个程序员不需要知道您对象的实现。 如果看到“排序”功能,则可以使用而不必担心代码是什么样。 防错 :我们可以隐藏对类中函数或变量的访问,以防止其他不熟悉我们代码的开发人员创建错误。 其他人只会看到他们需要看的东西。 使大型项目易于管理:大型 项目变得复杂。 OOP使我们可以将一个大问题分解为一些子问题-每个子问题都由不同的对象处理。 如果Nabil,Julia和Alex正在制作太空侵略者游戏。 纳比尔(Nabil)可以建立一个代表外星人的对象,朱莉娅(Julia)可以建立一个GameBoard对象,该对象可以跟踪我的得分,生命数以及游戏开始/结束的时间,而亚历克斯(Alex)可以创建代表我的坦克及其导弹的对象。 最后,我们将这些对象组合在一起,以构建功能强大的游戏。 更新代码:使用模块化代码,随着时间的推移,我们可以轻松编写添加,更新或删除特定组件的代码。 例如,在用砖建造的建筑物中,您可以用新砖替换掉破裂的砖,而不必替换建筑物的整个部分。 与旧同在 虽然非常方便,但是OOP附带了很多问题: Massive View Controller,“ GOD”对象 :为了保持模块化,程序员使用一种类别,一种目的的主体。 但是,view肿的viewController和模型是流行的快速设计模式(MVC,MVVM)的常见副产品。 传递大块的对象会减慢您的代码的速度,并在构建时使模块化变得困难。 如果一个对象拥有您所需的太多功能,那么您编写的新代码也将最终取决于该对象。 多重所有权:假设您和一位工程师(Nick)正在使用引用同一BankAccount对象的单独ViewController。 如果您在firstViewController中添加功劳,而Nick在secondViewController中删除功劳,则两个人最终都会得到意外的结果。 类是通过引用传递的,因此,在项目的一个区域中更改值将导致该对象的值在所有其他位置均发生更改。 这使得很难测试功能对给定对象的隔离效果。 子类问题:如此之大的问题应有其自己的部分

Swift中的设计模式:观察者模式

欢迎来到一系列致力于学习设计模式的文章。 尽管许多想法与代码无关,但我们的目标是向您展示如何在Swift中实现它们(在撰写本文时为Swift 3.0)。 每个帖子彼此独立,所有项目代码都可以 在Git上找到 。 观察者模式允许对象订阅所谓的主题。 主题更新后,将通知所有已订阅主题的对象有关更新的信息。 当对象之间存在一对多关系时使用。 观察者模式的常见实现使您能够: 添加一个观察者 这实际上告诉主题“嘿,我想加入循环”,并且在更新其他观察者时保持更新。 将该主题想成小组中总是有八卦并且想告诉别人的人。 通知观察员 观察者订阅后,我们将调用接口中定义的共享函数。 所有观察者都将实现此接口。 移除观察者 可能希望删除对象,而不再希望对其进行更新,因此我们必须给予机会删除它们。 许多语言和SDK都有自己的实现。 iOS将其与Notification Center及其NSNotificationCenter类一起使用。 使用“推送通知”,用户可以订阅以收听来自应用程序的更新,然后应用程序/服务器( 主题 )将通知推送到用户设备,并且用户始终可以选择通过删除应用程序来取消订阅。 我们将使用一个用户希望以二进制,八进制和十六进制格式显示数字的示例。 他们只想输入一次该号码。 该程序的UML图将如下所示: 首先,在Xcode中创建一个新项目。 我们不会在UIKit中碰任何东西,因此创建一个macOS Terminal项目。 首先,我们将从创建观察者协议开始。 该协议将包含id属性。 这将使我们以后可以删除观察者。 该代码将如下所示: 接下来,我们将创建Subject类。 这将是负责通知对象有关更新的类。 当我们附加一个Observer时,我们将其添加到ObserverArray中 。 当我们通知其他对象时,我们遍历ObserverArray并调用Observer协议中包含的update()函数。 看起来像这样: 继承Observer协议的类的工作是为Subject分配一个id,并在从Subject调用update()方法时执行该方法。 它们将如下所示: 现在是时候将它们放在一起了。 在主类中,我们要创建一个Subject对象。 我们创建的所有观察者将被分配相同的Subject 。 然后,我们给主题分配一个数字。 然后,我们将再次进行显示更新。 它看起来像这样: 终端输出将如下所示: 二进制:1111 八进制:17 十六进制:f 二进制数:10 八进制:2 […]

在iOS和SQLite上使用Fluent

大家好,今天,我将尽我最大的努力,向您介绍安装和使用SQLite在iOS上使Fluent正常工作的经验。 Fluent是完全基于Swift 3.0编写的基于口才的ORM,由团队在Steam上创建。 它易于使用和设置,并且与Vapor进行了深度集成,Vapor是利用Swift 3.0的最新和有前途的Web框架之一。 我建议您看一下它们的主要仓库,在其中可以找到很多有希望的服务器端swift库:蒸气 本演练基本上适用于任何依赖基础C库的Swift框架。 在我的小冒险中,我严重依赖这些资源和教程: https://medium.com/swift-and-ios-writing/using-ac-library-inside-a-swift-framework-d041d7b701d9#.jsp34w5km http://stackoverflow.com/a/31757698/1233655 为什么呢 对于Vapor用户和服务器端敏捷开发人员而言,Fluent是使您的应用程序与后端之间的模型保持一致的好方法。 另外,Node使在您的应用程序和服务器之间传输JSON变得非常容易,Fluent很大程度上依赖于它以及Vapor。 现在开始吧! 创建一个iOS Xcode项目 这里没有技巧,这将是您的iOS应用程序项目。 您当然可以使用现有项目,它将与任何类型的iOS项目一起使用。 将Fluent集成到工作区中 此步骤旨在创建一个工作区,包括您的应用程序项目和FluentSQLite.xcodeproj, 为了在单个git clone获取所有框架,我们只需要获取将使我们能够将Fluent与SQLite一起使用的驱动程序,而swift软件包管理器将获取所需的所有依赖项。 git clone https://github.com/vapor/sqlite-driver.git 让我们生成Xcode项目,该项目将获取所有依赖项。 cd sqlite-driver / 迅捷包generate-xcodeproj 现在我们有一个适合Fluent的xcodeproject,让我们创建一个包含两个项目的工作区。 Fluent及其依赖项配置为仅在macOS上构建。 要更改此设置,我们需要转到FluentSQLite设置>构建设置,并将每个框架支持的平台从macOS更改为iOS。 (用箭头显示的列表) 更改支持的平台后,选择适当的iOS设备以在其上构建FluentSQLite。 导入CSQLiteMac 到目前为止,由于尚未导入CSQliteMac模块,因此无法编译。 您将需要从github获取它(我建议将其克隆到您项目的根目录) git clone https://github.com/vapor/csqlite 现在在项目的构建设置中,转到Swift搜索路径->导入路径,如果在项目的根目录中克隆了${SRCROOT}/csqlite则只需添加${SRCROOT}/csqlite ,否则添加路径。 就是这样! iOS默认情况下安装了sqlite,因此无需将其嵌入到项目中。 让我为您提供一个用于创建数据库的简单代码段,它是我添加到AppDelegate.swift中的一个简单函数:https://gist.github.com/adriencanterot/fc5fb983e55cab115440406e33c3e88f 欢迎在vapor.team上提问,并在vapor / fluent-example上查看Fluent-example! 社区反应异常活跃,如果有的话,我很乐意提供帮助!

玩CAGradientLayer — Swift 3.0

该博客旨在展示CAGradientLayer的基本实现。 👌 什么是CAGradientLayer? CAGradientLayer是CALayer的子类,它用于绘制填充图层形状(在任何圆角的边界内)的颜色渐变。 它是最简单的图层之一,因为实现它只需几行即可在UI中添加漂亮的彩色效果。 实施CAGradientLayer 渐变层的最基本实现只需两件事: 颜色数组(由于CAGradientLayer使用Core Graphics,因此必须为CGColor) 渐变层框架的大小。 但是最有可能的是,我们想控制渐变色的停止位置和重新开始的位置。 这是一个示例代码: 您可以在此示例代码中看到 gradient.colors是CGColor对象的数组,定义了每个渐变色标的颜色。 gradient.startPoint和gradient.endPoint定义了渐变相对于图层坐标空间边界的开始和结束位置。 (我总是更喜欢使用CGFloat,因为它更容易估计渐变的位置)。 让我们看一下在使用startPoint和endPoint. 在startPoint(0,0) & endPoint(1,0) 在startPoint(0,0) & endPoint(0,1) 在startPoint(0.25,0.25) & endPoint(1,1) 在startPoint(0.75,0.75) & endPoint(0,1) 动画怎么样? 当然! 您可以通过访问渐变图层的属性来为其设置动画,在此示例中,我尝试使用locations属性,并使用两种颜色在我的UIView中具有类似于扫描仪的效果。 这是输出: 希望您可以将其应用到您的超赞应用中! 🙌