SwiftUI:如何将视图与 HStack 的子视图对齐?
SwiftUI: How to align view to HStack's subview?
我想将圆圈与左上角的 TileView“1”中心对齐。还有类似UIView的center constraint吗?
struct BoardView: View {
var body: some View {
ZStack {
VStack {
HStack {
TileView(number: 1)
TileView(number: 2)
}
HStack {
TileView(number: 3)
TileView(number: 4)
}
}
Circle()
.frame(width: 30, height: 30)
.foregroundColor(Color.red.opacity(0.8))
}
}
}
这是使用自定义对齐指南的可能方法
extension VerticalAlignment {
private enum VCenterAlignment: AlignmentID {
static func defaultValue(in dimensions: ViewDimensions) -> CGFloat {
return dimensions[VerticalAlignment.center]
}
}
static let vCenterred = VerticalAlignment(VCenterAlignment.self)
}
extension HorizontalAlignment {
private enum HCenterAlignment: AlignmentID {
static func defaultValue(in dimensions: ViewDimensions) -> CGFloat {
return dimensions[HorizontalAlignment.center]
}
}
static let hCenterred = HorizontalAlignment(HCenterAlignment.self)
}
struct BoardView: View {
var body: some View {
ZStack(alignment: Alignment(horizontal: .hCenterred, vertical: .vCenterred)) {
VStack {
HStack {
TileView(number: 1)
.alignmentGuide(.vCenterred) { [=10=][VerticalAlignment.center] }
.alignmentGuide(.hCenterred) { [=10=][HorizontalAlignment.center] }
TileView(number: 2)
}
HStack {
TileView(number: 3)
TileView(number: 4)
}
}
Circle()
.frame(width: 30, height: 30)
.foregroundColor(Color.red.opacity(0.8))
.alignmentGuide(.vCenterred) { [=10=][VerticalAlignment.center] }
.alignmentGuide(.hCenterred) { [=10=][HorizontalAlignment.center] }
}
}
}
使用GeometryReader和首选项
GeometryReader - 让我们获取视图的 geometryProxy(根据 parent 视图/space 由 parent 提供)
注意:- child 视图保留在它们自己的位置(parent 不能强制它们的位置或大小)
.preference(key:,value:) - 这个修饰符让我们从视图中获取一些值(geometryProxy)。这样我们也可以从 parent 访问 child 的几何代理。
如有任何关于这些主题的问题,请在下方发表评论。
这是代码,
(加点 - 你可以轻松地为你的圈子的位置设置动画。(通过添加 .animation() 修饰符。例如 - 如果你希望你的圈子在用户触摸标题时移动)
完整代码
import SwiftUI
struct ContentView: View {
@State var centerCoordinateOfRectangele: MyPreferenceData = MyPreferenceData(x: 0, y: 0)
var body: some View {
ZStack {
VStack {
HStack {
GeometryReader { (geometry) in
TileView(number: 1)
.preference(key: MyPreferenceKey.self, value: MyPreferenceData(x: geometry.frame(in: .named("spaceIWantToMoveMyView")).midX, y: geometry.frame(in: .named("spaceIWantToMoveMyView")).midY))
}
TileView(number: 2)
}.onPreferenceChange(MyPreferenceKey.self) { (value) in
self.centerCoordinateOfRectangele = value
}
HStack {
TileView(number: 3)
TileView(number: 4)
}
}
Circle()
.frame(width: 30, height: 30)
.foregroundColor(Color.red.opacity(0.8))
.position(x: centerCoordinateOfRectangele.x, y: centerCoordinateOfRectangele.y)
}
.coordinateSpace(name: "spaceIWantToMoveMyView") //to get values relative to this layout
// watch where i have use this name
}
}
struct TileView: View{
let number: Int
var body: some View{
GeometryReader { (geometry) in
RoundedRectangle(cornerRadius: 30)
}
}
}
struct MyPreferenceData:Equatable {
let x: CGFloat
let y: CGFloat
}
struct MyPreferenceKey: PreferenceKey {
typealias Value = MyPreferenceData
static var defaultValue: MyPreferenceData = MyPreferenceData(x: 0, y: 0)
static func reduce(value: inout MyPreferenceData, nextValue: () -> MyPreferenceData) {
value = nextValue()
}
}
代码解释 ->
我想从 child 视图中获取的数据模型
struct MyPreferenceData:Equatable {
let x: CGFloat
let y: CGFloat
}
关键
struct MyPreferenceKey: PreferenceKey {
typealias Value = MyPreferenceData
static var defaultValue: MyPreferenceData = MyPreferenceData(x: 0, y: 0)
static func reduce(value: inout MyPreferenceData, nextValue: () -> MyPreferenceData) {
value = nextValue()
}
}
defaultValue - SwiftUI 在没有明确设置值时使用它
reduce() - 当 SwiftUI 想要提供值时调用(我们可以在具有相同键的许多视图上使用 .preference()
修饰符)
我们添加我们想要获取值的 .preference()
修饰符
我想将圆圈与左上角的 TileView“1”中心对齐。还有类似UIView的center constraint吗?
struct BoardView: View {
var body: some View {
ZStack {
VStack {
HStack {
TileView(number: 1)
TileView(number: 2)
}
HStack {
TileView(number: 3)
TileView(number: 4)
}
}
Circle()
.frame(width: 30, height: 30)
.foregroundColor(Color.red.opacity(0.8))
}
}
}
这是使用自定义对齐指南的可能方法
extension VerticalAlignment {
private enum VCenterAlignment: AlignmentID {
static func defaultValue(in dimensions: ViewDimensions) -> CGFloat {
return dimensions[VerticalAlignment.center]
}
}
static let vCenterred = VerticalAlignment(VCenterAlignment.self)
}
extension HorizontalAlignment {
private enum HCenterAlignment: AlignmentID {
static func defaultValue(in dimensions: ViewDimensions) -> CGFloat {
return dimensions[HorizontalAlignment.center]
}
}
static let hCenterred = HorizontalAlignment(HCenterAlignment.self)
}
struct BoardView: View {
var body: some View {
ZStack(alignment: Alignment(horizontal: .hCenterred, vertical: .vCenterred)) {
VStack {
HStack {
TileView(number: 1)
.alignmentGuide(.vCenterred) { [=10=][VerticalAlignment.center] }
.alignmentGuide(.hCenterred) { [=10=][HorizontalAlignment.center] }
TileView(number: 2)
}
HStack {
TileView(number: 3)
TileView(number: 4)
}
}
Circle()
.frame(width: 30, height: 30)
.foregroundColor(Color.red.opacity(0.8))
.alignmentGuide(.vCenterred) { [=10=][VerticalAlignment.center] }
.alignmentGuide(.hCenterred) { [=10=][HorizontalAlignment.center] }
}
}
}
使用GeometryReader和首选项
GeometryReader - 让我们获取视图的 geometryProxy(根据 parent 视图/space 由 parent 提供)
注意:- child 视图保留在它们自己的位置(parent 不能强制它们的位置或大小)
.preference(key:,value:) - 这个修饰符让我们从视图中获取一些值(geometryProxy)。这样我们也可以从 parent 访问 child 的几何代理。
如有任何关于这些主题的问题,请在下方发表评论。
这是代码, (加点 - 你可以轻松地为你的圈子的位置设置动画。(通过添加 .animation() 修饰符。例如 - 如果你希望你的圈子在用户触摸标题时移动)
完整代码
import SwiftUI
struct ContentView: View {
@State var centerCoordinateOfRectangele: MyPreferenceData = MyPreferenceData(x: 0, y: 0)
var body: some View {
ZStack {
VStack {
HStack {
GeometryReader { (geometry) in
TileView(number: 1)
.preference(key: MyPreferenceKey.self, value: MyPreferenceData(x: geometry.frame(in: .named("spaceIWantToMoveMyView")).midX, y: geometry.frame(in: .named("spaceIWantToMoveMyView")).midY))
}
TileView(number: 2)
}.onPreferenceChange(MyPreferenceKey.self) { (value) in
self.centerCoordinateOfRectangele = value
}
HStack {
TileView(number: 3)
TileView(number: 4)
}
}
Circle()
.frame(width: 30, height: 30)
.foregroundColor(Color.red.opacity(0.8))
.position(x: centerCoordinateOfRectangele.x, y: centerCoordinateOfRectangele.y)
}
.coordinateSpace(name: "spaceIWantToMoveMyView") //to get values relative to this layout
// watch where i have use this name
}
}
struct TileView: View{
let number: Int
var body: some View{
GeometryReader { (geometry) in
RoundedRectangle(cornerRadius: 30)
}
}
}
struct MyPreferenceData:Equatable {
let x: CGFloat
let y: CGFloat
}
struct MyPreferenceKey: PreferenceKey {
typealias Value = MyPreferenceData
static var defaultValue: MyPreferenceData = MyPreferenceData(x: 0, y: 0)
static func reduce(value: inout MyPreferenceData, nextValue: () -> MyPreferenceData) {
value = nextValue()
}
}
代码解释 ->
我想从 child 视图中获取的数据模型
struct MyPreferenceData:Equatable {
let x: CGFloat
let y: CGFloat
}
关键
struct MyPreferenceKey: PreferenceKey {
typealias Value = MyPreferenceData
static var defaultValue: MyPreferenceData = MyPreferenceData(x: 0, y: 0)
static func reduce(value: inout MyPreferenceData, nextValue: () -> MyPreferenceData) {
value = nextValue()
}
}
defaultValue - SwiftUI 在没有明确设置值时使用它
reduce() - 当 SwiftUI 想要提供值时调用(我们可以在具有相同键的许多视图上使用 .preference()
修饰符)
我们添加我们想要获取值的 .preference()
修饰符