Как создать динамический компонент Swiftui с гибкой сеткойIOS

Программируем под IOS
Ответить
Anonymous
 Как создать динамический компонент Swiftui с гибкой сеткой

Сообщение Anonymous »

Я хочу создать многоразовый компонент Swiftui, который отображает сетку карт. Макет должен быть гибким в зависимости от предоставленных данных. сторона.

Прямо сейчас я сделал это. Но должен быть лучший способ сделать это. struct SettingsCardView: View {
@ObservedObject var viewModel: SettingsCardItemViewModel

var body: some View {
BindableView(viewModel: viewModel) {
makeContent()
}
}

@ViewBuilder
private func makeContent() -> some View {
Button {
viewModel.onClick()
} label: {
VStack(alignment: .leading) {
TextView(viewModel.title)
TextView(viewModel.subtitle)
Spacer()
HStack {
Spacer()

makeIcon()
}
}
.modifier(SettingsCard())
}
}

@ViewBuilder
private func makeIcon() -> some View {
switch viewModel {
case let battery as BatterySettingsCardViewModel:
BatteryIcon(viewModel: battery.batteryIconViewModel)
case let greenLight as GreenStatusSettingsCardViewModel:
DefaultSettingsIcon(viewModel: greenLight.icon)
case let connectionNotification as ConnectionNotificationSettingsCardViewModel:
DefaultSettingsIcon(viewModel: connectionNotification.icon)
default:
EmptyView()
}
}
}

public class SettingsCardItemViewModel: BindableViewModel, Identifiable {
public var title: TextViewModel
public var subtitle: TextViewModel

public init(
title: String,
subtitle: String,
subtitleTextViewModel: TextViewModel? = nil
) {
self.title = .b1(title, color: .uiTextLightPrimary)
self.subtitle = subtitleTextViewModel ?? .b1(subtitle, color: .uiTextLightPrimaryInactive)
}

public func onClick() {
Debugger.fail(desc: "onClick not implemented")
}
}

public class BatterySettingsCardViewModel: SettingsCardItemViewModel {
public let batteryIconViewModel: BatteryIconViewModel

public init() {
self.batteryIconViewModel = BatteryIconViewModel()
super.init(title: "Battery", subtitle: "", subtitleTextViewModel: .h0("92%", color: .uiTextLightSecondary))
}
}

public class GreenStatusSettingsCardViewModel: SettingsCardItemViewModel {
public var icon: DefaultSettingsIconViewModel

public init() {
self.icon = DefaultSettingsIconViewModel(icon: .iconArrowLeft(.medium))
super.init(title: "Green status", subtitle: "Inactive")
}

public override func onClick() { }
}

public class ConnectionNotificationSettingsCardViewModel: SettingsCardItemViewModel {
public var icon: DefaultSettingsIconViewModel

public init() {
self.icon = DefaultSettingsIconViewModel(icon: .iconArrowLeft(.medium))
super.init(title: "Connection notifications", subtitle: "Inactive")
}

public override func onClick() { }
}

public class BatteryIconViewModel: BindableViewModel {
public override init() { }
}

public class BaseSettingsMenuSection: Identifiable, ObservableObject {
public var title: TextViewModel?
public var subtitle: TextViewModel?
@Published public var items: [SettingsCardItemViewModel]

public init(title: String? = nil, subtitle: String? = nil, items: [SettingsCardItemViewModel]) {
if let title {
self.title = .h2(title)
}
if let subtitle {
self.subtitle = .b1(subtitle, color: .uiTextLightSecondary)
}
self.items = items
}
}

public class OneColumn: BaseSettingsMenuSection { }

public class TwoColumn: BaseSettingsMenuSection { }

public class CameraSettingsCardViewModel: SettingsCardItemViewModel {
public var icon: DefaultSettingsIconViewModel

public init() {
self.icon = DefaultSettingsIconViewModel(icon: .iconSpeedCam(.medium))

super.init(title: "Cameras", subtitle: "Active")
}
}

public class RoadHazardSettingsCardViewModel: SettingsCardItemViewModel {
public var icon: DefaultSettingsIconViewModel

public init() {
self.icon = DefaultSettingsIconViewModel(icon: .iconRoadHazad(.medium))

super.init(title: "Road Hazard", subtitle: "InActive")
}
}

public class SpeedLimitSettingsCardViewModel: SettingsCardItemViewModel {
public var icon: DefaultSettingsIconViewModel

public init() {
self.icon = DefaultSettingsIconViewModel(icon: .iconSpeedCam(.medium))

super.init(title: "Speed Limit", subtitle: "Active")
}
}

public class NotificationSettingsCardViewModel: SettingsCardItemViewModel {
public var icon: DefaultSettingsIconViewModel

public init() {
self.icon = DefaultSettingsIconViewModel(icon: .iconNotificationOn(.medium))

super.init(title: "Notifications", subtitle: "Active")
}
}

struct SettingsMenuSectionView: View {
@ObservedObject var viewModel: BaseSettingsMenuSection

var body: some View {
VStack(alignment: .leading) {
VStack(alignment: .leading, spacing: 16) {
if let title = viewModel.title {
TextView(title)
}

if let subtitle = viewModel.subtitle {
TextView(subtitle)
}
}

makeItemList()
}
}

@ViewBuilder
private func makeItemList() -> some View {
switch viewModel {
case is OneColumn:
makeOneColumnItemList()
case is TwoColumn:
makeTwoColumnItemList()
default:
EmptyView()
}
}

@ViewBuilder
private func makeOneColumnItemList() -> some View {
VStack(spacing: Constants.Padding.padding8) {
ForEach(viewModel.items) { item in
SettingsCardView(viewModel: item)
}
}
}

@ViewBuilder
private func makeTwoColumnItemList() -> some View {
HStack(spacing: Constants.Padding.padding8) {
ForEach(viewModel.items) { item in
SettingsCardView(viewModel: item)
}
}
}
}

public class BaseSettingsMenuSection: Identifiable, ObservableObject {
public var title: TextViewModel?
public var subtitle: TextViewModel?
@Published public var items: [SettingsCardItemViewModel]

public init(title: String? = nil, subtitle: String? = nil, items: [SettingsCardItemViewModel]) {
if let title {
self.title = .h2(title)
}
if let subtitle {
self.subtitle = .b1(subtitle, color: .uiTextLightSecondary)
}
self.items = items
}
}

public class OneColumn: BaseSettingsMenuSection { }

public class TwoColumn: BaseSettingsMenuSection { }


Подробнее здесь: https://stackoverflow.com/questions/797 ... rid-layout
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»