mirror of
https://github.com/ivanvorobei/SwiftUI.git
synced 2026-05-02 05:24:28 +02:00
Update
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that displays a badge.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct Badge: View {
|
||||
static let rotationCount = 8
|
||||
|
||||
var badgeSymbols: some View {
|
||||
ForEach(0..<Badge.rotationCount) { i in
|
||||
RotatedBadgeSymbol(
|
||||
angle: .degrees(Double(i) / Double(Badge.rotationCount)) * 360.0)
|
||||
}
|
||||
.opacity(0.5)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
BadgeBackground()
|
||||
|
||||
GeometryReader { geometry in
|
||||
self.badgeSymbols
|
||||
.scaleEffect(1.0 / 4.0, anchor: .top)
|
||||
.position(x: geometry.size.width / 2.0, y: (3.0 / 4.0) * geometry.size.height)
|
||||
}
|
||||
}
|
||||
.scaledToFit()
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct Badge_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Badge()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that displays the background of a badge.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct BadgeBackground: View {
|
||||
var body: some View {
|
||||
GeometryReader { geometry in
|
||||
Path { path in
|
||||
var width: CGFloat = min(geometry.size.width, geometry.size.height)
|
||||
let height = width
|
||||
let xScale: CGFloat = 0.832
|
||||
let xOffset = (width * (1.0 - xScale)) / 2.0
|
||||
width *= xScale
|
||||
path.move(
|
||||
to: CGPoint(
|
||||
x: xOffset + width * 0.95,
|
||||
y: height * (0.20 + HexagonParameters.adjustment)
|
||||
)
|
||||
)
|
||||
|
||||
HexagonParameters.points.forEach {
|
||||
path.addLine(
|
||||
to: .init(
|
||||
x: xOffset + width * $0.useWidth.0 * $0.xFactors.0,
|
||||
y: height * $0.useHeight.0 * $0.yFactors.0
|
||||
)
|
||||
)
|
||||
|
||||
path.addQuadCurve(
|
||||
to: .init(
|
||||
x: xOffset + width * $0.useWidth.1 * $0.xFactors.1,
|
||||
y: height * $0.useHeight.1 * $0.yFactors.1
|
||||
),
|
||||
control: .init(
|
||||
x: xOffset + width * $0.useWidth.2 * $0.xFactors.2,
|
||||
y: height * $0.useHeight.2 * $0.yFactors.2
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
.fill(LinearGradient(
|
||||
gradient: .init(colors: [Self.gradientStart, Self.gradientEnd]),
|
||||
startPoint: .init(x: 0.5, y: 0),
|
||||
endPoint: .init(x: 0.5, y: 0.6)
|
||||
))
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
}
|
||||
}
|
||||
static let gradientStart = Color(red: 239.0 / 255, green: 120.0 / 255, blue: 221.0 / 255)
|
||||
static let gradientEnd = Color(red: 239.0 / 255, green: 172.0 / 255, blue: 120.0 / 255)
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct BadgeBackground_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
BadgeBackground()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that display a symbol in a badge.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct BadgeSymbol: View {
|
||||
static let symbolColor = Color(red: 79.0 / 255, green: 79.0 / 255, blue: 191.0 / 255)
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geometry in
|
||||
Path { path in
|
||||
let width = min(geometry.size.width, geometry.size.height)
|
||||
let height = width * 0.75
|
||||
let spacing = width * 0.030
|
||||
let middle = width / 2
|
||||
let topWidth = 0.226 * width
|
||||
let topHeight = 0.488 * height
|
||||
|
||||
path.addLines([
|
||||
CGPoint(x: middle, y: spacing),
|
||||
CGPoint(x: middle - topWidth, y: topHeight - spacing),
|
||||
CGPoint(x: middle, y: topHeight / 2 + spacing),
|
||||
CGPoint(x: middle + topWidth, y: topHeight - spacing),
|
||||
CGPoint(x: middle, y: spacing)
|
||||
])
|
||||
|
||||
path.move(to: CGPoint(x: middle, y: topHeight / 2 + spacing * 3))
|
||||
path.addLines([
|
||||
CGPoint(x: middle - topWidth, y: topHeight + spacing),
|
||||
CGPoint(x: spacing, y: height - spacing),
|
||||
CGPoint(x: width - spacing, y: height - spacing),
|
||||
CGPoint(x: middle + topWidth, y: topHeight + spacing),
|
||||
CGPoint(x: middle, y: topHeight / 2 + spacing * 3)
|
||||
])
|
||||
}
|
||||
.fill(Self.symbolColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct BadgeSymbol_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
BadgeSymbol()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that clips an image to a circle and adds a stroke and shadow.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CircleImage: View {
|
||||
var image: Image
|
||||
|
||||
var body: some View {
|
||||
image
|
||||
.clipShape(Circle())
|
||||
.overlay(Circle().stroke(Color.white, lineWidth: 4))
|
||||
.shadow(radius: 10)
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct CircleImage_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
CircleImage(image: Image("turtlerock"))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A single line in the graph.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct GraphCapsule: View {
|
||||
var index: Int
|
||||
var height: Length
|
||||
var range: Range<Double>
|
||||
var overallRange: Range<Double>
|
||||
|
||||
var heightRatio: Length {
|
||||
max(Length(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
|
||||
}
|
||||
|
||||
var offsetRatio: Length {
|
||||
Length((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
|
||||
}
|
||||
|
||||
var animation: Animation {
|
||||
Animation.spring(initialVelocity: 5)
|
||||
.speed(2)
|
||||
.delay(0.03 * Double(index))
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Capsule()
|
||||
.fill(Color.white)
|
||||
.frame(height: height * heightRatio, alignment: .bottom)
|
||||
.offset(x: 0, y: height * -offsetRatio)
|
||||
.animation(animation)
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct GraphCapsule_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
GraphCapsule(index: 0, height: 150, range: 10..<50, overallRange: 0..<100)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
The elevation, heart rate, and pace of a hike plotted on a graph.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
func rangeOfRanges<C: Collection>(_ ranges: C) -> Range<Double>
|
||||
where C.Element == Range<Double> {
|
||||
guard !ranges.isEmpty else { return 0..<0 }
|
||||
let low = ranges.lazy.map { $0.lowerBound }.min()!
|
||||
let high = ranges.lazy.map { $0.upperBound }.max()!
|
||||
return low..<high
|
||||
}
|
||||
|
||||
func magnitude(of range: Range<Double>) -> Double {
|
||||
return range.upperBound - range.lowerBound
|
||||
}
|
||||
|
||||
struct HikeGraph: View {
|
||||
var hike: Hike
|
||||
var path: KeyPath<Hike.Observation, Range<Double>>
|
||||
|
||||
var color: Color {
|
||||
switch path {
|
||||
case \.elevation:
|
||||
return .gray
|
||||
case \.heartRate:
|
||||
return Color(hue: 0, saturation: 0.5, brightness: 0.7)
|
||||
case \.pace:
|
||||
return Color(hue: 0.7, saturation: 0.4, brightness: 0.7)
|
||||
default:
|
||||
return .black
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
let data = hike.observations
|
||||
let overallRange = rangeOfRanges(data.lazy.map { $0[keyPath: self.path] })
|
||||
let maxMagnitude = data.map { magnitude(of: $0[keyPath: path]) }.max()!
|
||||
let heightRatio = 1 - Length(maxMagnitude / magnitude(of: overallRange))
|
||||
|
||||
return GeometryReader { proxy in
|
||||
HStack(alignment: .bottom, spacing: proxy.size.width / 120) {
|
||||
ForEach(data.indices) { index in
|
||||
GraphCapsule(
|
||||
index: index,
|
||||
height: proxy.size.height,
|
||||
range: data[index][keyPath: self.path],
|
||||
overallRange: overallRange)
|
||||
.colorMultiply(self.color)
|
||||
}
|
||||
.offset(x: 0, y: proxy.size.height * heightRatio)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct HikeGraph_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
HikeGraph(hike: hikeData[0], path: \.elevation)
|
||||
.frame(height: 200)
|
||||
HikeGraph(hike: hikeData[0], path: \.heartRate)
|
||||
.frame(height: 200)
|
||||
HikeGraph(hike: hikeData[0], path: \.pace)
|
||||
.frame(height: 200)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A single row to be displayed in a list of landmarks.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct LandmarkRow: View {
|
||||
var landmark: Landmark
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
landmark.image(forSize: 50)
|
||||
Text(verbatim: landmark.name)
|
||||
Spacer()
|
||||
|
||||
if landmark.isFavorite {
|
||||
Image(systemName: "star.fill")
|
||||
.imageScale(.medium)
|
||||
.foregroundColor(.yellow)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct LandmarkRow_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
LandmarkRow(landmark: landmarkData[0])
|
||||
LandmarkRow(landmark: landmarkData[1])
|
||||
}
|
||||
.previewLayout(.fixed(width: 300, height: 70))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that hosts an `MKMapView`.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
import MapKit
|
||||
|
||||
struct MapView: UIViewRepresentable {
|
||||
var coordinate: CLLocationCoordinate2D
|
||||
|
||||
func makeUIView(context: Context) -> MKMapView {
|
||||
MKMapView(frame: .zero)
|
||||
}
|
||||
|
||||
func updateUIView(_ view: MKMapView, context: Context) {
|
||||
let span = MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)
|
||||
let region = MKCoordinateRegion(center: coordinate, span: span)
|
||||
view.setRegion(region, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct MapView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MapView(coordinate: landmarkData[0].locationCoordinate)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
See LICENSE folder for this sample’s licensing information.
|
||||
|
||||
Abstract:
|
||||
A view that displays a rotated version of a badge symbol.
|
||||
*/
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct RotatedBadgeSymbol: View {
|
||||
let angle: Angle
|
||||
|
||||
var body: some View {
|
||||
BadgeSymbol()
|
||||
.padding(-60)
|
||||
.rotationEffect(angle, anchor: .bottom)
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct RotatedBadgeSymbol_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
RotatedBadgeSymbol(angle: .init(degrees: 5))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user