一、SwiftUI 实用控件

71 阅读3分钟

1、图片下载--URLSession

struct ContentView : View
{
    @State private var remoteImage : UIImage? = nil
    let placeholderOne = UIImage(named: "PlaceholderPicture")
    
    var body: some View
    {
        Image(uiImage: self.remoteImage ?? placeholderOne!)
            .onAppear(perform: fetchRemoteImage)
    }
    
    func fetchRemoteImage()
    {
        guard let url = URL(string: "http://hdjc8.com/images/logo.png") else { return }
        URLSession.shared.dataTask(with: url)
        { (data, response, error) in
            if let image = UIImage(data: data!)
            {
                self.remoteImage = image
            }
            else
            {
                print(error ?? "")
            }
        }
        .resume()
    }
}

2、DatePicker日期拾取器

import SwiftUI

struct ContentView : View
{
    var myDateFormatter: DateFormatter
    {
        let formatter = DateFormatter()
        formatter.dateStyle = .long
        return formatter
    }

    @State var selectedDate = Date()

    var body: some View
    {
        VStack
        {
            DatePicker(selection: $selectedDate, displayedComponents: DatePickerComponents.hourAndMinute)
            {
                Text("Date")
            }
            
            DatePicker(selection: $selectedDate, displayedComponents: DatePickerComponents.date)
            {
                Text("Date")
            }
            .labelsHidden()

            DatePicker(selection: $selectedDate,in: Date()...Date().advanced(by: 7*24*3600), displayedComponents: [.date, .hourAndMinute])
            {
                Text("Date")
            }
            .datePickerStyle(GraphicalDatePickerStyle())

            Text("Your Choice: \(selectedDate, formatter: myDateFormatter)")
        }
    }
}

3、ColorPicker颜色拾取器

import SwiftUI

struct ContentView : View
{
    @State var color = Color.black
    
    var body: some View
    {
        VStack(alignment: .center)
        {
            Circle()
                .frame(width: 300, height: 300)
                .foregroundColor(color)
            
            Spacer()
                .frame(height: 20)
            
            HStack
            {
                ColorPicker("Pick color: ", selection: self.$color, supportsOpacity: true)
            }
        }
        .padding()
    }
}

4、Picker分段选择器实现--SegmentedPickerStyle

import SwiftUI

struct ContentView : View
{
    private let animals = ["🐶 Dog", "🐯 Tiger", "🐷 Pig"]
    @State private var selectedAnimal = 0

    var body: some View
    {
        VStack
        {
            Picker(selection: $selectedAnimal, label: Text("animals"))
            {
                ForEach(0 ..< animals.count)
                {
                    Text(self.animals[$0]).tag($0)
                }
            }
            .pickerStyle(SegmentedPickerStyle())
            
            Text("Your choice: \(animals[selectedAnimal])")
        }
        .padding()
    }
}

5、Slider滑杆

import SwiftUI

struct ContentView : View
{
     @State var temperature: Double = 0

    var body: some View
       {
            VStack
            {
                Slider(value: $temperature)
//                Slider(value: $temperature, in: -20...40)
                Slider(value: $temperature, in: -20...40)
                { (item) in
                    print(item)
                }
                
                HStack
                {
                    Image(systemName: "sun.max")

                    Slider(value: $temperature, in: -20...40, step: 2)
                    { (item) in
                        print(item)
                    }
                    .accentColor(.pink).colorInvert()
                    
                   Image(systemName: "sun.max.fill")
                }
                .padding()

                Text("The temperature is \(Int(temperature)).")
           }
       }
}

6、Stepper步进器

import SwiftUI

struct ContentView : View
{
     @State var temperature: Double = 0

       var body: some View
       {
            VStack
            {
                Stepper(onIncrement: {
                    self.temperature += 1
                }, onDecrement: {
                    self.temperature -= 1
                }, label:
                {
                    Text("Temperature: \(Int(temperature))")
                })
                
                Stepper(onIncrement: {
                    self.temperature += 1
                }, onDecrement: {
                    self.temperature -= 1
                }, onEditingChanged: { (item) in
                    print(item)
                }, label: {
                    Text("Temperature: \(Int(temperature))")
                })
           
            }
            .padding()
        }
}

7、Toggle开关

import SwiftUI

struct ContentView : View
{
    @State var showNotification = true

    var body: some View
    {
        VStack
        {
            Text("Show Notification: ")
            + Text("\(self.showNotification.description)")
                .foregroundColor(.green)
                .bold()
                
            Toggle(isOn: $showNotification)
            {
                Text("Show notification:")
            }
            .padding()
        }
    }
}

8、Tabview切换页面--tabItem

import SwiftUI

struct ContentView: View {
//-----------------------------
    var body: some View {
        TabView {
            Text("AAAAAA")
                .tabItem{
                    Image(systemName: "car.2")
                    Text("个人")
                }
            Text("BBBBBB")
                .tabItem{
                    Image(systemName: "figure.walk")
                    Text("测试")
                }
        }
    }
}

9、Tabview实现分页效果--tabViewStyle

import SwiftUI

struct ContentView : View
{
    var body: some View
    {
        ScrollView
        {
            TabView
            {
                Text("The home page.")
                    .font(.system(size: 36))
                    .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
                    .background(Color.orange)
                    .tabItem({
                        Image(systemName: "house")
                        Text("Home") })
                
                Text("The settings page")
                    .font(.system(size: 36))
                    .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
                    .background(Color.purple)
                    .tabItem({
                        Image(systemName: "gear")
                        Text("Settings")
                    })
            }
            .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .always))
        }
        .edgesIgnoringSafeArea(.all)
    }
}

10、实现WebKit网页视图--UIViewRepresentable

import SwiftUI
import WebKit

struct ContentView : UIViewRepresentable
{
    func makeUIView(context: UIViewRepresentableContext<ContentView>) -> WKWebView
    {
        return WKWebView()
    }
    
    func updateUIView(_ uiView: WKWebView, context: UIViewRepresentableContext<ContentView>)
    {
        let request = URLRequest(url:URL(string: "https://www.apple.com")!)
        uiView.load(request)
    }
}

11、Map视图创建地图和MapPin

import SwiftUI
import MapKit

struct IdentifiableMapPin : Identifiable
{
    var id : Int
    var mapPin : MapPin
}

struct ContentView : View
{
    @State var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 39.915352,
                              longitude: 116.397105),
            span: MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02))
    @State var mapPins : [IdentifiableMapPin] = []
    
    var body: some View
    {
        Map(coordinateRegion: self.$region, annotationItems: mapPins) { identifiableMapPin in
            identifiableMapPin.mapPin
        }
        .onAppear(perform:
        {
            let newMapPin = MapPin(coordinate: CLLocationCoordinate2D(latitude: 39.915352, longitude: 116.397105))
            self.mapPins.append(IdentifiableMapPin(id: self.mapPins.count, mapPin: newMapPin))
        })
    }
}

12、使用MapKit里的地图视图--UIViewRepresentable

import SwiftUI
import MapKit

struct ContentView : UIViewRepresentable
{
    
    func makeUIView(context: UIViewRepresentableContext<ContentView>) -> MKMapView
    {
        return MKMapView()
    }
    
    func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<ContentView>)
    {
        uiView.showsUserLocation = true
        uiView.mapType = MKMapType.satellite
        
        let coordinate2D = CLLocationCoordinate2D(latitude: 39.915352, longitude: 116.397105)
        let zoomLevel = 0.02
        let region = MKCoordinateRegion(center: coordinate2D, span: MKCoordinateSpan(latitudeDelta: zoomLevel, longitudeDelta: zoomLevel))
        
        uiView.setRegion(uiView.regionThatFits(region), animated: true)
    }
}

13、ActivityIndicator的实现--UIViewRepresentable & @Bind

import UIKit
import SwiftUI

struct ContentView : View
{
    @State var isActive = true
    
    var body: some View
    {
        LoadingView(isActive: self.$isActive)
        .onAppear
        {
            Timer.scheduledTimer(withTimeInterval: 2, repeats: false)
            { (timer) in
                self.isActive.toggle()
                timer.invalidate()
            }
        }
    }
}

struct ActivityIndicator: UIViewRepresentable
{
    @Binding var isActive: Bool

    func makeUIView(context: UIViewRepresentableContext<ActivityIndicator>) -> UIActivityIndicatorView
    {
        return UIActivityIndicatorView(style: UIActivityIndicatorView.Style.large)
    }

    func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<ActivityIndicator>)
    {
        isActive ? uiView.startAnimating() : uiView.stopAnimating()
    }
}

struct LoadingView: View
{
    @Binding var isActive: Bool

    var body: some View
    {
        VStack
        {
            Text("Waiting...")
            ActivityIndicator(isActive: self.$isActive)
        }
        .frame(width: UIScreen.main.bounds.width / 2,
               height: UIScreen.main.bounds.height / 5)
        .background(Color.orange)
        .foregroundColor(Color.primary)
        .cornerRadius(20)
        .opacity(self.isActive ? 1 : 0)
    }
}

14、ActivityIndicator的实现--UIViewRepresentable & @EnvironmentObject(ObservableObject)

import UIKit
import SwiftUI
import Combine

class GlobalData : ObservableObject
{
    @Published var isActive = false
    var cancelableSubscriber : AnyCancellable? = nil
    
    init()
    {
        cancelableSubscriber = $isActive
            .delay(for: 3, scheduler: RunLoop.main)
            .map{val in false}
            .assign(to: \.isActive, on: self)
    }
}

struct ContentView : View
{
    @EnvironmentObject var globalData : GlobalData
    
    var body: some View
    {
        LoadingView(isActive:  $globalData.isActive)
    }
}

struct ActivityIndicator: UIViewRepresentable
{
    @Binding var isActive: Bool

    func makeUIView(context: UIViewRepresentableContext<ActivityIndicator>) -> UIActivityIndicatorView
    {
        return UIActivityIndicatorView(style: UIActivityIndicatorView.Style.large)
    }

    func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<ActivityIndicator>)
    {
        isActive ? uiView.startAnimating() : uiView.stopAnimating()
    }
}

struct LoadingView: View
{
    @Binding var isActive: Bool

    var body: some View
    {
        VStack
        {
            Text("Waiting...")
            ActivityIndicator(isActive: self.$isActive)
        }
        .frame(width: UIScreen.main.bounds.width / 2,
               height: UIScreen.main.bounds.height / 5)
        .background(Color.orange)
        .foregroundColor(Color.primary)
        .cornerRadius(20)
        .opacity(self.isActive ? 1 : 0)
    }
}

#if DEBUG
struct ContentView_Previews : PreviewProvider
{
    static var previews: some View
    {
        let globalData = GlobalData()
        globalData.isActive = true
        
        return ContentView().environmentObject(globalData)
    }
}
#endif

15、圆形进度条实现

import SwiftUI
 
struct CircleProgressView: View {
    var body: some View {
        Circle()
            .trim(from: 0, to: 0.5) // 进度为50%
            .stroke(style: StrokeStyle(lineWidth: 10, lineCap: .round))
            .foregroundColor(.blue)
            .frame(width: 100, height: 100)
            .overlay(
                Text("50%")
                    .foregroundColor(.white)
                    .font(.caption)
                    .position(x: 50, y: 50)
            )
            .animation(.linear, value: 0.5)
            .rotationEffect(.degrees(270)) // 起始角度
    }
}

16、ProgressView进度条

import SwiftUI

struct ContentView : View
{
    @State var value  = 20.0
    
    var body: some View
    {
        VStack
        {
//            ProgressView()
//                .progressViewStyle(CircularProgressViewStyle(tint: Color.orange))
            
            ProgressView(value: value, total: 100)
            {
                Text(String(format: "%.2f", value))
            }
            Button(action:
            {
                if(self.value <= 90)
                {
                    self.value += 10
                }
            }, label: {
                Text("Go ahead")
            })
        }
        .padding()
    }
}

17、旋转和偏移功能

import SwiftUI

struct ContentView : View
{
    var body: some View
    {
        ZStack
        {
            Image("halfFace")
            
            Image("halfFace")
                .rotation3DEffect(.degrees(180), axis: (x: 1, y: 0, z: 0))
                .rotationEffect(.degrees(180), anchor: .center)
                .offset(x: 125, y: 0)
        }
        .offset(x: -70, y: 0)
    }
}
## 18Group & AnyView 的使用

import SwiftUI

struct ContentView : View { private var randomBool = Bool.random()

// var body: some View // { // Group // { // if randomBool // { // Image(systemName: "star.fill") // } // else // { // Text("Sorry, you miss the gift.") // .font(.system(size: 32)) // } // } // }

// var body: some View // { // if randomBool // { // return Text("Hi, you get the gift.") // .font(.system(size: 32)) // } // else // { // return Text("Sorry, you miss the gift.") // .font(.system(size: 32)) // } // }

var body: AnyView
{
    if randomBool
    {
        return AnyView(Image(systemName: "star.fill").font(.system(size: 72)))
    }
    else
    {
        return AnyView(Text("Sorry, you miss the gift.").font(.system(size: 32)))
    }
}

}

## 19、ViewModifier封装相同样式

import SwiftUI

struct ContentView : View { var body: some View { VStack(spacing: 40) { Image("avarta1") .modifier(myImageStyle())

        Image("avarta2")
            .modifier(myImageStyle())
        
        Image("avarta3")
            .modifier(myImageStyle())
    }
}

}

struct myImageStyle: ViewModifier { func body(content: Content) -> some View { content .frame(width: 200, height: 200, alignment: .trailing) .cornerRadius(100) .saturation(0.0) .brightness(0.1) } }

## 20、矩形Rectangle 和 圆角矩形RoundedRectangle

import SwiftUI

struct ContentView : View { var body: some View { VStack { Rectangle() Rectangle() .fill(Color.orange) .frame(width: 200, height: 200)

        ZStack
        {
           Rectangle().fill(Color.purple)
            .frame(width: 300, height: 200)

           Rectangle().fill(Color.yellow)
            .frame(width: 300, height: 200)
            .scaleEffect(0.8)

           Rectangle()
            .fill(Color.orange)
            .frame(width: 300, height: 200)
            .scaleEffect(0.6)
        }
        
        RoundedRectangle(cornerRadius: 120)

        RoundedRectangle(cornerSize: CGSize(width: 100, height: 40)).frame(width: 300, height: 200)
        
        RoundedRectangle(cornerRadius: 100, style: RoundedCornerStyle.continuous)
            .stroke(lineWidth: 20)
    }
    .padding(40)
}

}