16day 开始正式进入 ui 的部分
import SwiftUI
struct ContentView: View {
@State private var checkAmount = 0.0 //monitoring changes and refresh view
@State private var numberOfPeople = 2
@State private var tipPercetage = 20
//@FocusState
let tipPercetages = [10,15,20,25,0]
var totalAmount: Double{ //计算属性
let checkAmount = Double(checkAmount)
let tipPercentage = Double(tipPercetage)
return checkAmount * (1 + tipPercentage/100)
}
var perPayAmount:Double{
let peopleCount = Double(numberOfPeople + 2)
return totalAmount/peopleCount
}
var body: some View { //some就类似于 c++的 auto, 表示自动推断适合的view协议 //body 是必须的
NavigationStack{ //availbe to show new view with navigation link ,为了添加整个页面的标题,一般需要一个NavigationStack
Form{ //form 会自动将页面设成适合填写的布局
Section{ //分块,空白比较大
TextField("Amount",value:$checkAmount,format: .currency(code: Locale.current.currency?.identifier ?? "USD"))
.keyboardType(.decimalPad) //填入区 ,第一个一般是 label, $checkAmount表示binding,元变量会被修改更新
Picker("Number of People",selection: $numberOfPeople){ //显示多个选项,一般跟一个闭包来具体编写有几个选项,每个表示什么,一般用 text
ForEach(2..<100){ //here the number is only for render, not the value of numberOfPeople, so numberOfPeople should add 2 to fit the rendered number
Text("\($0) people")
}
}
.pickerStyle(.navigationLink) //show new view //这个修饰符会将选择迁移到新的画面
}
Section("Tips"){//section 可加入标题
Picker("Tip percentage", selection: $tipPercetage){
ForEach(tipPercetages,id:\.self){ //同个自身作为索引的 id
Text($0,format: .percent)
}
}
.pickerStyle(.segmented) //不是下拉菜单,是横向的选项式
Picker("Precious setting",selection: $tipPercetage){
ForEach(0..<101){
Text($0,format: .percent) //format 修改显示
}
}
.pickerStyle(.navigationLink)
}
Section("Total Amount"){
Text(totalAmount,format: .currency(code: Locale.current.currency?.identifier ?? "USD"))
.foregroundColor(tipPercetage == 0 ? .red:.black) //通过三元符来控制变动参数
}
Section("Amount Per Person"){
Text(perPayAmount,format: .currency(code: Locale.current.currency?.identifier ?? "USD"))
}
}
.navigationTitle("WeSplit") //标题
}
//.navigationTitle("WeSplit") have to attach inside the stack
}
}
#Preview { //在 xcode 上需要预览的画面的函数
ContentView()
}
import SwiftUI
struct ContentView: View {
@State private var unit = ["meter","kilometer","feet","yard","miles"]
@State private var selectedInputUnit = "meter"
@State private var selectedOutputUnit = "meter"
@State private var rawNumber: Double = 0.0
private var covertedToMeter: Double{
switch selectedInputUnit {
case "meter":
return rawNumber
case "kilometer":
return rawNumber * 1000
case "feet":
return rawNumber * 0.3048
case "yard":
return rawNumber * 0.9144
case "miles":
return rawNumber * 1609.34
default:
return rawNumber
}
}
private var covertedToOutputUnit: Double{
switch selectedOutputUnit {
case "meter":
return covertedToMeter
case "kilometer":
return covertedToMeter * 0.001
case "feet":
return covertedToMeter * 3.28084
case "yard":
return covertedToMeter * 1.09361
case "miles":
return covertedToMeter * 0.000621371
default:
return covertedToMeter
}
}
var body: some View {
NavigationStack{
Form{
Section("unit setting"){
HStack{ //横向排列悬殊
Text("Input unit ")
Picker("Input unit",selection: $selectedInputUnit){
ForEach(unit,id:\.self){
Text("\($0)")
}
}
.pickerStyle(.segmented)
}
HStack{
Text("Output unit")
Picker("Output unit",selection: $selectedOutputUnit){
ForEach(unit,id:\.self){
Text("\($0)")
}
}
.pickerStyle(.segmented)
}
}
Section("input number"){
HStack {
TextField("Enter value", value: $rawNumber, format: .number)//format定义一定是数字
.keyboardType(.decimalPad) //可定义弹出的键盘类型
Text(selectedInputUnit)
}
}
Section("Oput number"){
HStack{
Text("\(covertedToOutputUnit.formatted())") //format ted 自动转换为 string,一般用来表示文字
Spacer() //分割两个元素
Text(" \(selectedOutputUnit)")
}
}
}
.navigationTitle("Length Conversion")
}
}
}
#Preview {
ContentView()
}
import SwiftUI
struct clipshadowImageModifier: ViewModifier { //自定义 view 的修饰符,这里是将两个修饰符的功能合并
func body(content: Content)-> some View{ //content 表示本来的 view
content
.clipShape(.capsule)
.shadow(radius: 5)
}
}
extension View{ //扩展 View 以便方便使用该自定义修饰符
func clipandshadow() -> some View{
modifier(clipshadowImageModifier())
}
}
func flagImage(_ name:String) -> some View{ //自定义函数
Image(name)
.clipandshadow()
}
struct BigBlueTitleFontModifier: ViewModifier{
func body(content: Content) -> some View {
content
.font(.largeTitle.weight(.bold))
.foregroundColor(.blue)
}
}
extension View{
func bigbluetitle() -> some View{
modifier(BigBlueTitleFontModifier())
}
}
struct ContentView: View {
@State private var countries = ["Estonia","France","Germany","Ireland","Italy","Nigeria","Poland","Spain","UK","Ukraine","US"].shuffled() //random it 自动随机顺序
@State private var correctAnswer = Int.random(in: 0...2)
@State private var showingScore = false
@State private var scoreTitle = ""
@State private var score = 0
@State private var turn = 0
@State private var final = false
var body: some View {
ZStack{ //上下层结构,一般用来先头放置颜色 view 作为背景
// LinearGradient(colors: [.blue,.black], startPoint: .top, endPoint: .bottom)
// .ignoresSafeArea()
RadialGradient(stops:[.init(color: Color(red:0.1,green: 0.2,blue: 0.45), location: 0.3),.init(color: .red, location: 0.3)],center: .top, startRadius: 100, endRadius: 700) //没有定义的地方 swift 会自动设置为与最近的一个设置相同的参数,比如 0.。100 会被设置为 100 的颜色
.ignoresSafeArea() //包括安全区也覆盖颜色
VStack{
Spacer()
Text("Guess the flag")
.bigbluetitle() //设置字体类型
VStack(spacing:30){ //设定元素之间的间距
VStack{
Text("Tap the flag of")
.foregroundStyle(.secondary)
.font(.subheadline.weight(.heavy))//weight是字体的主席
Text(countries[correctAnswer])
.font(.largeTitle.weight(.semibold))
Text("\(turn) turn")
.foregroundStyle(.secondary)
.font(.subheadline.weight(.heavy))
}
ForEach(0..<3){ number in //ForEach(0...3) 报错是因为范围包含的类型必须是 Range,而不是 ClosedRange。用 0..<4 来表示从0到3。
Button{
flagTapped(number)
}label:{ //可自定义 lable,一般是文字,图像等
flagImage(countries[number])
}
}
}
.frame(maxWidth: .infinity) //设置大小,一般可设置 maxmin 长宽
.padding(.vertical,20) //设置周围余白 这里只设置垂直方向
.background(.regularMaterial) //背景为模糊材料效果
.clipShape(.rect(cornerRadius: 20)) //圆角类型
Spacer() //used to fix layout with ratio of spacer number
Spacer() //多个以控制各个空白的比例
Text("Score: \(score)")
.foregroundStyle(.white) //颜色
.font(.subheadline.weight(.heavy))
Spacer()
}
.padding()
}
.alert(scoreTitle,isPresented: $showingScore){ //设置警告框,isPresented需设定一个state 值,当值发生变化时会触发警告框
Button("Continue",action: askQuestion) //设置警告框的按钮
}message:{ //设置小字
Text("Your score is \(score)")
}
.alert(scoreTitle,isPresented: $final){
Button("Reset",action: resetScore)
}
message:{
Text("Your total score is \(score)")
}
}
func flagTapped(_ number: Int)
{
if (number == correctAnswer){
scoreTitle = "Correct"
score += 1
}
else{
scoreTitle = "Wrong, it is \(countries[number])"
}
turn += 1
if turn == 3{
scoreTitle = "Game Over!"
final = true
return
}
showingScore = true
}
func askQuestion(){
countries.shuffle()
correctAnswer = Int.random(in: 0...2)
}
func resetScore(){
countries.shuffle()
correctAnswer = Int.random(in: 0...2)
score = 0
turn = 0
}
}
#Preview {
ContentView()
}
下面包括了一个机械学习的模型,以预测输出
还有一些日期的用法
import SwiftUI
import CoreML
struct ml: View {
@State private var sleepAmount = 9.0
@State private var wakeUP = defaultWakeTime
@State private var coffeeAmount = 0
@State private var alertTitle = ""
@State private var alertMessage = ""
@State private var showingAlert = false
//因为defaultWakeTime被 state 使用,所以要设置为 static 保证事先赋值好
// var defaultWakeTime : Date{ //swift cant order the two var here, so failed compile, instead use static to priority the order here
// var components = DateComponents()
// components.hour = 7
// components.minute = 0
// return Calendar.current.date(from:components) ?? .now
// }
static var defaultWakeTime : Date{
var components = DateComponents() //时间组件
components.hour = 7 //定义时间
components.minute = 0
return Calendar.current.date(from:components) ?? .now //通过Calendar.current.date(from: 来 cast 到 Date 类型,才能被 view 使用
}
var body: some View {
NavigationView{
Form{
//Vstack{ Form list them automatically and looks good
VStack(alignment:.leading,spacing:0){ //section divied here by vstack //aligment 对齐方式,这里是对齐左边
//Section{ //it takes more space thran vstack section
Text("When do you want to wake up ?")
.font(.headline)
DatePicker("Please enter a time ", selection: $wakeUP,displayedComponents: .hourAndMinute)
.labelsHidden() //关闭标签显示
}
VStack(alignment:.leading,spacing:0){
Text("Desired amount of sleep")
.font(.headline)
Stepper("\(sleepAmount.formatted()) hours", value:$sleepAmount, in:4...12, step: 0.25) //选步进选择起
}
VStack(alignment:.leading,spacing:0){
Text("Daliy coffee intake")
.font(.headline)
Stepper(coffeeAmount == 1 ? "\(coffeeAmount) cup" : "\(coffeeAmount) cups",value: $coffeeAmount, in:0...20) //sovle the cup and cups
Stepper("^[\(coffeeAmount) cup](inflect: true)",value: $coffeeAmount, in:0...20) //sovle the cup and cups by markdown
Picker("Input cup", selection: $coffeeAmount){
ForEach(0..<11){
Text($0 == 1 ? "\($0) cup" : "\($0) cups")
}
}
}
}
.navigationTitle("BetterRest")
.toolbar{ //顶部右边的位置
Button("Caluculate",action:calculateBedtime)
Button("Test"){} //clousure buttom returns nothing //按钮可以通过空包放置没有作用的空按钮
//Button("Test2") //not allowed
}
.alert(alertTitle,isPresented: $showingAlert){
Button("OK"){}//按钮可以通过空包放置没有作用的空按钮,但这里可以直接退出警告框
}message:{
Text(alertMessage)
}
}
}
func calculateBedtime(){
do {
//一般来说用 model 都加上 try 防止错误运行出现不可预料结果
let config = MLModelConfiguration() //设置 MLMODEL
let model = try SleepCalculator(configuration: config) // model instance ,通过 try 来解包,异常就终止 如果用 try?来解包可以忽略错误并返回 nil(但是在 do 里面不能用 try?)
//current 是表示使用当前系统的日历的规格,dateComponents来设置具体取些什么,具体的值从 from 取,Date 烈性
let components = Calendar.current.dateComponents( [.hour,.minute], from: wakeUP)
let hour = (components.hour ?? 0) * 60 * 60 // convert to second //需要解包
let minute = (components.minute ?? 0 ) * 60 // convert to second //需要解包
//通过prediction来输入输出模型
let prediction = try model.prediction(wake: Double(hour+minute), estimatedSleep: sleepAmount, coffee: Double(coffeeAmount))
//日期相减得到一个时间间隔,但依旧是 Date 类型
let sleepTime = wakeUP - prediction.actualSleep
alertMessage = "your ideal betime is "
//要打印 Date 类型,需要 formatted 转换为时间,可以设置 omiited 表示不输出,。shorten 为短格式
alertMessage = sleepTime.formatted(date:.omitted,time: .shortened) //convert to string
}
catch
{
alertTitle = "Error"
alertMessage = "Problem in calcualtiing"
}
showingAlert = true
}
}
#Preview {
ml()
}
import SwiftUI
struct ContentView: View {
@State private var sleepAmount = 9.0
@State private var wakeUP = Date.now //当前日期
var body: some View {
Stepper("\(sleepAmount.formatted()) hours", value:$sleepAmount, in:4...12, step: 0.25)//formatted 在这里去掉多余的小数位
DatePicker("Please enter a date ", selection: $wakeUP)//选择日期的 picker , 初始值为 selection
DatePicker("Please enter a date ", selection: $wakeUP,displayedComponents: .hourAndMinute) //displayedComponents选择那些时间
.labelsHidden()
DatePicker("Please enter a date ", selection: $wakeUP)
DatePicker("Please enter a date ", selection: $wakeUP, in:Date.now...) //单向闭包是可以的
Text(Date.now, format: .dateTime.hour().minute())//format 控制时间格式,后面加.来连续设置
Text(Date.now, format: .dateTime.day().month().year())
Text(Date.now.formatted(date: .long, time: .shortened))//另一种表示格式,用 formatted 转换为 string
}
func exampleDates(){
let now = Date.now
let tomorrow = Date.now.addingTimeInterval(86400) //增加时间,秒单位
let range = now...tomorrow //时间的区间
var components = DateComponents() //时间组件
components.hour = 8 //设定时间
components.minute = 0
let date = Calendar.current.date(from: components) //将时间组件转换为 Date 类型
let date2 = Calendar.current.date(from: components) ?? .now
let components2 = Calendar.current.dateComponents([.hour, .minute], from: .now)
let hour = components2.hour ?? 0 //取出某一个单位
let minute = components2.minute ?? 0
}
}
#Preview {
ContentView()
}