Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions AltSwiftUI.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
7D2D4D6E25148269000F5DDC /* Rectangle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D2D4D6825148269000F5DDC /* Rectangle.swift */; };
7D2D4D6F25148269000F5DDC /* Shapes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D2D4D6925148269000F5DDC /* Shapes.swift */; };
7D2D4D7025148269000F5DDC /* RoundedRectangle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D2D4D6A25148269000F5DDC /* RoundedRectangle.swift */; };
EAB11531265B437700E11F25 /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB11530265B437700E11F25 /* Label.swift */; };
EACD577F25EC694800FEF5A1 /* Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = EACD577E25EC694800FEF5A1 /* Menu.swift */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -174,6 +175,7 @@
7D2D4D6825148269000F5DDC /* Rectangle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Rectangle.swift; sourceTree = "<group>"; };
7D2D4D6925148269000F5DDC /* Shapes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Shapes.swift; sourceTree = "<group>"; };
7D2D4D6A25148269000F5DDC /* RoundedRectangle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoundedRectangle.swift; sourceTree = "<group>"; };
EAB11530265B437700E11F25 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = "<group>"; };
EACD577E25EC694800FEF5A1 /* Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Menu.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -364,6 +366,7 @@
2CD19FEB2512066D00E2CCBA /* Picker.swift */,
2CD19FEC2512066D00E2CCBA /* Spacer.swift */,
2CD19FEF2512066D00E2CCBA /* Text.swift */,
EAB11530265B437700E11F25 /* Label.swift */,
);
path = ReadOnly;
sourceTree = "<group>";
Expand Down Expand Up @@ -578,6 +581,7 @@
2CD1A00E2512066D00E2CCBA /* View.swift in Sources */,
2CD1A0492512066D00E2CCBA /* FoundationExtensions.swift in Sources */,
2CD1A0392512066D00E2CCBA /* Toggle.swift in Sources */,
EAB11531265B437700E11F25 /* Label.swift in Sources */,
2CD1A0352512066D00E2CCBA /* Color.swift in Sources */,
2CD1A0452512066D00E2CCBA /* HStack.swift in Sources */,
2CD1A0162512066D00E2CCBA /* StateTypes.swift in Sources */,
Expand Down
4 changes: 4 additions & 0 deletions Example/AltSwiftUIExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
EAB11538265B6C2E00E11F25 /* LebelExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB11537265B6C2E00E11F25 /* LebelExampleView.swift */; };
EACD577925EC689200FEF5A1 /* MenuExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EACD577825EC689200FEF5A1 /* MenuExampleView.swift */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -101,6 +102,7 @@
2CFE2ABF25AD487800C925FC /* ScrollView2AxisExampleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollView2AxisExampleView.swift; sourceTree = "<group>"; };
35D1A58525C7EDA100861DC4 /* AlertsExampleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertsExampleView.swift; sourceTree = "<group>"; };
682C3A7B2594B18A005E798E /* SecureFieldExampleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureFieldExampleView.swift; sourceTree = "<group>"; };
EAB11537265B6C2E00E11F25 /* LebelExampleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LebelExampleView.swift; sourceTree = "<group>"; };
EACD577825EC689200FEF5A1 /* MenuExampleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuExampleView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -152,6 +154,7 @@
EACD577825EC689200FEF5A1 /* MenuExampleView.swift */,
2C74075D262833D600FF4380 /* ScrollViewTextFieldExample.swift */,
2C7407632628365100FF4380 /* ListTextFieldExampleView.swift */,
EAB11537265B6C2E00E11F25 /* LebelExampleView.swift */,
);
path = ExampleViews;
sourceTree = "<group>";
Expand Down Expand Up @@ -377,6 +380,7 @@
2C49E3CC2535382F00543E7D /* TextExampleView.swift in Sources */,
2C7407642628365100FF4380 /* ListTextFieldExampleView.swift in Sources */,
682C3A7C2594B18A005E798E /* SecureFieldExampleView.swift in Sources */,
EAB11538265B6C2E00E11F25 /* LebelExampleView.swift in Sources */,
35D1A58825C7EDA100861DC4 /* AlertsExampleView.swift in Sources */,
2C83ED522554E50400C378DC /* NavigationExampleView.swift in Sources */,
2C74075E262833D600FF4380 /* ScrollViewTextFieldExample.swift in Sources */,
Expand Down
58 changes: 58 additions & 0 deletions Example/AltSwiftUIExample/ExampleViews/LebelExampleView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// LebelExampleView.swift
// AltSwiftUIExample
//
// Created by Chan, Chengwei on 2021/05/24.
// Copyright © 2021 Rakuten Travel. All rights reserved.
//

import AltSwiftUI

struct LabelExampleView: View {
var viewStore = ViewValues()
var body: View {
VStack(spacing: 20) {
Label("Lamen", image: "icon")

Label {
Text("fullName")
.font(.body)
.foregroundColor(.primary)
Text("(nickName)")
.font(.body)
.foregroundColor(.primary)
} icon: {
Circle()
.fill(.blue)
.frame(width: 44, height: 44)
}

Label {
Text("fullName")
.font(.body)
.foregroundColor(.primary)
Text("(nickName)")
.font(.body)
.foregroundColor(.primary)
} icon: {
Circle()
.fill(.blue)
.frame(width: 44, height: 44)
}
.labelStyle(TitleOnlyLabelStyle())

if #available(iOS 14.0, *) {
Label("Rain", systemImage: "cloud.rain")
}

if #available(iOS 14.0, *) {
VStack {
Label("Rain", systemImage: "cloud.rain")
Label("Snow", systemImage: "snow")
Label("Sun", systemImage: "sun.max")
}
.labelStyle(IconOnlyLabelStyle())
}
}
}
}
1 change: 1 addition & 0 deletions Example/AltSwiftUIExample/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct ExampleView: View {
ExampleViewData(title: "Shapes", destination: ShapesExampleView()),
ExampleViewData(title: "Stack Update", destination: StackUpdateExample()),
ExampleViewData(title: "Texts", destination: TextExampleView()),
ExampleViewData(title: "Label", destination: LabelExampleView()),
ExampleViewData(title: "Ramen Example", destination: RamenExampleView())
]

Expand Down
12 changes: 12 additions & 0 deletions Sources/AltSwiftUI/Source/ViewProperties/ViewPropertyBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,18 @@ extension View {
view.viewStore.accessibilityIdentifier = identifier
return view
}

// MARK: - Label
/// Sets the labelStyle of this view.
///
/// Apply labelStyle to labels views
///
/// - Parameter labelStyle: DefaultLabelStyle / TitleAndIconLabelStyle / TitleOnlyLabelStyle / IconOnlyLabelStyle.
public func labelStyle(_ labelStyle: LabelStyle) -> Self {
var view = self
view.viewStore.labelStyle = labelStyle
return view
}
}

/// Returns the result of executing `body` with `animation` installed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,45 @@ struct ViewDimensions: Hashable {
self.maxHeight = maxHeight
}
}

/// A protocol and basic class of label style
public protocol LabelStyle {
var labelStyleType: LabelStyleType { get set }
}

public struct DefaultLabelStyle: LabelStyle {
public var labelStyleType: LabelStyleType

public init() {
labelStyleType = .TitleAndIcon
}
}

public struct TitleAndIconLabelStyle: LabelStyle {
public var labelStyleType: LabelStyleType

public init() {
labelStyleType = .TitleAndIcon
}
}

public struct TitleOnlyLabelStyle: LabelStyle {
public var labelStyleType: LabelStyleType

public init() {
labelStyleType = .TitleOnly
}
}

public struct IconOnlyLabelStyle: LabelStyle {
public var labelStyleType: LabelStyleType

public init() {
labelStyleType = .IconOnly
}
}

/// A type that represents the label style of label
public enum LabelStyleType {
case TitleAndIcon, TitleOnly, IconOnly
}
3 changes: 2 additions & 1 deletion Sources/AltSwiftUI/Source/ViewProperties/ViewValues.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public struct ViewValues: AnimatedViewValuesHolder {
var skipOnHighPerformance: Bool?
var navigationAccentColor: UIColor?
var accessibilityIdentifier: String?
var labelStyle: LabelStyle?

private var skOverlayPresentationObject: Any? // Workaround as SKOverlayPresentation is only available from iOS 14.0+
@available(iOS 14.0, *)
Expand Down Expand Up @@ -141,7 +142,7 @@ extension ViewValues {
mergedValues.parentViewEventHandler = defaultValues.parentViewEventHandler }
if textContentType == nil { mergedValues.textContentType = defaultValues.textContentType }
if navigationAccentColor == nil { mergedValues.navigationAccentColor = defaultValues.navigationAccentColor }

if labelStyle == nil { mergedValues.labelStyle = defaultValues.labelStyle }
return mergedValues
}

Expand Down
115 changes: 115 additions & 0 deletions Sources/AltSwiftUI/Source/Views/ReadOnly/Label.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//
// Label.swift
// AltSwiftUI
//
// Created by Chan, Chengwei on 2021/05/24.
//

import UIKit

@available(iOS 14.0, *)
public typealias LocalizedStringKey = String
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can remove the constraint for this typealias


/// A view that display icon with text.
public struct Label<Title: View, Icon: View>: View {
public var viewStore = ViewValues()
var title: Title
var icon: Icon

/// Creates an instance that disaly an `icon` with a `title`.
///
/// - Parameters:
/// - title: The visual representation of right part text of the label
/// - icon: The visual representation of left part image of the label
public init(@ViewBuilder title: () -> Title, icon: () -> Icon) {
self.title = title()
self.icon = icon()
}

public var body: View {
self
}
}

extension Label where Title == Text, Icon == Image {
/// Creates an instance that disaly an `icon` with a `title`.
///
/// - Parameters:
/// - title: The string of right part text of the label
/// - icon: The visual representation of left part image of the label
public init<S: StringProtocol>(_ title: S, image: String) {
self.title = Text(title)
self.icon = Image(image)
}

/// Creates an instance that disaly an `icon` with a `title`.
///
/// - Parameters:
/// - title: The LocalizedStringKey of right part text of the label
/// - icon: The visual representation of left part image of the label
@available(iOS 14.0, *)
Copy link
Contributor

@kevinwl02 kevinwl02 Jun 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these 3 inits iOS14 available? I think you should be able to remove this constraint.

public init(_ title: LocalizedStringKey, image: String) {
self.title = Text(NSLocalizedString(title, comment: ""))
self.icon = Image(image)
}

/// Creates an instance that disaly an `icon` with a `title`.
///
/// - Parameters:
/// - title: The string of right part text of the label
/// - icon: The system icon name of left part image of the label
@available(iOS 14.0, *)
public init<S: StringProtocol>(_ title: S, systemImage: String) {
self.title = Text(title)
self.icon = Image(uiImage: UIImage(systemName: systemImage) ?? UIImage())
}

/// Creates an instance that disaly an `icon` with a `title`.
///
/// - Parameters:
/// - title: The LocalizedStringKey of right part text of the label
/// - icon: The system icon name of left part image of the label
@available(iOS 14.0, *)
public init(_ title: LocalizedStringKey, systemImage: String) {
self.title = Text(NSLocalizedString(title, comment: ""))
self.icon = Image(uiImage: UIImage(systemName: systemImage) ?? UIImage())
}
}

extension Label: Renderable {
public func updateView(_ view: UIView, context: Context) {
guard let stackView = view as? SwiftUIStackView else { return }
setupView(stackView, context: context)
}

public func createView(context: Context) -> UIView {
let hstack = HStack {
Spacer()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems this view always expands horizontally and always centered. Please confirm this behavior.

.frame(height: 0)
self.icon
self.title
Spacer()
.frame(height: 0)
}
if let stackView = hstack.createView(context: context) as? SwiftUIStackView {
setupView(stackView, context: context)
return stackView
}

return UIView()
}

private func setupView(_ view: UIStackView, context: Context) {
guard let labelStyleType = context.viewValues?.labelStyle?.labelStyleType else { return }

context.viewOperationQueue.addOperation {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not necessary to use the operation queue in this case.

Note: The operation queue main purpose is to flatten view hierarchy updates that would add strain to the call stack causing potential stack overflows. Usually this is used when you want to call updateView of children views.

for i in 1..<(view.arrangedSubviews.count - 1) {
if i <= self.icon.subViews.count {
view.arrangedSubviews[i].isHidden = (labelStyleType == .TitleOnly)
} else {
view.arrangedSubviews[i].isHidden = (labelStyleType == .IconOnly)
}
}
}
}
}