SwiftUI知识点(二)

Animation

import SwiftUI

struct AnimationBootcamp: View {
    
    @State var isAnimation: Bool = false
    
    var body: some View {
        VStack{
            Button("Button"){
                withAnimation(
                    Animation
                        .default
                        //重复
                        //autoreverses: true:A-B-A-B
                        //false: A-B,A-B
                        .repeatForever(autoreverses: true)){
                    isAnimation.toggle()
                }
                
            }
            
            Spacer()
            
            Rectangle()
                .fill(isAnimation ? .green : .red)
                .cornerRadius(isAnimation ? 10 : 50)
                .frame(
                    width: isAnimation ? 300 : 100,
                    height: isAnimation ? 300 : 100)
                //移动距离
                .offset(y: isAnimation ? 200 : 0)
                //转动角度
                .rotationEffect(Angle(degrees: isAnimation ? 360 : 0))
            
            
            Spacer()
        }
        
        
        
    }
}

#Preview {
    AnimationBootcamp()
}

在这里插入图片描述

Transition

import SwiftUI

struct TransitionBootcamp: View {
    
    @State var isShowView: Bool = true
    
    var body: some View {
        ZStack(alignment: .bottom) {
            VStack {
                Button("Button") {
                    //等价于:isShowView = !isShowView
                    isShowView.toggle()
                }
                Spacer()
            }
            
            if isShowView {
                RoundedRectangle(cornerRadius: 30)
                    .frame(height: UIScreen.main.bounds.height * 0.5)
                    //从什么地方进,从什么地方出
                    .transition(.asymmetric(
                        insertion: .move(edge: .leading),
                        removal: .move(edge: .bottom)))
                    ///动画:慢进慢出
                    .animation(.easeInOut)
            }
        }
        
        ///忽略底部的间隙
        .edgesIgnoringSafeArea(.bottom)
    }
}

#Preview {
    TransitionBootcamp()
}

在这里插入图片描述

Sheets

import SwiftUI

struct SheetsBootcamp: View {
    
    @State var isPresented: Bool = false
    
    var body: some View {
        
        ZStack {
            ///绿色背景
            Color.green
                .edgesIgnoringSafeArea(.all)//全部填充满
            
            Button(action: {
                isPresented.toggle()
            }, label: {
                Text("pop另外一个view")
                    .foregroundColor(.green)
                    .font(.headline)
                    .padding(20)
                    .background(Color.white.cornerRadius(5.0))
            })
            
            ///pop出下一个view
            .sheet(isPresented: $isPresented, content: {
                NextSheetsBootcamp()
            })
            
            ///全屏出现
            .fullScreenCover(isPresented: $isPresented, content: {
                NextSheetsBootcamp()
            })
            
            ///方法二:Transition
            ZStack{
                if isPresented {
                    NextSheetsBootcamp(isPresented: $isPresented)
                        .padding(.top, 100)
                        .transition(.move(edge: .bottom))
                        .animation(.spring)
                }
            }
            //设置了视图的堆叠顺序(不加这个,也有动画效果)
            .zIndex(2)
            
            ///方法三:Animation
            NextSheetsBootcamp(isPresented: $isPresented)
                .padding(.top, 100)
                .offset(y: isPresented ? 0 : UIScreen.main.bounds.height)
                .animation(.spring)
        }
    }
}

///出现的新View
struct NextSheetsBootcamp: View {
    ///固定写法
    @Environment(\.presentationMode) var presentationMode
    
    var body: some View {
        ///关闭按钮在左上角
        ZStack(alignment: .topLeading) {
            Color.red
                .edgesIgnoringSafeArea(.all)
            
            Button(action: {
                ///点击按钮,关闭popView
                presentationMode.wrappedValue.dismiss()
                
                ///方法二、三的关闭
                isPresented.toggle()
            }, label: {
                Image(systemName: "xmark")
                    .foregroundColor(.white)
                    .font(.largeTitle)
                    .padding(20)
            })
        }
    }
}


#Preview {
    SheetsBootcamp()
}

在这里插入图片描述

NavigationView

import SwiftUI

struct NavigationViewBootcamp: View {
    var body: some View {
        NavigationView{
            ScrollView {
                
                ///需要点击跳转的,加上NavigationLink
                NavigationLink("Hello") {
                    //下一个View的内容
                    SecondNavigationViewBootcamp()
                }
                
                Text("Hello,navigationView1")
                Text("Hello,navigationView2")
                Text("Hello,navigationView3")
                Text("Hello,navigationView4")
            }
            .navigationTitle("Title")
            .navigationBarTitleDisplayMode(.large)
//            .toolbar(.hidden)
            
            //leading:左边items
            //trailing:右边items
            .navigationBarItems(leading:
                                    HStack{
                                    Image(systemName: "person.fill")
                                    Image(systemName: "flame.fill")
                                },
                                trailing: NavigationLink(destination: {
                                    SecondNavigationViewBootcamp()
                                }, label: {
                                    Image(systemName: "gear")
                                }))
            
        }
    }
}

struct SecondNavigationViewBootcamp: View {
    var body: some View {
        ZStack{
            Color.green.ignoresSafeArea(.all)
                .navigationTitle("navigationTitle2")
            
            NavigationLink("Click here", destination: Text("第三个Nav内容"))
        }
    }
}

#Preview {
    NavigationViewBootcamp()
}

在这里插入图片描述

List

import SwiftUI

struct ListBootcamp: View {
    @State var fruits: [String] = [
        "apple", "banana", "orange", "peach"
    ]
    
    var body: some View {
        NavigationView {
            List{
                Section {
                    ///for循环
                    ///id: \.self,以自己为index
                    ForEach(0..<fruits.count, id: \.self){ index in
                        Text(fruits[index])
                            .font(.caption)//设置cell的样式
                            .foregroundStyle(.white)
                            .padding(.vertical)
                    }
                    ///左滑删除
                    .onDelete(perform: { indexSet in
                        fruits.remove(atOffsets: indexSet)
                    })
                    ///section的背景颜色
                    .listRowBackground(Color.blue)
                } header: {
                    HStack{
                        Text("Fruits1")
                        Image(systemName: "flame.fill")
                    }
                    //设置section的样式
                    .font(.largeTitle)
                    .foregroundColor(.orange)
                }
                
                Text("----------")
                
                Section {
                    ForEach(fruits, id: \.self){ fruit in
                        Text(fruit)
                    }
                    
                    ///没有实现,不能正常保存
                    .onMove(perform: { indices, newOffset in
                        fruits.move(fromOffsets: indices, toOffset: newOffset)
                    })
                } header: {
                    Text("Fruits2")
                }
                
            }
            ///样式,类似group\plain
            //.listStyle(.insetGrouped)
            .accentColor(.purple)//没起作用
            .navigationTitle("Navigation Title")
            .navigationBarItems(
                leading: EditButton(),
                trailing: Button("Add", action: {
                fruits.append("watermelon")
            }))
        }
        .accentColor(.red)
    }
}

#Preview {
    ListBootcamp()
}

在这里插入图片描述

Alert

import SwiftUI

struct AlertBootcamp: View {
    @State var showAlert: Bool = false
    @State var backgroundColor: Color = Color.yellow
    var body: some View {
        ZStack {
            backgroundColor.edgesIgnoringSafeArea(.all)
            
            Button("Click here"){
                showAlert.toggle()
            }
            
            .alert(isPresented: $showAlert, content: {
    //            Alert(title: Text("There was an error!"))
                
                getAlert()
            })
        }
    }
    
    func getAlert() -> Alert {
        return Alert(title: Text("There was an error!"),
                     message: Text("This is a message"),
                     primaryButton: .destructive(Text("red color"), action: {
                       backgroundColor = .red
                     }),
                     secondaryButton: .default(Text("cancel")))
    }
    
}

#Preview {
    AlertBootcamp()
}

在这里插入图片描述

Actionsheet

import SwiftUI

struct ActionsheetBootcamp: View {
    @State var isPresented: Bool = false
    @State var actionSheetOption: ActionSheetOptions = .isOtherPost
    
    enum ActionSheetOptions {
        case isMyPost
        case isOtherPost
    }
    
    var body: some View {
        
        VStack {
            HStack {
                Circle()
                    .frame(width: 30, height: 30)
                Text("userNane")
                Spacer()
                Button(action: {
                    actionSheetOption = .isMyPost
                    isPresented.toggle()
                }, label: {
                    Image(systemName: "ellipsis")
                })
            }
            Rectangle()
                .frame(width: 370, height: 300)
                .cornerRadius(10)
        }
        .padding(10)
        
        .actionSheet(isPresented: $isPresented, content: {
            
            let button1: ActionSheet.Button = .cancel(Text("取消"))
            let button2: ActionSheet.Button = .destructive(Text("删除"))
            let button3: ActionSheet.Button = .default(Text("默认"))
            
            
            var otherButtonsArray = [button1]
            var myButtonsArray = [button1, button2, button3]
            
            return ActionSheet(title: Text("标题"),
                        message: Text("消息"),
                               buttons: actionSheetOption == .isMyPost ? myButtonsArray : otherButtonsArray
            )
        })
    }
}

#Preview {
    ActionsheetBootcamp()
}

在这里插入图片描述

ContextMenu

import SwiftUI

struct ContextMenuBootcamp: View {
    
    @State var backgroundColor: Color = Color.blue
    
    var body: some View {
        VStack(alignment: .leading){
            Image(systemName: "house")
                .font(.largeTitle)
            
            Text("SwiftUI Thinking")
                .font(.title2)
            
            Text("How to use Context Menu")
                .font(.title3)
        }
        .foregroundStyle(.white)
        .padding(30)
        .background(backgroundColor)
        .cornerRadius(30)
        ///长按,而不是点按
        .contextMenu(menuItems: {
            Button(action: {
                backgroundColor = Color.red
            }, label: {
                Label("标题1", systemImage: "flame.fill")
            })
            Button(action: {
                backgroundColor = Color.green
            }, label: {
                Text("标题2")
            })
            Button(action: {
                backgroundColor = Color.yellow
            }, label: {
                Text("标题2")
                Image(systemName: "heart.fill")
            })
        })
    }
}

#Preview {
    ContextMenuBootcamp()
}

在这里插入图片描述

TextField

import SwiftUI

struct TextfieldBootcamp: View {
    @State var textFieldString: String = ""
    @State var stringArray: [String] = []
    
    var body: some View {
        NavigationView{
            VStack(alignment: .leading){
                TextField("请输入文字", text: $textFieldString)
                    .padding()
                    .background(.gray.opacity(0.5))
                    .foregroundStyle(.red)
                    .cornerRadius(5.0)
                    .font(.headline)
                
                Button("Save".uppercased()) {
                    if isRight() {
                        saveText()
                    }
                }
                .padding()
                .frame(maxWidth: .infinity)
                .background(isRight() ? .blue : .gray)
                .foregroundStyle(.white)
                .cornerRadius(5.0)
                .disabled(!isRight())
                
                ///由于是绑定了stringArray,
                ///stringArray.append(textFieldString)的时候,stringArray值发生改变,此时,调用这个方法
                ForEach(stringArray, id:\.self) { item in
                    Text(item)
                }
                
                Spacer()
            }
            .padding()
            .navigationTitle("标题")
        }
    }
    
    func saveText(){
        stringArray.append(textFieldString)
        textFieldString = ""
    }
    
    func isRight() -> Bool{
        if textFieldString.count >= 3 {
            return true
        }
        return false
    }
}

#Preview {
    TextfieldBootcamp()
}

在这里插入图片描述

这块有点不好理解的地方
比如我先输入123,点击save,则有一个Text(123)
再输入456,点击save,此时,for循环变量,拿出数组的值,而数组有两个元素[“123”, “456”]
应该输出两个Text,即Text(123),Text(456),加上之前的Text(123),此时有:Text(123),Text(123),Text(456)
而实际上,只有Text(123),Text(456)
这是因为:swiftUI的视图是声明式的,在状态改变的时候,重新渲染视图,渲染的内容只有新的部分,即Text(456)

当你在一个数组中添加新的元素时,SwiftUI 会进行视图差异计算,只更新那些真正改变的部分:

  • 已存在的元素,不会被删除;视图保持不变,以实现高效复用。
  • 新增的元素,会被 SwiftUI 生成新的视图,并插入到视图树中。

TextEditor


import SwiftUI

struct TextEditorBootcamp: View {
    @State var textEditorString: String = "占位字"
    @State var saveTextString: String = ""
    var body: some View {
        NavigationView{
            VStack{
                TextEditor(text: $textEditorString)
                    ///使用这个设置文本框的背景颜色比较好
                    .overlay(
                        Color.gray.opacity(0.3).cornerRadius(10)
                    )
                    .cornerRadius(10)
                    .padding(10)
                    .font(.largeTitle)
                    .frame(height: 300)
                    .foregroundStyle(.red)
                    //这个背景颜色,会将字体一起添加上透明度
//                    .colorMultiply(.gray.opacity(0.3))
                    //这个颜色,区域不是文字的背景色
//                    .background(.gray.opacity(0.3))
                    
                Button(action: {
                    saveTextString = textEditorString
                }, label: {
                    Text("保存")
                        //先设置frame才生效
                        .frame(maxWidth: .infinity, minHeight: 50)
                        .background(.blue)
                        .foregroundStyle(.white)
                        .cornerRadius(10)
                        .padding(10)
                        //这里设置,按钮大小是对的,但是颜色值等不生效,因为是根据顺序渲染的
//                        .frame(maxWidth: .infinity)
                })
                
                Text(saveTextString)
                
                Spacer()
            }
            .navigationTitle("导航标题")
        }
    }
}

#Preview {
    TextEditorBootcamp()
}

在这里插入图片描述

Toggle

import SwiftUI

struct ToggleBootcamp: View {
    
    @State var toggleState: Bool = false
    
    var body: some View {
        
        VStack {
            
            Text("按钮状态:\(toggleState)")
                .font(.largeTitle)
            
            Toggle(isOn: $toggleState, label: {
                Text("改变按钮状态:")
            })
            .toggleStyle(SwitchToggleStyle(tint: .purple))
            .padding(.horizontal, 100)
            
            Spacer()
        }
    }
}

#Preview {
    ToggleBootcamp()
}

在这里插入图片描述

Picker

import SwiftUI

struct PickerBootcamp: View {
    
    @State var selection1: String = ""
    @State var selection2: String = ""
    @State var selection3: String = ""
    
    let filterOptions: [String] = [
        "Most Recent", "Most Popular", "Most Linked"
    ]
    
    //只对segment样式的picker起作用
    init(){
        UISegmentedControl.appearance().selectedSegmentTintColor = UIColor.red
        
        let attrubutes: [NSAttributedString.Key : Any] = [
            .foregroundColor: UIColor.white
        ]
        UISegmentedControl.appearance().setTitleTextAttributes(attrubutes, for: .selected)
    }
    
    var body: some View {
        NavigationView{
            VStack{
                Text("pick1选中的是:" + selection1)
                Picker(selection: $selection1) {
                    ForEach(18...100, id: \.self) { item in
                        //tag不能少,因为text只是显示,tag才是给上面selection使用的
                        Text("\(item)").tag("\(item)")
                    }
                } label: {
                    Text("Picker")
                }
                //样式
                .pickerStyle(.wheel)
                
                //分割线
                Divider()
                
                Text("pick2选中的是:" + selection2)
                Picker(selection: $selection2) {
                    ForEach(filterOptions, id: \.self) { item in
                        HStack{
                            Text("\(item)")
                            Image(systemName: "heart")
                        }
                        .tag(item)
                    }
                } label: {
                    Text("Picker2")
                        .font(.headline)
                        .foregroundStyle(.white)
                        .padding()
                        .backgroundStyle(Color.blue)
                }
                .pickerStyle(.menu)
                
                Spacer()
                //分割线
                Divider()
                Spacer()
                
                Text("pick3选中的是:" + selection3)
                Picker(selection: $selection3) {
                    ForEach(filterOptions, id: \.self) { item in
                        //tag不能少,因为text只是显示,tag才是给上面selection使用的
                        Text("\(item)").tag(item)
                    }
                } label: {
                    Text("Picker3")
                }
                .pickerStyle(.segmented)
                
                
                Spacer()

            }
            .navigationTitle("导航栏")
        }
        
        
    }
}

#Preview {
    PickerBootcamp()
}

在这里插入图片描述

ColorPicker

import SwiftUI

struct ColorPickerBootcamp: View {
    @State var backgroundColor: Color = .green
    
    var body: some View {
        ZStack{
            backgroundColor.ignoresSafeArea(.all)
            
            ColorPicker("颜色选择器", selection: $backgroundColor, supportsOpacity: true)
                .padding()
                .background(.black)
                .foregroundColor(.white)
                .cornerRadius(10)
                .padding(30)
        }
    }
}

#Preview {
    ColorPickerBootcamp()
}

在这里插入图片描述

DatePicker


import SwiftUI

struct DatePickerBootcamp: View {
    @State var selectedDate: Date = Date()
    
    let startingDate: Date = Calendar.current.date(from: DateComponents(year: 2018)) ?? Date()
    let endingDate: Date = Calendar.current.date(from: DateComponents(year: 2038)) ?? Date()
    
    //设置输出的日期格式
    var dateFormatter: DateFormatter {
        let formatter = DateFormatter()
        formatter.dateStyle = .short
        formatter.timeStyle = .short
        return formatter
    }
    
    var body: some View {
        
        VStack{
            HStack{
                Text("选中的日期是:")
                Text(dateFormatter.string(from: selectedDate))
                    .foregroundStyle(.green)
            }
            
            
            DatePicker("日期选择器1", selection: $selectedDate)
                .datePickerStyle(CompactDatePickerStyle())//默认CompactDatePickerStyle
            
            //displayedComponents可以具体要日、时、分?
            DatePicker("日期选择器2", selection: $selectedDate, displayedComponents: [.date, .hourAndMinute])
                .datePickerStyle(GraphicalDatePickerStyle())//展开样式
            
            //in 可以设置时间的起止日期
            DatePicker("日期选择3", selection: $selectedDate, in: startingDate...endingDate, displayedComponents: [.date])
                .datePickerStyle(WheelDatePickerStyle())
            
        }
        .accentColor(Color.red)
        
    }
}

#Preview {
    DatePickerBootcamp()
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值