2021-04-16

SwiftUI 简明教程之文本与图片

本文为 Eul 样章,如果您喜欢,请移步 AppStore/Eul 查看更多内容。

Eul 是一款 SwiftUI & Combine 教程类 App(iOS、macOS),以文章(文字、图片、代码)配合真机示例(Xcode 12+、iOS 14+,macOS 11+)的形式呈现给读者。笔者意在尽可能使用简洁明了的语言阐述 SwiftUI & Combine 相关的知识,使读者能快速掌握并在 iOS 开发中实践。

Text

本地化字符串

SwiftUI 中涉及到字符串的地方,基本都支持普通的字符串和本地化字符串。Text 的初始化方法也不例外:

/// 普通字符串init<S>(_ content: S) where S : StringProtocol/// 本地化字符串init(_ key: LocalizedStringKey, tableName: String? = nil, bundle: Bundle? = nil, comment: StaticString? = nil)

我们先创建多语言文件,分别写入中英文的 Stay Hungry, Stay Foolish! 文本,通过枚举去获取对应的 LocalizedStringKey,然后就可以使用 Text(LocalizeKey.Hungry) 方便地展示本地化字符串了。

enum LocalizeKey { static let kHungry: LocalizedStringKey = "Hungry"}struct LocalizableView: View { var body: some View { Text(LocalizeKey.kHungry) }}// "Hungry" = "Stay Hungry, Stay Foolish!";// "Hungry" = "求知若饥,虚心若愚!";

富文本

Text 实现了操作符重载,我们可以直接用 + 来拼接不同样式的文字。

struct RichTextView: View { private let text: Text = Text("Stay ").foregroundColor(.blue).font(.title).italic() + Text("Hungry, ").font(.headline) + Text("Stay ").foregroundColor(.red).font(.title) + Text("Foolish!").font(.headline).underline() var body: some View { text }}

另外,Text 本身遵循 Equatable 协议,我们还可以直接使用 ==!= 来对两个 Text 进行判等。

日期

Text 甚至可以直接展示日期,现在创建一个倒计时控件只需要一行代码就可以实现!

Text 的初始化方法有如下几种:

/** 以下日期均指当地日期 *//// 使用指定样式展示日期public init(_ date: Date, style: Text.DateStyle)/// 展示日期范围public init(_ dates: ClosedRange<Date>)/// 展示日期间隔public init(_ interval: DateInterval)

DateStyle 有如下枚举值:

public struct DateStyle { /// 时间,比如:11:23PM public static let time: Text.DateStyle  /// 日期,比如:June 3, 2019 public static let date: Text.DateStyle  /// 相对现在的时间,比如:2 hours, 23 minutes public static let relative: Text.DateStyle 	 /// 与现在的时间差,比如:-3 months,+2 hours public static let offset: Text.DateStyle  /// 倒计时,比如:36:59:01 public static let timer: Text.DateStyle}

下面我们通过代码展示其用法:

struct DateView: View { private var future: Date { now.addingTimeInterval(3600) } private var now: Date { Date() } var body: some View { VStack(alignment: .leading, spacing: 10) {  row(style: ".date") { Text(now, style: .date) }  row(style: ".offset") { Text(future, style: .offset) }  row(style: ".relative") { Text(future, style: .relative) }  row(style: ".time") { Text(future, style: .time) }  row(style: ".timer") { Text(future, style: .timer) }  row(style: "Range") { Text(now...future) }  row(style: "Interval") { Text(DateInterval(start: now, end: future)) } } } func row<Content: View>(style: String, @ViewBuilder content: () -> Content) -> some View { VStack {  HStack {  content()  Spacer()  Text(style).foregroundColor(.secondary)  }   Divider () } }}

先简述一下 @ViewBuilder 的作用:它可以用来修饰闭包参数,并从中构建视图。

.offset.relative.timer 展示的时间都是根据秒数变化的,其它样式的日期则是静态的。

Label

构建方法

Label 是一个相当强大的控件,可以快速生成图片和文字的组合,默认布局是左图右文,也支持自定义配置。

它有如下初始化方法:

init<S>(S, image: String)init<S>(S, systemImage: String)init(LocalizedStringKey, image: String)init(LocalizedStringKey, systemImage: String)// Title: View, icon: Viewinit(title: () -> Title, icon: () -> Icon)

我们试着用以上方法构建不同的视图,代码和界面如下:

Label("Swift", systemImage: "swift") .foregroundColor(.orange)Label( title: { Text("Apple") },icon: { Image(systemName: "applelogo") }).foregroundColor(.blue)Label( title: { Image(systemName: "gift.fill")  .renderingMode(.original) },icon: { Text("Gift") }).foregroundColor(.red).labelStyle(TitleOnlyLabelStyle())

LabelStyle 有如下三种样式:

  • DefaultLabelStyle // Title + Icon
  • IconOnlyLabelStyle // 只显示 Icon
  • TitleOnlyLabelStyle // 只显示 Title

自定义样式

上面的构建方法中,其实还有一种是未曾提及的:

init(LabelStyleConfiguration)

LabelStyleConfiguration 是一个结构体类型,包含 IconTitle

我们可以通过这个初始化方法,给系统提供的样式添加自定义的样式。

比如我们需要给 Label 加上阴影,可以先创建一个遵循 LabelStyle 协议的 ShadowLabelStyle,然后使用该样式。下面代码中的 Configuration 实际上就是 LabelStyleConfiguration ,只不过系统通过 typealias Configuration = LabelStyleConfiguration 改头换面了而已。

Label("Apple", systemImage: "applelogo")  .labelStyle(ShadowLabelStyle())struct ShadowLabelStyle: LabelStyle { func makeBody(configuration: Configuration) -> some View { Label(configuration)  .shadow(color: Color.black.opacity(0.5), radius: 5, x: 0, y: 5) }}

上面的样式有一定的局限性,如果我们需要一个垂直布局或是左右对齐的样式呢?实现的原理是一样的,代码如下:

struct VerticalLabelStyle: LabelStyle { func makeBody(configuration: Configuration) -> some View { VStack(alignment: .center, spacing: 10) {  configuration.icon  configuration.title } }}struct LeftRightLabelStyle: LabelStyle { func makeBody(configuration: Configuration) -> some View { HStack(alignment: .center, spacing: 10) {  configuration.icon  Spacer()  configuration.title } }}

TextField

TextField 有如下的三种构建方式:

  1. 普通的初始化方法
  2. 在方法 1 的基础上新增了监听功能,可以监听编辑状态、Return 键的按下动作
  3. 在方法 2 的基础上新增了格式转换功能

前两种方法比较简单,这里说一下方法 3 的细节。如下样例是将输入的文字转换成数字,当我们正在输入的时候,格式转换功能是不生效的,只有当编辑结束的时候,才会去执行转换,如果转换成功,会更新绑定的值(s3),如果转换失败,不会更新 s3。

@State private var s1 = ""@State private var s2 = ""@State private var s3 = 0@State private var pwd = ""GroupBox(label: Text(s1)) { /// 1 TextField("TextField", text: $s1)}GroupBox(label: Text(s2)) { /// 2 TextField("Observe TextField", text: $s2) { (isEditing) in print(isEditing) } onCommit: { print("Return") } .textFieldStyle(RoundedBorderTextFieldStyle())}GroupBox(label: Text(String(s3))) { /// 3 TextField("Formatter TextField", value: $s3, formatter: NumberFormatter()) { (isEditing) in print(isEditing) } onCommit: { print("Return") } .textFieldStyle(RoundedBorderTextFieldStyle()) .keyboardType(.numbersAndPunctuation)}GroupBox(label: Text("密码输入: \(pwd)")) { /// 密码输入 SecureField("Password", text: $pwd)}

TextEditor

TextEditor 的使用比较简单,如下代码我们就可以轻松创建一个文本输入框:

@State private var text = "Stay Hungry, Stay Foolish!"TextEditor(text: $text) .frame(height: 150) .lineSpacing(10.0)     // 行距 .multilineTextAlignment(.center) // 对齐方式 .overlay( RoundedRectangle(cornerRadius: 5)  .stroke(Color.blue, lineWidth: 1) )

系统并没有提供 placeholder 这样的特性,不过我们可以轻松实现这个功能。

// 添加 placeholderZStack(alignment: .topLeading) { TextEditor(text: $text2) .frame(height: 150) .border(Color.blue) if text2.isEmpty { Text("Type something")  .foregroundColor(Color(UIColor.placeholderText))  .padding(8) }}

Image

Image 用来展示图片,它可以加载资源包中的图片文件和系统内置的图标(SF Symbols)。

以下是几点提示:

  • 图片默认具有伸展特性,.resizable() 可使图片不超出屏幕或指定区域
  • 如果要展示 SF Symbols 内置图标自带的颜色,可以用 .renderingMode(.original). 来渲染。
  • Text 可以直接插入图片,支持字符串插值和拼接两种方式

本文为 Eul 样章,如果您喜欢,请移步 AppStore/Eul 查看更多内容。









原文转载:http://www.shaoqun.com/a/691746.html

跨境电商:https://www.ikjzd.com/

cicpa考试:https://www.ikjzd.com/w/1375

亚马逊t恤:https://www.ikjzd.com/w/1932


本文为Eul样章,如果您喜欢,请移步AppStore/Eul查看更多内容。Eul是一款SwiftUI&Combine教程类App(iOS、macOS),以文章(文字、图片、代码)配合真机示例(Xcode12+、iOS14+,macOS11+)的形式呈现给读者。笔者意在尽可能使用简洁明了的语言阐述SwiftUI&Combine相关的知识,使读者能快速掌握并在iOS开发中实践。Text
淘粉吧首页:https://www.ikjzd.com/w/1725.html
c88是什么:https://www.ikjzd.com/w/1017
斑马物联网:https://www.ikjzd.com/w/1316
亚马逊这些敏感词要小心了!:https://www.ikjzd.com/home/132125
妻子口述:我们喜欢同床激情分居睡:http://www.30bags.com/a/253786.html
广告系卖家胜出!亚马逊搜索规则大变:https://www.ikjzd.com/home/114265

No comments:

Post a Comment