CoreGraphic框架解析 (十二)—— Shadows 和 Gloss (一)

版本记录

版本号 时间
V1.0 2019.02.11 星期一

前言

quartz是一个通用的术语,用于描述在iOSMAC OS X 中整个媒体层用到的多种技术 包括图形、动画、音频、适配。Quart 2D 是一组二维绘图和渲染APICore Graphic会使用到这组APIQuartz Core专指Core Animation用到的动画相关的库、API和类。CoreGraphicsUIKit下的主要绘图系统,频繁的用于绘制自定义视图。Core Graphics是高度集成于UIView和其他UIKit部分的。Core Graphics数据结构和函数可以通过前缀CG来识别。在app中很多时候绘图等操作我们要利用CoreGraphic框架,它能绘制字符串、图形、渐变色等等,是一个很强大的工具。感兴趣的可以看我另外几篇。
1. CoreGraphic框架解析(一)—— 基本概览
2. CoreGraphic框架解析(二)—— 基本使用
3. CoreGraphic框架解析(三)—— 类波浪线的实现
4. CoreGraphic框架解析(四)—— 基本架构补充
5. CoreGraphic框架解析 (五)—— 基于CoreGraphic的一个简单绘制示例 (一)
6. CoreGraphic框架解析 (六)—— 基于CoreGraphic的一个简单绘制示例 (二)
7. CoreGraphic框架解析 (七)—— 基于CoreGraphic的一个简单绘制示例 (三)
8. CoreGraphic框架解析 (八)—— 基于CoreGraphic的一个简单绘制示例 (四)
9. CoreGraphic框架解析 (九)—— 一个简单小游戏 (一)
10. CoreGraphic框架解析 (十)—— 一个简单小游戏 (二)
11. CoreGraphic框架解析 (十一)—— 一个简单小游戏 (三)

开始

首先看下写作环境

Swift 4.2, iOS 12, Xcode 10

通过应用阴影和光泽(shadows and gloss)使您的UI元素脱颖而出。 阴影营造出一种深度感,而光泽则让您的元素闪耀。

在iOS 6之前,光泽(gloss)效果在iOS中很常见,从按钮和条形图到UIKit中的几乎任何元素。 在iOS 7中,Apple将其设计方法改为更扁平的界面。 这并不意味着使用光泽效果是错误的或过时的! 了解如何创建它们仍然很重要。

Core Graphics使其变得简单。

在本教程中,您将学习一个名为Cool Table的项目。 该项目本身涵盖了许多关于Core Graphics的主题,但在本教程中,您将专注于如何在视图上创建阴影和简单的光泽效果。

首先,打开已经下载好的项目,并在Xcode中打开启动项目并运行它。

您将看到一个由两个部分组成的分组表,每个部分都有一个标题和三行。 你在这里要做的所有工作都将在这些部分的标题视图中,因此不必担心行。


The Drawing Canvas

现在,该表通过tableView(_:titleForHeaderInSection :)显示节标题,它不允许在标题中进行太多自定义。 为了能够自定义它,您需要使用tableView(_:viewForHeaderInSection :)设置标头。

值得了解的是,有两种方法可以创建标题视图:

  • 您可以仅使用代码创建自定义视图。
  • 您可以使用Interface Builder创建自定义视图。

两者都是不错的选择,但在这里,你将采取第二种方法。 您将在Interface Builder中创建和自定义视图,并将其作为header view提供。

1. Creating the Files

Project导航器中,使用Cocoa Touch Class模板创建一个新文件。 将类命名为CustomHeader。 确保它是UIView的子类,语言是Swift。

创建空UIView子类后,创建名为CustomHeader.xib文件。 这一次,不要在模板选择中选择Cocoa Touch Class,而是在User Interface组中选择View。

在新的XIB文件中,您将找到一个视图。 在Identity检查器中,将其类从UIView更改为CustomHeader,这是您刚刚创建的类。

现在您需要header来显示section名称。 请遵循以下三个步骤:

  • 1) 从View菜单中打开Library,然后将label拖到XIB文件内的视图上。
  • 2) 为标签创建所有四个约束,左右两个点间距分别为4,顶部距离0,底部距离10。
  • 3) 在“属性”检查器中,将其文本对齐方式设置为center
  • 4) 再次选择CustomHeader视图。 在“属性”检查器中,将Simulated Metrics组中的SizeInferred更改为Freeform
  • 5) 在Size inspector中,将视图的高度设置为50。

接下来,在CustomHeader.swift中,为UILabeloutlet添加此行。 确保将其连接到XIB文件中。

@IBOutlet public var titleLabel: UILabel!

2. Loading the View

下一步是从interface file加载视图并将其提供给table view。 要完成此操作,请在outlet后面添加以下方法:

class func loadViewFromNib() -> CustomHeader? {
  let bundle = Bundle.main
  let nib = UINib(nibName: "CustomHeader", bundle: bundle)
  guard 
    let view = nib.instantiate(withOwner: CustomHeader())
      .first as? CustomHeader
    else {
      return nil
    }
  return view
}

loadViewFromNib()是一个为您创建并返回CustomHeader的类方法。

接下来,在CoolTableViewController.swift中,在类的末尾添加此方法:

override func tableView(
  _ tableView: UITableView,
  viewForHeaderInSection section: Int
  ) -> UIView? {
  guard let customHeaderView = CustomHeader.loadViewFromNib()
    else { return nil }
  customHeaderView.titleLabel.text = self.tableView(
    tableView,
    titleForHeaderInSection: section)
  
  return customHeaderView
}

代码按照上一步骤中的说明加载视图,设置label的文本,并返回新视图。

建立并运行。 您将看到刚刚使用白色背景创建的新header


Drawing the Masterpiece

现在你有了一个标题画布,你已经准备好了有趣的部分。 首先,考虑一下你将要绘制的杰作中需要什么。

header分为两个区域。 在上图中,有三点需要注意。

  • 带有光泽的渐变色。
  • 彩色区域下方的一个小阴影。
  • 标题周围的stroke line

阴影区域是10点。 这就是label下的底部约束为10的原因。您知道完整标题的高度为50。因此,彩色区域为40。


Preparing the Header

为什么不通过赋予每种不同的颜色来直观地定义这些区域? 您将为渐变区域指定红色背景并使阴影区域变为绿色。

CustomHeader.swift中,在标题label声明后面添加以下行:

@IBInspectable var coloredBoxHeight: CGFloat = 40

@IBInspectable值允许您直接从Interface Builder执行尽可能多的UI自定义。

将任何数字声明为常量或属性而不是在代码中分散许多数字是一种很好的做法。 大多数情况下,几天后查看自己的代码时,您会忘记使用的具体数字。

CustomHeader的末尾添加此方法:

override func draw(_ rect: CGRect) {
    // 1:
    var coloredBoxRect = bounds
    coloredBoxRect.size.height = coloredBoxHeight
    
    var paperRect = bounds
    paperRect.origin.y += coloredBoxHeight
    paperRect.size.height = bounds.height - coloredBoxHeight
    
    // 2:
    let context = UIGraphicsGetCurrentContext()!
    
    context.setFillColor(UIColor.red.cgColor)
    context.fill(coloredBoxRect)
    
    context.setFillColor(UIColor.green.cgColor)
    context.fill(paperRect)
  }

UIViewdraw(_:)是放置任何您想要用来更改自定义视图外观的自定义绘图代码的位置。 默认绘制方法不执行任何操作。 因此,请确保您重写。 这里有两个步骤:

  • 1) 计算要着色的两个矩形。 第一个是具有渐变的区域。 第二个是阴影区域。 两者都是基于您之前定义的coloredBoxHeight计算的。
  • 2) 获取当前的Core Graphics上下文并绘制两个彩色矩形。

现在,直接从Attributes inspectorCustomHeader.xib中标题的label文本颜色更改为白色。

建立并运行。 你应该看到你的彩色标题。


Drawing Drop Shadows

现在明确定义了矩形,添加阴影。 在CustomHeader.swift中,在coloredBoxHeight之后添加这两个变量:

var lightColor = UIColor(red: 105/255.0, green: 179/255.0, blue: 216/255.0, alpha: 1)
var darkColor = UIColor(red: 21/255.0, green: 92/255.0, blue: 136/255.0, alpha: 1)

接下来,在draw(_ :)方法中,从方法的底部删除以下四行。

context.setFillColor(UIColor.red.cgColor)
context.fill(coloredBoxRect)
    
context.setFillColor(UIColor.green.cgColor)
context.fill(paperRect)

然后添加下面这些行:

// 1:
let shadowColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 0.5)
// 2:
context.saveGState()  
// 3:
context.setShadow(
  offset: CGSize(width: 0, height: 2), 
  blur: 3.0,
  color: shadowColor.cgColor) 
// 4:
context.setFillColor(lightColor.cgColor)
context.fill(coloredBoxRect) 
// 5:
context.restoreGState()

这就是你画阴影的方式! 以下是上述代码的含义,一步一步看一下:

  • 1) 将阴影定义为灰色,透明度为50%。
  • 2) 保存当前图形状态,以便您可以应用所需的任何配置更改,并在完成后返回到此状态。
  • 3) 为要绘制的任何内容设置阴影配置。
  • 4) 画出彩色的盒子。 如果没有这个,屏幕上就不会有阴影。
  • 5) 返回上面保存的图形配置。

最后,在CoolTableViewController.swift中,在return之前的tableView(_:viewForHeaderInSection :)的末尾添加以下行:

if section == 1 {
  customHeaderView.lightColor = UIColor(
    red: 147/255.0,
    green: 105/255.0,
    blue: 216/255.0,
    alpha: 1)
  customHeaderView.darkColor = UIColor(
    red: 72/255.0,
    green: 22/255.0,
    blue: 137/255.0,
    alpha: 1)
}

这是为第二个table section显示不同的颜色。 darkColor尚未使用,所以不要担心。

建立并运行。 您应该看到上次运行应用程序时的巨大改进。 标题现在看起来更好,对吧? 接下来,您将添加光泽效果。


Adding a Gloss Effect

应用光泽效果的方法不止一种。 Matt GallagherMichael Heyeck解释了更难的方法,但在这里,你将学习一种简单的方法。

为简单起见,通过应用渐变alpha蒙版来实现光泽效果的近似是现在足够好的方法。

专业提示:这是一种常用的方法,为什么不把它放在一个单独的文件中,以便在以后的项目中轻松访问?Extensions.swift是该作业的文件。 它有一些方便的扩展,使事情变得更容易。

CGContext扩展的末尾,添加以下方法:

func drawGlossAndGradient(rect: CGRect, startColor: UIColor, endColor: UIColor) {
  // 1:
  drawLinearGradient(rect: rect, startColor: startColor, endColor: endColor)
  // 2:
  let glossColor1 = UIColor.white.withAlphaComponent(0.35)
  let glossColor2 = UIColor.white.withAlphaComponent(0.1)
  // 3:
  var topHalf = rect
  topHalf.size.height /= 2
  // 4:
  drawLinearGradient(rect: topHalf, startColor: glossColor1, endColor: glossColor2)
}

以下是上面代码的作用:

  • 1) 从示例项目中调用扩展文件中的另一个方法,该方法在矩形中绘制双色渐变。
  • 2) 定义两种白色光泽颜色。
  • 3) 计算将具有白色渐变或光泽的矩形。 此矩形是彩色渐变区域的一半。
  • 4) 在较小的矩形中绘制白色渐变。

CustomHeader.swift中,在draw(_:)结束时,添加以下行:

context.drawGlossAndGradient(
  rect: coloredBoxRect,
  startColor: lightColor,
  endColor: darkColor)

构建并运行。 你会看到一个漂亮的标题,带有渐变色和光泽效果。

你需要的最后一件事是在标题的彩色区域周围进行stroke。 在刚添加的行之后,添加以下行:

context.setStrokeColor(darkColor.cgColor)
context.setLineWidth(1)
context.stroke(coloredBoxRect.rectFor1PxStroke())

建立并运行。 注意你想要的较暗的stroke

CGContext有很多有趣的绘图工具,可用于绘制路径,线条,形状,文本和图像。 值得查看developer documentation并进行实验。

后记

本篇主要讲述了Shadows 和 Gloss,感兴趣的给个赞或者关注~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容