67780296146ece82384be5e4fe1fd879
SwiftUI 特色组件之超酷图标组件 最全的图标emoji json(教程含源码)

实战需求

SwiftUI 特色组件之超酷图标组件

本文价值与收获

看完本文后,您将能够作出下面的界面

 SwiftUI 特色组件之超酷图标组件

SwiftUI 特色组件之超酷图标组件

 SwiftUI 特色组件之超酷图标组件

SwiftUI 特色组件之超酷图标组件

 SwiftUI 特色组件之超酷图标组件

SwiftUI 特色组件之超酷图标组件

emoji.json

emoji.json

kaomoji.json

kaomoji.json


核心组件

  • 网格可平稳滚动
  • 面板可平稳拖动
  • 列出要正确处理面板拖动手势的列表
  • 关闭后要向后向后滚动到顶部的列表
  • 部分标题选择器,以便能够导航到正确的部分
  • 滚动到相应部分时要更新的部分标题选择器
  • 键盘响应用户界面
  • 在顶部显示最近使用的表情符号部分
  • 深色模式
  • 干净的代码

核心逻辑

该项目的重点是学习SwiftUI,并利用其声明语法在几行代码中使用手势和动画构建一个复杂的控件。因为我学习新东西的最大动机是能够做出美丽和表演的东西。

首先从最小的组件开始

  • 搜索栏:本质上是一个文本字段,左侧有灰色背景颜色和搜索图标。当字段聚焦时,搜索按钮应显示,否则就消失了。
  • 表情符号网格:点击时将内容返回其父级的按钮网格。网格可以用VStack和HStack(需要二维数组)的组合构建,但SwiftUI 2提供了超级有帮助的网格,所以我改用LazyVGrid。这是一个玩具项目,反正我不在乎使用iOS 13的用户。
  • 包含表情符号网格的节标头列表。SwiftUI的酷之处在于,许多UI组件本机支持,无需急需的代码,以下是其中之一:用标题环绕aSection的List将为您提供带有粘性标头的表视图。与我不得不用UIKit实现同样的事情相比,这太方便了。
  • 筛选表情符号的搜索结果行。
  • 搜索结果列表。
  • 主要内容视图:包含上述所有组件。
  • 章节标题选择器,以便在章节之间导航。我希望这个漂浮在主要内容视图上方,这样它就不会包含在主要内容视图中。
  • 主面板:包含暗淡的背景、主要内容视图和部分标题选择器。

在各节之间导航

在ScrollViewReader和ScrollViewProxy的帮助下,只需一个简单的scrollTo(_ id:)函数,导航到列表的所需部分非常简单。问题是,我必须学会如何艰难地使用它,这牵涉到很多挫折感。

ScrollViewProxy的魔力在于它扫描儿童视图,以找到您发送的id的视图。就这么简单,但起初我尝试调用List的滚动函数,该函数会崩溃应用程序,因为myList不会立即包含我要查找的视图,而是将其嵌入到子ForEach中。将电话向下移到孩子身上是花了我几乎一整天时间的解决方案。

我还没有实现一个功能。预计滚动表情符号网格时,部分选择器会相应地更新其所选段。据我所知,这在天不可能,因为SwiftUIList没有提供读取当前偏移量的方法,但如果有一天它这样做了,我想我可以将偏移量与每个部分的预计算帧进行比较。这仍然很模糊,当我可以确定当前可见部分并更新currentCategory环境变量时,这将引起循环引用,因为选择器本身正在监听此变量的任何更改,以滚动到正确的部分。那么,有更好的解决方案吗?

用拖动手势移动主面板

使用拖动手势更新主面板偏移量并不是最难的部分。我保留了2个变量——一个用于计算偏移量,另一个用于拖动手势结束时的最后一个偏移量,用于计算第一个变量。然后,我有一些魔法代码来将面板磁化到顶部,或根据手势的结束位置关闭面板。

我注意到的一个问题是,如果我将主要内容视图的代码移动到主面板,拖动性能就会受到影响。我保留相同的代码并将其移动到单独的文件中,拖动变得尽可能流畅。这对我来说仍然是一个谜。

不过这里有一个挑战。Slack很好地利用了表情符号网格视图上的拖动手势,当面板处于半模式时,您无法滚动网格,只能拖动面板。我试图模仿这种行为,但没有本地方法来干预List的滚动行为。因此,我只是把它留在那里,等着看看SwiftUI何时提供此类功能,如果有的话。

@EnvironmentObject

最初,我使用了很多@State和@Binding在儿童和家长观点之间来回发送一些州。然后,我决定使用@EnvironmentObject清理混乱,以便所有孩子和父母都可以访问视图的相同状态。这让我思考,如果这是属性包装器本身的预期行为——如果它让所有听众都能看到这个状态,可以读写,这安全吗?就像我在视图中可能有一些与搜索关键字无关的代码,但更改变量,控件就会中断。如果SwiftUI的主要目的是以干净的方式维护状态,那么我对@EnvironmentObject的使用完全违反了规则。


实战代码

1. 主界面

```
import SwiftUI
import Shared

struct ContentView: View {
@State var selectedEmoji: Emoji?
@State var isShowingEmojiPanel = false

var body: some View {

    ZStack {
        VStack(spacing: 40) {
            Text("How do you feel today?")
                .font(.largeTitle)

            selectedEmoji.map {
                Text($0.string)
                    .font(Font.system(size: 40))
            }

            Button(action: {
top Created with Sketch.