SwiftUI: Как выровнять вид с подпредставлением HStack? - PullRequest
2 голосов
/ 19 января 2020

Я хочу выровнять круг по центру TileView "1" в левом верхнем углу. Есть ли другие подобные ограничения центра UIView?

enter image description here

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))

        }
    }
}

Ответы [ 2 ]

1 голос
/ 14 февраля 2020

Использование GeometryReader и предпочтение

portrait mode

landscape mode

GeometryReader - давайте получим geometryProxy вида (в соответствии с родительским представлением / пространством, предоставленным родителем)

Примечание: - дочерний вид остается на своих own (родитель не может заставить их положение или размер)

.preference (key:, value:) - этот модификатор позволяет нам получить некоторые значения (geometryProxy) из представления. так что мы можем получить доступ к прокси геометрии дочернего элемента также из родительского.

комментарий ниже для любого вопроса по этим темам.

вот код, (плюс точка - вы может легко анимировать положение вашего круга (добавив модификатор .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()
    }   
}

Объяснение кода ->

модель данных, которую я хочу получить из дочернего представления

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 () - getCalled, когда SwiftUI хочет дать значения (мы можем использовать модификатор .preference() во многих представлениях с одним и тем же ключом)

мы добавляем модификатор .preference(), который мы хотим получить значения

1 голос
/ 19 января 2020

Здесь возможен подход с использованием пользовательских направляющих

SwiftUI center dependent shapes

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) { $0[VerticalAlignment.center] }
                        .alignmentGuide(.hCenterred) { $0[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) { $0[VerticalAlignment.center] }
                .alignmentGuide(.hCenterred) { $0[HorizontalAlignment.center] }

        }
    }
}
...