From 24e4debcfa195259e2edfef9ed81cf15af6ba26e Mon Sep 17 00:00:00 2001 From: pepix Date: Tue, 1 Jun 2021 12:20:49 +0900 Subject: [PATCH 1/3] Add ProgressView --- AltSwiftUI.xcodeproj/project.pbxproj | 4 + .../project.pbxproj | 4 + .../ProgressViewExampleView.swift | 39 +++++++ .../AltSwiftUIExample/ViewController.swift | 1 + .../Source/Views/ReadOnly/ProgressView.swift | 109 ++++++++++++++++++ 5 files changed, 157 insertions(+) create mode 100644 Example/AltSwiftUIExample/ExampleViews/ProgressViewExampleView.swift create mode 100644 Sources/AltSwiftUI/Source/Views/ReadOnly/ProgressView.swift diff --git a/AltSwiftUI.xcodeproj/project.pbxproj b/AltSwiftUI.xcodeproj/project.pbxproj index 13b41f1..736aa8d 100644 --- a/AltSwiftUI.xcodeproj/project.pbxproj +++ b/AltSwiftUI.xcodeproj/project.pbxproj @@ -76,6 +76,7 @@ 2CD1A04E2512066D00E2CCBA /* AltSwiftUI.h in Headers */ = {isa = PBXBuildFile; fileRef = 2CD1A00D2512066D00E2CCBA /* AltSwiftUI.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2CD1A056251206C200E2CCBA /* ViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD1A054251206C200E2CCBA /* ViewTests.swift */; }; 68CBD3E12578AADB00A3F033 /* SecureField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68CBD3E02578AADB00A3F033 /* SecureField.swift */; }; + 714D6C84265F6629003F2682 /* ProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 714D6C83265F6629003F2682 /* ProgressView.swift */; }; 7D2D4D6B25148269000F5DDC /* Capsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D2D4D6525148269000F5DDC /* Capsule.swift */; }; 7D2D4D6C25148269000F5DDC /* Circle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D2D4D6625148269000F5DDC /* Circle.swift */; }; 7D2D4D6D25148269000F5DDC /* Ellipse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D2D4D6725148269000F5DDC /* Ellipse.swift */; }; @@ -167,6 +168,7 @@ 2CD1A054251206C200E2CCBA /* ViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewTests.swift; sourceTree = ""; }; 2CD1A055251206C200E2CCBA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 68CBD3E02578AADB00A3F033 /* SecureField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureField.swift; sourceTree = ""; }; + 714D6C83265F6629003F2682 /* ProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressView.swift; sourceTree = ""; }; 7D2D4D6525148269000F5DDC /* Capsule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Capsule.swift; sourceTree = ""; }; 7D2D4D6625148269000F5DDC /* Circle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Circle.swift; sourceTree = ""; }; 7D2D4D6725148269000F5DDC /* Ellipse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Ellipse.swift; sourceTree = ""; }; @@ -355,6 +357,7 @@ 2CD19FEA2512066D00E2CCBA /* ReadOnly */ = { isa = PBXGroup; children = ( + 714D6C83265F6629003F2682 /* ProgressView.swift */, 2CD19FF02512066D00E2CCBA /* Color.swift */, 2CD19FEE2512066D00E2CCBA /* Divider.swift */, 2CD19FF22512066D00E2CCBA /* GeometryReader.swift */, @@ -638,6 +641,7 @@ 2CD1A01C2512066D00E2CCBA /* StateObject.swift in Sources */, 2CD1A03F2512066D00E2CCBA /* TabView.swift in Sources */, 2CD1A0372512066D00E2CCBA /* GeometryReader.swift in Sources */, + 714D6C84265F6629003F2682 /* ProgressView.swift in Sources */, 2CD1A03D2512066D00E2CCBA /* CoreViews.swift in Sources */, 2CD1A0212512066D00E2CCBA /* UIKitCoreViews.swift in Sources */, ); diff --git a/Example/AltSwiftUIExample.xcodeproj/project.pbxproj b/Example/AltSwiftUIExample.xcodeproj/project.pbxproj index ce049b6..3efbabb 100644 --- a/Example/AltSwiftUIExample.xcodeproj/project.pbxproj +++ b/Example/AltSwiftUIExample.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 2CFE2AC025AD487800C925FC /* ScrollView2AxisExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CFE2ABF25AD487800C925FC /* ScrollView2AxisExampleView.swift */; }; 35D1A58825C7EDA100861DC4 /* AlertsExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35D1A58525C7EDA100861DC4 /* AlertsExampleView.swift */; }; 682C3A7C2594B18A005E798E /* SecureFieldExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682C3A7B2594B18A005E798E /* SecureFieldExampleView.swift */; }; + 714D6C8B265F69CD003F2682 /* ProgressViewExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 714D6C8A265F69CD003F2682 /* ProgressViewExampleView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -100,6 +101,7 @@ 2CFE2ABF25AD487800C925FC /* ScrollView2AxisExampleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollView2AxisExampleView.swift; sourceTree = ""; }; 35D1A58525C7EDA100861DC4 /* AlertsExampleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertsExampleView.swift; sourceTree = ""; }; 682C3A7B2594B18A005E798E /* SecureFieldExampleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureFieldExampleView.swift; sourceTree = ""; }; + 714D6C8A265F69CD003F2682 /* ProgressViewExampleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressViewExampleView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -143,6 +145,7 @@ 2C83ED512554E50400C378DC /* NavigationExampleView.swift */, 2CADC30E251CA0DF00EA3F17 /* RamenExampleView.swift */, 682C3A7B2594B18A005E798E /* SecureFieldExampleView.swift */, + 714D6C8A265F69CD003F2682 /* ProgressViewExampleView.swift */, 2CFE2ABF25AD487800C925FC /* ScrollView2AxisExampleView.swift */, 2CADC316251CA15400EA3F17 /* ShapesExampleView.swift */, 2C49E3CB2535382F00543E7D /* TextExampleView.swift */, @@ -384,6 +387,7 @@ 2CE5E28B231398D70072F907 /* AppDelegate.swift in Sources */, 2CDCE7F325C40D2500BB52D1 /* StackUpdateExample.swift in Sources */, 2C0BE74C2521CEE800B37BA9 /* ListExampleView.swift in Sources */, + 714D6C8B265F69CD003F2682 /* ProgressViewExampleView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Example/AltSwiftUIExample/ExampleViews/ProgressViewExampleView.swift b/Example/AltSwiftUIExample/ExampleViews/ProgressViewExampleView.swift new file mode 100644 index 0000000..c77d5cd --- /dev/null +++ b/Example/AltSwiftUIExample/ExampleViews/ProgressViewExampleView.swift @@ -0,0 +1,39 @@ +// +// ProgressViewExampleView.swift +// AltSwiftUIExample +// +// Created by Tsuchiya, Hiroma | Hiroma | TID on 2021/05/27. +// Copyright © 2021 Rakuten Travel. All rights reserved. +// + +import AltSwiftUI + +struct ProgressViewExampleView: View { + var viewStore = ViewValues() + @State private var progressValue: Float = 0.7 + + var body: View { + VStack { + HStack { + ProgressView() + ProgressView("Now loading...") + } + + Divider() + + Button { + progressValue = Float.random(in: 0..<1) + } label: { () -> View in + Text("Set a random progress value") + } + + Text(String(progressValue)) + + ProgressView(progressValue) + .frame(maxWidth: .infinity) + ProgressView("Downloading...", value: progressValue, total: 1.0) + .frame(maxWidth: .infinity) + } + .frame(maxWidth: .infinity) + } +} diff --git a/Example/AltSwiftUIExample/ViewController.swift b/Example/AltSwiftUIExample/ViewController.swift index c8e6f40..0ced224 100644 --- a/Example/AltSwiftUIExample/ViewController.swift +++ b/Example/AltSwiftUIExample/ViewController.swift @@ -30,6 +30,7 @@ struct ExampleView: View { ExampleViewData(title: "Shapes", destination: ShapesExampleView()), ExampleViewData(title: "Stack Update", destination: StackUpdateExample()), ExampleViewData(title: "Texts", destination: TextExampleView()), + ExampleViewData(title: "ProgressView", destination: ProgressViewExampleView()), ExampleViewData(title: "Ramen Example", destination: RamenExampleView()) ] diff --git a/Sources/AltSwiftUI/Source/Views/ReadOnly/ProgressView.swift b/Sources/AltSwiftUI/Source/Views/ReadOnly/ProgressView.swift new file mode 100644 index 0000000..89440a1 --- /dev/null +++ b/Sources/AltSwiftUI/Source/Views/ReadOnly/ProgressView.swift @@ -0,0 +1,109 @@ +// +// ProgressView.swift +// AltSwiftUI +// +// Created by Tsuchiya, Hiroma | Hiroma | TID on 2021/05/27. +// Copyright © 2021 Rakuten Travel. All rights reserved. +// + +import UIKit + +/// A view that shows the progress towards completion of a task. +public struct ProgressView: View { + public var viewStore = ViewValues() + public var body: View { + self + } + + var title: String? + var label: View? + var progress: Float? + var total: Float? + + public init() {} + + public init(_ title: String) { + self.title = title + } + + public init(label: View) { + self.label = label + } + + public init(_ progress: Float) { + self.progress = progress + } + + public init(value: Float?, total: Float? = 1.0) { + self.progress = (value ?? 0) / (total ?? 1.0) + } + + public init(_ title: String, value: Float?, total: Float?) { + self.title = title + self.progress = (value ?? 0) / (total ?? 1.0) + } +} + +extension ProgressView: Renderable { + public func createView(context: Context) -> UIView { + if (progress != nil) { + /// Determinate Progress View + if (title != nil) { + let titleView = UITextView() + titleView.text = title + titleView.isScrollEnabled = false + titleView.textColor = .gray + let progressView = UIProgressView(progressViewStyle: UIProgressView.Style.default) + updateView(progressView, context: context) + let view = UIStackView() + view.axis = .vertical + view.alignment = .leading + view.addArrangedSubview(titleView) + view.addArrangedSubview(progressView) +// updateView(view, context: context) + return view +// return progressView + } else { + let view = UIProgressView(progressViewStyle: UIProgressView.Style.default) + updateView(view, context: context) + return view + } + + } else { + /// Indeterminate Progress View + if (title != nil) { + let indicatorView = UIActivityIndicatorView(style: .whiteLarge) + indicatorView.color = .gray + indicatorView.startAnimating() + let titleView = UITextView() + titleView.text = title + titleView.isScrollEnabled = false + titleView.textColor = .gray + let view = UIStackView() + view.axis = .vertical + view.alignment = .center + view.addArrangedSubview(indicatorView) + view.addArrangedSubview(titleView) + return view + } else { + let view = UIActivityIndicatorView(style: .whiteLarge) + view.color = .gray + view.startAnimating() + return view + } + } + } + + public func updateView(_ view: UIView, context: Context) { + print("updateView") + if let progressView = view as? UIProgressView { + progressView.setProgress(progress ?? 0, animated: true) + } + + if let uiStackView = view as? UIStackView { + if let progressView = uiStackView.subviews.last as? UIProgressView { + progressView.setProgress(progress ?? 0, animated: false) + } + } + } +} From e7cb04e64fd21d37ceee031d702636417ab01461 Mon Sep 17 00:00:00 2001 From: pepix Date: Tue, 1 Jun 2021 15:17:05 +0900 Subject: [PATCH 2/3] Set a properly constraint to inside of stack --- .../ExampleViews/ProgressViewExampleView.swift | 17 +++++++++++++++-- .../Source/Views/ReadOnly/ProgressView.swift | 8 +++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Example/AltSwiftUIExample/ExampleViews/ProgressViewExampleView.swift b/Example/AltSwiftUIExample/ExampleViews/ProgressViewExampleView.swift index c77d5cd..fa27312 100644 --- a/Example/AltSwiftUIExample/ExampleViews/ProgressViewExampleView.swift +++ b/Example/AltSwiftUIExample/ExampleViews/ProgressViewExampleView.swift @@ -13,26 +13,39 @@ struct ProgressViewExampleView: View { @State private var progressValue: Float = 0.7 var body: View { - VStack { + VStack() { + Spacer() + HStack { + Spacer() ProgressView() + Spacer() ProgressView("Now loading...") + Spacer() } + Spacer() + Divider() + Spacer() + Button { progressValue = Float.random(in: 0..<1) } label: { () -> View in Text("Set a random progress value") } - Text(String(progressValue)) + Text(String(floor(progressValue * 100)) + "%") + .padding(.bottom, 16) ProgressView(progressValue) .frame(maxWidth: .infinity) + ProgressView("Downloading...", value: progressValue, total: 1.0) .frame(maxWidth: .infinity) + + Spacer() } .frame(maxWidth: .infinity) } diff --git a/Sources/AltSwiftUI/Source/Views/ReadOnly/ProgressView.swift b/Sources/AltSwiftUI/Source/Views/ReadOnly/ProgressView.swift index 89440a1..6e3693f 100644 --- a/Sources/AltSwiftUI/Source/Views/ReadOnly/ProgressView.swift +++ b/Sources/AltSwiftUI/Source/Views/ReadOnly/ProgressView.swift @@ -53,16 +53,15 @@ extension ProgressView: Renderable { titleView.text = title titleView.isScrollEnabled = false titleView.textColor = .gray - let progressView = UIProgressView(progressViewStyle: UIProgressView.Style.default) + let progressView = UIProgressView(progressViewStyle: .default) updateView(progressView, context: context) let view = UIStackView() view.axis = .vertical view.alignment = .leading view.addArrangedSubview(titleView) view.addArrangedSubview(progressView) -// updateView(view, context: context) + progressView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true return view -// return progressView } else { let view = UIProgressView(progressViewStyle: UIProgressView.Style.default) updateView(view, context: context) @@ -95,14 +94,13 @@ extension ProgressView: Renderable { } public func updateView(_ view: UIView, context: Context) { - print("updateView") if let progressView = view as? UIProgressView { progressView.setProgress(progress ?? 0, animated: true) } if let uiStackView = view as? UIStackView { if let progressView = uiStackView.subviews.last as? UIProgressView { - progressView.setProgress(progress ?? 0, animated: false) + progressView.setProgress(progress ?? 0, animated: true) } } } From 414ba18e4c77e7e0e6a330abeb8f8baa6dd07b2a Mon Sep 17 00:00:00 2001 From: pepix Date: Tue, 8 Jun 2021 17:12:30 +0900 Subject: [PATCH 3/3] Refactor code --- .../Source/Views/ReadOnly/ProgressView.swift | 87 +++++++++++-------- 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/Sources/AltSwiftUI/Source/Views/ReadOnly/ProgressView.swift b/Sources/AltSwiftUI/Source/Views/ReadOnly/ProgressView.swift index 6e3693f..09d158f 100644 --- a/Sources/AltSwiftUI/Source/Views/ReadOnly/ProgressView.swift +++ b/Sources/AltSwiftUI/Source/Views/ReadOnly/ProgressView.swift @@ -49,46 +49,16 @@ extension ProgressView: Renderable { if (progress != nil) { /// Determinate Progress View if (title != nil) { - let titleView = UITextView() - titleView.text = title - titleView.isScrollEnabled = false - titleView.textColor = .gray - let progressView = UIProgressView(progressViewStyle: .default) - updateView(progressView, context: context) - let view = UIStackView() - view.axis = .vertical - view.alignment = .leading - view.addArrangedSubview(titleView) - view.addArrangedSubview(progressView) - progressView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true - return view + return makeDeterminateProgressViewWithTitle(title: title!, context: context) } else { - let view = UIProgressView(progressViewStyle: UIProgressView.Style.default) - updateView(view, context: context) - return view + return makeDeterminateProgressView(context: context) } - } else { /// Indeterminate Progress View if (title != nil) { - let indicatorView = UIActivityIndicatorView(style: .whiteLarge) - indicatorView.color = .gray - indicatorView.startAnimating() - let titleView = UITextView() - titleView.text = title - titleView.isScrollEnabled = false - titleView.textColor = .gray - let view = UIStackView() - view.axis = .vertical - view.alignment = .center - view.addArrangedSubview(indicatorView) - view.addArrangedSubview(titleView) - return view + return makeIndeterminateProgressViewWithTitle(title: title!) } else { - let view = UIActivityIndicatorView(style: .whiteLarge) - view.color = .gray - view.startAnimating() - return view + return makeIndeterminateProgressView() } } } @@ -96,12 +66,55 @@ extension ProgressView: Renderable { public func updateView(_ view: UIView, context: Context) { if let progressView = view as? UIProgressView { progressView.setProgress(progress ?? 0, animated: true) - } - - if let uiStackView = view as? UIStackView { + } else if let uiStackView = view as? UIStackView { if let progressView = uiStackView.subviews.last as? UIProgressView { progressView.setProgress(progress ?? 0, animated: true) } } } + + func makeDeterminateProgressViewWithTitle(title: String, context: Context) -> UIStackView { + let titleView = UILabel() + titleView.text = title + titleView.textColor = .gray + titleView.font = .systemFont(ofSize: 14) + let progressView = UIProgressView(progressViewStyle: .default) + updateView(progressView, context: context) + let view = UIStackView() + view.axis = .vertical + view.alignment = .leading + view.addArrangedSubview(titleView) + view.addArrangedSubview(progressView) + progressView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true + return view + } + + func makeDeterminateProgressView(context: Context) -> UIProgressView { + let view = UIProgressView(progressViewStyle: .default) + updateView(view, context: context) + return view + } + + func makeIndeterminateProgressViewWithTitle(title: String) -> UIStackView { + let indicatorView = UIActivityIndicatorView(style: .whiteLarge) + indicatorView.color = .gray + indicatorView.startAnimating() + let titleView = UILabel() + titleView.text = title + titleView.font = .systemFont(ofSize: 14) + titleView.textColor = .gray + let view = UIStackView() + view.axis = .vertical + view.alignment = .center + view.addArrangedSubview(indicatorView) + view.addArrangedSubview(titleView) + return view + } + + func makeIndeterminateProgressView() -> UIActivityIndicatorView { + let view = UIActivityIndicatorView(style: .whiteLarge) + view.color = .gray + view.startAnimating() + return view + } }