diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 3251ff8..c0dec35 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - ExyteGrid (1.2.1.beta) + - ExyteGrid (1.3.1.beta) DEPENDENCIES: - ExyteGrid (from `../`) @@ -9,7 +9,7 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - ExyteGrid: 07bfd36208451abf592c6d4500b2863d3623898e + ExyteGrid: 616f4790a25339ed8664db1c1d9e38a1e49c6a11 PODFILE CHECKSUM: 76084cf935f120b28a0e2dcc60936504183d3608 diff --git a/ExyteGrid.podspec b/ExyteGrid.podspec index 12644ff..afb0db5 100644 --- a/ExyteGrid.podspec +++ b/ExyteGrid.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'ExyteGrid' - s.version = '1.2.1.beta' + s.version = '1.3.1.beta' s.summary = 'The most powerful Grid container missed in SwiftUI' s.homepage = 'https://github.com/exyte/Grid.git' diff --git a/Grid.xcodeproj/project.pbxproj b/Grid.xcodeproj/project.pbxproj index 69e6628..8253ecc 100644 --- a/Grid.xcodeproj/project.pbxproj +++ b/Grid.xcodeproj/project.pbxproj @@ -76,6 +76,8 @@ 363AD4B2253045A200C27F2F /* GridCacheMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3633AB8D24E678290033A172 /* GridCacheMode.swift */; }; 363AD4B3253045A200C27F2F /* GridGroup+Init.swift in Sources */ = {isa = PBXBuildFile; fileRef = 365DFA302523543C0019BB80 /* GridGroup+Init.swift */; }; 363AD4B4253045A200C27F2F /* GridContentMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 361723742475221000866539 /* GridContentMode.swift */; }; + 36435B1C25887A590011E2AC /* GridAlignment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36435B1B25887A590011E2AC /* GridAlignment.swift */; }; + 36435B1D25887A590011E2AC /* GridAlignment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36435B1B25887A590011E2AC /* GridAlignment.swift */; }; 364FFB2D24C1C1680054D275 /* GridPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 364FFB2C24C1C1680054D275 /* GridPreference.swift */; }; 365DFA362523543C0019BB80 /* GridBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 365DFA2E2523543C0019BB80 /* GridBuilder.swift */; }; 365DFA372523543C0019BB80 /* GridGroup+Inits_Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 365DFA2F2523543C0019BB80 /* GridGroup+Inits_Data.swift */; }; @@ -151,6 +153,7 @@ 363AD4732530455F00C27F2F /* GridMac.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GridMac.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 363AD4752530455F00C27F2F /* GridMac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GridMac.h; sourceTree = ""; }; 363AD4762530455F00C27F2F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 36435B1B25887A590011E2AC /* GridAlignment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridAlignment.swift; sourceTree = ""; }; 364FFB2C24C1C1680054D275 /* GridPreference.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GridPreference.swift; sourceTree = ""; }; 365DFA2E2523543C0019BB80 /* GridBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GridBuilder.swift; sourceTree = ""; }; 365DFA2F2523543C0019BB80 /* GridGroup+Inits_Data.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GridGroup+Inits_Data.swift"; sourceTree = ""; }; @@ -306,6 +309,7 @@ 3617237D2475221000866539 /* ArrangedItem.swift */, 3617237E2475221000866539 /* LayoutArrangement.swift */, 3617237F2475221000866539 /* PositionedItem.swift */, + 36435B1B25887A590011E2AC /* GridAlignment.swift */, ); path = Models; sourceTree = ""; @@ -581,6 +585,7 @@ 361723832475221000866539 /* View+GridPreferences.swift in Sources */, 361723952475221000866539 /* GridContentMode.swift in Sources */, 3617238D2475221000866539 /* Constants.swift in Sources */, + 36435B1C25887A590011E2AC /* GridAlignment.swift in Sources */, 365DFA362523543C0019BB80 /* GridBuilder.swift in Sources */, 3617239A2475221000866539 /* GridTrack.swift in Sources */, 365DFA3B2523543C0019BB80 /* GridElement+asGridElements.swift in Sources */, @@ -630,6 +635,7 @@ 363AD494253045A200C27F2F /* GridElement.swift in Sources */, 363AD498253045A200C27F2F /* LayoutArrangement+description.swift in Sources */, 363AD49A253045A200C27F2F /* GridSpacing.swift in Sources */, + 36435B1D25887A590011E2AC /* GridAlignment.swift in Sources */, 363AD49F253045A200C27F2F /* GridFlow.swift in Sources */, 363AD4A5253045A200C27F2F /* GridStart.swift in Sources */, 363AD4A2253045A200C27F2F /* GridGroup+Inits_Data.swift in Sources */, diff --git a/Sources/Configuration/Constants.swift b/Sources/Configuration/Constants.swift index 18f9627..392c366 100644 --- a/Sources/Configuration/Constants.swift +++ b/Sources/Configuration/Constants.swift @@ -19,5 +19,5 @@ public struct Constants { public static let defaultFlow: GridFlow = .rows public static let defaultPacking: GridPacking = .sparse public static let defaultCacheMode: GridCacheMode = .inMemoryCache - public static let defaultItemsAlignment: Alignment = .center + public static let defaultItemsAlignment: GridAlignment = .center } diff --git a/Sources/Models/GridAlignment.swift b/Sources/Models/GridAlignment.swift new file mode 100644 index 0000000..cf7bfe3 --- /dev/null +++ b/Sources/Models/GridAlignment.swift @@ -0,0 +1,11 @@ +// +// GridItemAlignment.swift +// Grid +// +// Created by Denis Obukhov on 15.12.2020. +// Copyright © 2020 Exyte. All rights reserved. +// + +import SwiftUI + +public typealias GridAlignment = Alignment diff --git a/Sources/Models/Preferences/GridPreference.swift b/Sources/Models/Preferences/GridPreference.swift index 6afb4a5..533c266 100644 --- a/Sources/Models/Preferences/GridPreference.swift +++ b/Sources/Models/Preferences/GridPreference.swift @@ -12,6 +12,7 @@ struct GridPreference: Equatable { var positionedItem: PositionedItem? var span: GridSpan? var start: GridStart? + var alignment: GridAlignment? static let empty = ItemInfo() } @@ -44,9 +45,11 @@ extension Array where Element == GridPreference.ItemInfo { let positionedItem = self.compactMap(\.positionedItem).first let span = self.compactMap(\.span).first ?? .default let start = self.compactMap(\.start).first ?? .default + let alignment = self.compactMap(\.alignment).first let itemInfo = GridPreference.ItemInfo(positionedItem: positionedItem, span: span, - start: start) + start: start, + alignment: alignment) return [itemInfo] } diff --git a/Sources/View/Grid.swift b/Sources/View/Grid.swift index 476b49e..e81822e 100644 --- a/Sources/View/Grid.swift +++ b/Sources/View/Grid.swift @@ -9,11 +9,12 @@ import SwiftUI public struct Grid: View, LayoutArranging, LayoutPositioning { - @State var positions: PositionedLayout = .empty - @State var isLoaded: Bool = false + @State private var positions: PositionedLayout = .empty + @State private var isLoaded: Bool = false + @State private var alignments: [GridElement: GridAlignment] = [:] #if os(iOS) || os(watchOS) || os(tvOS) - @State var internalLayoutCache = Cache() - @State var internalPositionsCache = Cache() + @State private var internalLayoutCache = Cache() + @State private var internalPositionsCache = Cache() #endif @Environment(\.gridContentMode) private var environmentContentMode @Environment(\.gridFlow) private var environmentFlow @@ -29,7 +30,7 @@ public struct Grid: View, LayoutArranging, LayoutPositioning { var internalPacking: GridPacking? var internalContentMode: GridContentMode? var internalCacheMode: GridCacheMode? - var internalItemsAlignment: Alignment? + var internalItemsAlignment: GridAlignment? private var flow: GridFlow { self.internalFlow ?? self.environmentFlow ?? Constants.defaultFlow @@ -47,7 +48,7 @@ public struct Grid: View, LayoutArranging, LayoutPositioning { self.internalCacheMode ?? self.environmentCacheMode ?? Constants.defaultCacheMode } - private var itemsAlignment: Alignment { + private var itemsAlignment: GridAlignment { self.internalItemsAlignment ?? self.environmentItemsAlignment ?? Constants.defaultItemsAlignment } @@ -87,7 +88,7 @@ public struct Grid: View, LayoutArranging, LayoutPositioning { .frame(flow: self.flow, size: self.positions[item]?.bounds.size, contentMode: self.contentMode, - alignment: itemsAlignment) + alignment: self.alignments[item] ?? itemsAlignment) .alignmentGuide(.leading, computeValue: { _ in self.leadingGuide(item: item) }) .alignmentGuide(.top, computeValue: { _ in self.topGuide(item: item) }) .backgroundPreferenceValue(GridBackgroundPreferenceKey.self) { preference in @@ -109,6 +110,7 @@ public struct Grid: View, LayoutArranging, LayoutPositioning { .onPreferenceChange(GridPreferenceKey.self) { preference in self.calculateLayout(preference: preference, boundingSize: mainGeometry.size) + self.saveAlignmentsFrom(preference: preference) } } .id(self.isLoaded) @@ -158,7 +160,16 @@ public struct Grid: View, LayoutArranging, LayoutPositioning { self.positions = positions self.isLoaded = true } - + + private func saveAlignmentsFrom(preference: GridPreference) { + var alignments: [GridElement: GridAlignment] = [:] + preference.itemsInfo.forEach { + guard let gridElement = $0.positionedItem?.gridElement else { return } + alignments[gridElement] = $0.alignment + } + self.alignments = alignments + } + private func corrected(size: CGSize) -> CGSize { return CGSize(width: size.width - self.spacing.horizontal, height: size.height - self.spacing.vertical) diff --git a/Sources/View/Inits/Grid+Init.swift b/Sources/View/Inits/Grid+Init.swift index 183fc6a..84605d9 100644 --- a/Sources/View/Inits/Grid+Init.swift +++ b/Sources/View/Inits/Grid+Init.swift @@ -11,7 +11,7 @@ import SwiftUI extension Grid { - public init(tracks: [GridTrack] = 1, contentMode: GridContentMode? = nil, flow: GridFlow? = nil, packing: GridPacking? = nil, spacing: GridSpacing = Constants.defaultSpacing, itemsAlignment: Alignment? = nil, cache: GridCacheMode? = nil, @GridBuilder content: () -> ConstructionItem) { + public init(tracks: [GridTrack] = 1, contentMode: GridContentMode? = nil, flow: GridFlow? = nil, packing: GridPacking? = nil, spacing: GridSpacing = Constants.defaultSpacing, itemsAlignment: GridAlignment? = nil, cache: GridCacheMode? = nil, @GridBuilder content: () -> ConstructionItem) { self.trackSizes = tracks self.spacing = spacing self.internalContentMode = contentMode diff --git a/Sources/View/Inits/Grid+Inits_Data.swift b/Sources/View/Inits/Grid+Inits_Data.swift index 130ba3d..02c1668 100644 --- a/Sources/View/Inits/Grid+Inits_Data.swift +++ b/Sources/View/Inits/Grid+Inits_Data.swift @@ -11,7 +11,7 @@ import SwiftUI extension Grid { - public init(_ data: Data, id: KeyPath, tracks: [GridTrack] = 1, contentMode: GridContentMode? = nil, flow: GridFlow? = nil, packing: GridPacking? = nil, spacing: GridSpacing = Constants.defaultSpacing, itemsAlignment: Alignment? = nil, cache: GridCacheMode? = nil, @GridBuilder item: @escaping (Data.Element) -> ConstructionItem) where Data: RandomAccessCollection, ID: Hashable { + public init(_ data: Data, id: KeyPath, tracks: [GridTrack] = 1, contentMode: GridContentMode? = nil, flow: GridFlow? = nil, packing: GridPacking? = nil, spacing: GridSpacing = Constants.defaultSpacing, itemsAlignment: GridAlignment? = nil, cache: GridCacheMode? = nil, @GridBuilder item: @escaping (Data.Element) -> ConstructionItem) where Data: RandomAccessCollection, ID: Hashable { var index = 0 self.items = data.flatMap { item($0).contentViews.asGridElements(index: &index, @@ -26,7 +26,7 @@ extension Grid { self.internalItemsAlignment = itemsAlignment } - public init(_ data: Range, tracks: [GridTrack] = 1, contentMode: GridContentMode? = nil, flow: GridFlow? = nil, packing: GridPacking? = nil, spacing: GridSpacing = Constants.defaultSpacing, itemsAlignment: Alignment? = nil, cache: GridCacheMode? = nil, @GridBuilder item: @escaping (Int) -> ConstructionItem) { + public init(_ data: Range, tracks: [GridTrack] = 1, contentMode: GridContentMode? = nil, flow: GridFlow? = nil, packing: GridPacking? = nil, spacing: GridSpacing = Constants.defaultSpacing, itemsAlignment: GridAlignment? = nil, cache: GridCacheMode? = nil, @GridBuilder item: @escaping (Int) -> ConstructionItem) { var index = 0 self.items = data.flatMap { item($0).contentViews.asGridElements(index: &index) @@ -40,7 +40,7 @@ extension Grid { self.internalItemsAlignment = itemsAlignment } - public init(_ data: Data, tracks: [GridTrack] = 1, contentMode: GridContentMode? = nil, flow: GridFlow? = nil, packing: GridPacking? = nil, spacing: GridSpacing = Constants.defaultSpacing, itemsAlignment: Alignment? = nil, cache: GridCacheMode? = nil, @GridBuilder item: @escaping (Data.Element) -> ConstructionItem) where Data: RandomAccessCollection, Data.Element: Identifiable { + public init(_ data: Data, tracks: [GridTrack] = 1, contentMode: GridContentMode? = nil, flow: GridFlow? = nil, packing: GridPacking? = nil, spacing: GridSpacing = Constants.defaultSpacing, itemsAlignment: GridAlignment? = nil, cache: GridCacheMode? = nil, @GridBuilder item: @escaping (Data.Element) -> ConstructionItem) where Data: RandomAccessCollection, Data.Element: Identifiable { var index = 0 self.items = data.flatMap { item($0).contentViews.asGridElements(index: &index, diff --git a/Sources/View/View+Environment.swift b/Sources/View/View+Environment.swift index 21fda5a..15d6690 100644 --- a/Sources/View/View+Environment.swift +++ b/Sources/View/View+Environment.swift @@ -29,7 +29,7 @@ extension View { return self.environment(\.gridCache, cache) } - public func gridItemsAlignment(_ alignment: Alignment?) -> some View { + public func gridItemsAlignment(_ alignment: GridAlignment?) -> some View { return self.environment(\.gridItemsAlignemnt, alignment) } } @@ -60,7 +60,7 @@ extension EnvironmentValues { set { self[EnvironmentKeys.GridCache.self] = newValue } } - var gridItemsAlignemnt: Alignment? { + var gridItemsAlignemnt: GridAlignment? { get { self[EnvironmentKeys.GridItemsAlignment.self] } set { self[EnvironmentKeys.GridItemsAlignment.self] = newValue } } @@ -88,6 +88,6 @@ private struct EnvironmentKeys { } struct GridItemsAlignment: EnvironmentKey { - static let defaultValue: Alignment? = .center + static let defaultValue: GridAlignment? = .center } } diff --git a/Sources/View/View+GridPreferences.swift b/Sources/View/View+GridPreferences.swift index b3b614a..ccfed28 100644 --- a/Sources/View/View+GridPreferences.swift +++ b/Sources/View/View+GridPreferences.swift @@ -42,6 +42,14 @@ extension View { preferences.itemsInfo = [info] }) } + + public func gridAlignment(_ alignment: GridAlignment) -> some View { + transformPreference(GridPreferenceKey.self, { preferences in + var info = preferences.itemsInfo.first ?? .empty + info.alignment = alignment + preferences.itemsInfo = [info] + }) + } public func gridCellOverlay( @ViewBuilder content: @escaping (CGSize?) -> Content