跳到主要内容

9 篇博文 含有标签「ios」

查看所有标签

· 阅读需 2 分钟

问题

如下图:有两个 VStack 容器,高和宽分别为 100 和 150,容器的上方是文字标题,标题下方分别有一个红色矩形和一个蓝色矩形,请用红色矩形将标题下方的容器填满,将蓝色矩形的高宽设置为容器的二分之一,放在距容器左侧 10 个单位,距顶部 10 个单位的位置。

Docusaurus Plushie

思路

使用 GeometryReader 读取父容器的尺寸,依此来定位矩形的位置。

解答

struct ContentView: View {
var body: some View {
VStack{
VStack {
Text("矩形一")
.padding(.top)
Rectangle()
.fill(Color.red)
}
.frame(width:250,height: 200)
.border(Color.black)
VStack{
Text("矩形二")
.padding(.top)
//GeometryReader会读取父容器的尺寸,然后根据父容器的尺寸设置矩形的大小及位置
GeometryReader{geometry in
Rectangle()
.path(in: CGRect(
x: 10, y: 10, width: geometry.size.width/2, height: geometry.size.height/2
)
)
.fill(Color.blue)
}
}
.frame(width:250,height: 200)
.border(Color.black)
}
}
}

· 阅读需 2 分钟

问题

假设我们从服务器获取了一个 JSON 类型的数据如下:

{"name": "Jone","age": 17}

请使用 swift 将其转换为结构体类型的数据,其中年龄转换为整型数据,并打印出来。

思路

首先将此 JSON 数据定义为字符串类型的数据,将其转换成 Data 型。

然后定义一个结构体类型的数据模型,使其遵守 Codable 协议,只要遵守这些协议才能进行 json 与模型之间的编码与解码。

接下来我们就可以进行讲 json 解码并映射成模型,打印出年龄值。

解答

//将 json 数据转换为字符串类型的数据,方法是使用三个双引号包裹,属于多行字符串,引号中什么样,打印出来就是什么样,格式都不会变。
let res = """
{
"name": "Jone",
"age": 17
}
"""

//使用字符串.data()方法对字符串进行转换转换之后打印显示 32bytes
let data = res.data(using: .utf8)!

//Codable 协议其实就是遵守一个关于解码的协议和一个关于编码的协议,只要遵守这些协议才能进行 Json 与模型之间的编码与解码。

struct Student : Codable{
let name : String
let age : Int
}

//接下来我们就可以将 json 解码并映射成模型
let decoder = JSONDecoder()

//!的意思是强制解码,因为我们知道 data 中有值
let stu = try! decoder.decode(Student.self, from: data)

//可以看到,stu.age 已经成为整型。
print(stu.age)

· 阅读需 4 分钟

问题

使用 HStack 和 VStack 来实现计算器的界面。

Docusaurus Plushie

思路

任何复杂的界面都可以将其分解为单一的 HStack 和 VStack 来实现,计算器界面也一样,先用 HStack 将横排的按钮组合,然后再将 HStack 放入到 VStack 中。

Docusaurus Plushie

步骤一:按照界面元素从上到下的顺序开始写起,使用 HStack 和 VStack 组织好界面。

步骤二:通过创建自定义视图 View 和自定义 ViewModifier 将重复的控件(Text())和修饰符合并,简化代码。其中计算器数字部分“0”的样式,通过在 ViewModifier 中设置布尔值加三元运算符的方法来实现。

步骤三:由于自定义的 ViewModifier 有三种,分别对应计算器按钮的三种不同样式,还需要进一步合并,接下来使用双重数组加 ForEach 语句,并通过定义枚举数据类型将计算器按钮数据归类来完成合并。

解答

import SwiftUI

//计算器界面的主视图。
struct ContentView: View {
var body: some View {
VStack(spacing : 20){
Text("0")
.frame(maxWidth: .infinity, maxHeight: 200, alignment: .trailing)
.padding(.trailing, 50)
//系统自带的文字大小
.font(.system(size: 60))
.foregroundColor(Color("resule_fg"))
ForEach(0..<calcu_text.count){ i in
HStack{
ForEach(0..<calcu_text[i].count){ j in
CustomButton(calcu_text[i][j])
//这里是每个按钮的视图。
}
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color("calc_bg"))
//注意顺序
.edgesIgnoringSafeArea(.all)
}
}


//使用View协议,生成一个CustomButton复合视图,这个视图生成了每个按钮的内容和样式。
struct CustomButton : View {

let type : CalcButtonType

init(_ type : CalcButtonType) {
self.type = type
}

var body: some View{

Text(self.type.text)
.modifier(CalcModifier(type:self.type))

}
}


//使用View协议,生成一个CalcModifier复合修饰符来修饰每个按钮。
struct CalcModifier : ViewModifier {

let type : CalcButtonType
//让结构体的类型为枚举型

func body(content: Content) -> some View {
content
.frame(width: 80,height: 80)
.font(.title)
.background(self.type.bg_color)
//从固定的样式,变为动态样式
.foregroundColor(self.type.fg_color)
.cornerRadius(40.0)
}
}


//使用枚举类型数据,对复合修饰符和内容进行操作。
enum CalcButtonType{
//因为要给按钮设置三种样式,那么将之前数组类型的数据定义为枚举型,更方便使用。

case number(_ text:String)
//number是枚举的成员,关联值是一个字符串类型
case calc_opterator(_ text:String)
case calc_s_opterator(_ text:String)

var text : String {
//定义一个属性,这个属性直接返回text.

switch self {
case let.number(text) :
return text
case let.calc_opterator(text) :
return text
case let.calc_s_opterator(text) :
return text

}

}

var fg_color : Color{

switch self {
case .number(_) :
//如果匹配number,那么返回Color("darkgrey_operator_fg")
return Color("darkgrey_operator_fg")
case .calc_opterator(_) :
return Color("yellow_operator_fg")
case .calc_s_opterator(_) :
return Color("s_operator_fg")

}

}

var bg_color : Color{

switch self {
case .number(_) :
return Color("darkgrey_operator_bg")
case .calc_opterator(_) :
return Color("yellow_operator_bg")
case .calc_s_opterator(_) :
return Color("s_operator_bg")

}

}

}

prefix operator %
prefix operator -
prefix operator +

prefix func % (right : String) -> CalcButtonType{
return .calc_s_opterator(right)

}
prefix func - (right : String) -> CalcButtonType{
return .calc_opterator(right)

}
prefix func + (right : String) -> CalcButtonType{
return .number(right)

}
//将数据定义为枚举类型。
let calcu_text : [[CalcButtonType]] = [[%"AC",%"+/-",%"%",-"+"],[+"7",+"8",+"9",-"x"],[+"4",+"5",+"6",-"2"],[+"AC",+"+/-",+"%",-"2"],[+"0",+"+/-",-"="]]


struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

· 阅读需 3 分钟

问题

创建如下图所示的待办事项列表视图,并将标题数据传递到待办事项中。

Docusaurus Plushie

思路

每一项待办事项所包含的数据都是一样的,因此我们可以通过创建一个 class 类型的数据,其中包括字符串数据类型的标题、日期类型的时间和布尔值类型的选框,然后使用 SwiftUI 中的 ForEach 语句对数据进行遍历,从而完成数据的传递。

解答

import SwiftUI

//让类从NSObject, NSCoder继承功能,保证下次打开APP时,数据还在
class Todo : NSCoder{

//每一个事项的标题
var title : String = ""
//每一个事项的日期
var dueDate : Date = Date()
//每一个事项是否打勾
var checked : Bool = false
//i用来记录某一待办事项是列表中的第几个待办事项
var i : Int = 0

init(title: String, dueDate: Date, checked: Bool){
//self.title代表类里面的title等于初始化函数里的参数title,如果这样写就好理解很多:
//self.title = a
self.title = title
self.dueDate = dueDate
self.checked = false
}
}

//var emptyTodo : Todo = Todo(title: "", dueDate: Date())

var exampleTodos: [Todo] = [
Todo(title: "看电影", dueDate: Date(), checked: false),
Todo(title: "看话剧", dueDate: Date(), checked: false),
Todo(title: "完成swiftUI", dueDate: Date(), checked: false),
Todo(title: "完成Sketch四个界面", dueDate: Date(), checked: false),
Todo(title: "洗锅", dueDate: Date(), checked: false),
Todo(title: "画画", dueDate: Date(), checked: false)
]

NavigationView{
ScrollView{
ForEach(0..<exampleTodos.count){todoIndex in
VStack{
HStack{
Button(action: {

})
{
//左边的部分,包括蓝边、项目标题及时间
HStack{
//蓝边
VStack{
Rectangle()
.fill(Color.blue)
//frame就是元素的大小
.frame(width: 8,height: 74)
}

//项目标题及时间
VStack{

//项目标题
HStack{
Text(exampleTodos[todoIndex].title)
.font(.headline)
.foregroundColor(exampleTodos[todoIndex].checked ? .gray : .blue)
//把标题挤到左边
Spacer()
}
//时间
HStack{
Image(systemName: "clock")
.resizable()
.frame(width: 12,height: 12)
Text("2020/1/21")
.font(.subheadline)
//不设置frame,无限大,把时间挤到左边
Spacer()
}
.foregroundColor(Color.gray)
}
//padding是元素和frame之间的边距
.padding(.leading,5)

}

}
Button(action: {

})
{
VStack{
Image(systemName: exampleTodos[todoIndex].checked ? "checkmark.square" : "square")
.resizable()
.frame(width: 24, height: 24)
.foregroundColor(Color.gray)
.animation(.easeInOut)
}
.padding()
}

}
//冒号前面表示checked为真时的背景色,后面为否时的背景色
.background(Color(exampleTodos[todoIndex].checked ? "SingleItemBgChecked" : "SingleItemBg"))
.cornerRadius(10)
//元素内边距
.padding(10)
}
}
}
.navigationBarTitle("待办事项")
}

· 阅读需 2 分钟

问题

使用 SwiftUI 制作开发如下图的点餐列表。

Docusaurus Plushie

思路

使用 SwiftUI 中 TextField、Stepper、Picker 控件设计界面,结合自定义类数据将数据传入控件,完成开发。

解答(XCode11.4)

import SwiftUI

//ObservableObject使得Order成为被监听的对象

class Order : ObservableObject{
//在添加ObservableObject协议的基础上,要改变值的变量必须加@Published
let types : Array = ["香草","巧克力","芒果","草莓"]
var type : Int = 0
//@Published和@State的作用一样,当变量的值改变,视图中也会同步改变
@Published var number : Int = 0
@Published var text : String = "Name"
}

struct ContentView: View {
//在结构体内容声明一个变量的类型为Order类,这样就可以用到外部的自定义数据类型
@ObservedObject var order = Order()
var body: some View{
NavigationView{
Form{
TextField("name", text: $order.text)
//Stepper是一个函数,其中的参数value必须要绑定一个值,rang给定一个范围.,访问变量值的时候不用加$,但是绑定,也就是改变的时候要加$,无论加不加$,它们的值都是一个值,所以这里前面加,后面不加。
Stepper("数量:\(order.number)", value: $order.number, in: 0…10)
//selection表示已经选择的口味,
Picker("请选择口味", selection: $order.type){
// ForEach部分表示选择的范围,这其中的order.types只是将值传进去,而不会变化,因此不需要加$符号,从这里开始,是点击进入之后的内容
ForEach(0..<order.types.count){i in
Text(self.order.types[i])
}
}
}
.navigationBarTitle("CupcakeCorner")
}
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

· 阅读需 2 分钟

在SwiftUI中创建Tab Bar非常简单——以下是如何来做。

选项卡栏(在UIKit中称为UITabBars)非常适合为用户提供在不同视图之间快速切换的能力。以下是如何在你的SwiftUI应用程序中创建选项卡栏。

第一步:将包含子视图的整个视图封装到TabView中,这样会自动为我们创建一个具有完整功能的选项卡条。

第二步:将子视图放入到Tab View中。这将自动为TabBar中的每个子视图创建一个“槽”。

第三步:通过添加.tabItem修饰符为每个子视图创建一个Tab选项。你可以为每个选项卡选择任何图标和标签,SwiftUI会知道每个对象应该拥有哪个索引,并根据当前的选择更新状态!然后,您可以使用状态值,就像是我们对显示选定颜色的文本所做的操作一样。

struct ContentView: View {
var body: some View {
//1. 创建一个TabView
TabView {
//2. 将子视图放入TabView中
Text("Home View")
//3. 为每一个子视图创建一个tab bar
.tabItem {
Image(systemName: "house")
Text("Home")
}
Text("Settings View")
.tabItem {
Image(systemName: "gear")
Text("Settings")
}
}
}
}

· 阅读需 1 分钟

问题

创建一个如下图的待办事项视图。

Docusaurus Plushie

思路

使用 SwiftUI 中的 HStack 和 VStack 来实现此视图,需要对扩张性控件和收缩性控件熟练把握。

解答

HStack{
Button(action: {})
{
//左边的部分,包括蓝边、项目标题及时间
HStack{
//蓝边
VStack{
Rectangle()
.fill(Color.blue)
//frame就是元素的大小
.frame(width: 8,height: 74)
}
//项目标题及时间
VStack{
//项目标题
HStack{
Text("看话剧")
.font(.headline)
//把标题挤到左边
Spacer()
}
//时间
HStack{
Image(systemName: "clock")
.resizable()
.frame(width: 12,height: 12)
Text("1月18日")
.font(.subheadline)
//不设置frame,无限大,把时间挤到左边
Spacer()
}
.foregroundColor(Color.gray)
}
//padding是元素和frame之间的边距
.padding(.leading,5)
}
}
Button(action: {})
{
VStack{
Image(systemName: "square")
.resizable()
.frame(width: 24, height: 24)
.foregroundColor(Color.gray)
}
.padding()
}
}
.background(Color("SingleItemBg"))
.cornerRadius(10)
//元素内边距
.padding(20)

· 阅读需 2 分钟

Docusaurus Plushie

想知道如何在 SwiftUI 中正确地构建图像吗?这就是你要的!

第一步:将.resizable 修饰符应用于图像对象上,此修饰符将调整图像的大小和 frame 到合适的大小。

第二步::当你改变图像的大小时,通常需要保持原来的尺寸。为此,添加.aspectRatio 修饰符。你可以选择.fill 内容模式,让整个 frame 被图像填满,而.fit 内容模式确保整个图像在 frame 内。

第三步:现在您可以声明图像的 frame 修饰符。

第四步:增加.clipped 修饰符,以确保你的图像超过 frame 的任何部分被切断。

import SwiftUI
struct ContentView : View {
var body: some View {
Image("dog")
//Enable size editing for the Image
.resizable()
//Define which method to use to keep the original dimensions when resizing
.aspectRatio(contentMode: .fill)
//Declare the frame for your image
.frame(width: 380, height: 280)
//Cut out the exceeding parts of the image
.clipped()
}
}

· 阅读需 4 分钟

第1步:买一个Mac电脑并下载Xcode

Docusaurus Plushie

首先,为自己准备一个MacOS系统(万一你还没有)。您的设备至少应该能够运行MacOS Catalina。然后下载来自AppStore的Xcode,它是免费的。Xcode是开发iOS应用程序最关键的软件!

第2步:了解Xcode的基本知识

Docusaurus Plushie

下载Xcode之后,是时候了解它的基本结构和概念了。检查本教程,以了解开始使用Xcode所需的所有知识。我们将建造我们的第一个迷你“你好世界”,帮助您决定使用UIKit和SwiftUI(iOS开发的两种不同方法),并学习Xcode的基本界面。

第3步:学习SWIFT编程的基础知识

Docusaurus Plushie

在你了解了Xcode的基本知识之后,现在是学习Swift的时候了。Swift是最常用的编程语言,尤其对于初学者来说。我们已经为此创建了一个免费的电子书,您可以下载免费的!

第4步:通过教程构建Apps

Docusaurus Plushie

开始用教程构建基本的应用程序,教程非常多!我们创建了一系列的SwiftUI教程让你开始从头学起!我们建议你先从本教程开始。之后,您可以继续学习这些教程。

虽然我们免费教程几乎涵盖了所有学习iOS开发需要了解的东西,你也许还想看看我们的全面掌握SwiftUI手册。在这本书中,我们将手把手的教你关于使用SwiftUI开发应用程序所需要知道的一切。

第5步:加深对IOS SDK和框架的了解

Docusaurus Plushie

一旦你完成了一些教程,在你感兴趣的话题上加深你的知识,你想学更多。在IOS开发中,有太多的框架需要掌握。例如,如果你对增强现实应用感兴趣,可以学习谷歌“ARKit教程”。你有很多选择!

第6步:加深你的Swift知识

Docusaurus Plushie

你对iOS应用程序开发了解的越多,就需要更多的Swift技能和概念。如果你不了解一些更高级的Swift概念,可以在官方网站上查一查Swift语言文档(这是一个非常好的来源)或在某个地方搜索或者提问,例如通过StackOverflow或给我们写条消息!

第7步:开发自己的定制应用程序

要真正成为iOS开发人员,关键是要尽快开始开发自己的定制应用程序。这会极大地提高了你的学习曲线和编程技能。