Position view bottom without using a spacer

回眸只為那壹抹淺笑 提交于 2019-12-24 00:42:59

问题


How can I position a View at the bottom without using a spacer. I know I can achieve it placing a spacer and my view in inside a VStack but I don't want to use a spacer because I don't want my view to take up all the vertical space. With UIKit I would position it at safe area bottom guide.


回答1:


Experimenting with different approaches I finally end up with creating own custom container, which, having some known limitation, fulfils my needs completely. Hope it would be helpful for someone else.

Demo:

Pros: ContentView & PinnedView are absolutely independent in layout on each other, automatically handle device orientation, and actually limitless in internal content

Cons: Due to used GeometryReader using .infinity at top-level content or pinned view result in crash due to "chicken-egg" problem.

Container code:

struct ContainerWithPinnedBottomView<Content, Pinned>: View 
                                     where Content: View, Pinned: View {

    private var content: () -> Content
    private var bottomView: () -> Pinned

    @inlinable public init(@ViewBuilder pinnedView: @escaping () -> Pinned,
                            @ViewBuilder content: @escaping () -> Content) {
        self.content = content
        self.bottomView = pinnedView
    }

    var body: some View {
        ZStack(alignment: .bottom) {
            Rectangle().fill(Color.clear) // !! Extends ZStack to full screen
            GeometryReader { _ in
                ZStack {
                    self.content()
                }
            }
            self.bottomView()
                .alignmentGuide(.bottom) { $0[.bottom] }
        }
    }

}

Usage example (of demo screenshot)

struct TestBottomView: View {
    var body: some View {
        ContainerWithPinnedBottomView(pinnedView: {
            HStack {
                Spacer()
                Text("Always Pinned to Bottom")
                    .padding()
    //                .frame(width: .infinity) // !! LIMITATION - don't use, cycling crash
                Spacer()
            }
            .background(Color.blue)
        }) {
            NavigationView {
                List (0 ..< 100, id: \.self) { i in
                    NavigationLink(destination: Text("Other")) {
                        Text("Row \(i)")
                    }
                }
                .navigationBarTitle("TitleBar")
            }
        }
    }
}

struct TestBottomView_Previews: PreviewProvider {
    static var previews: some View {
        TestBottomView()
    }
}



回答2:


I think the simplest way is to add a frame for the container view.

Group{ // container View
    Text("iner label")
}.frame(maxHeight: .infinity, alignment: .bottom)

If you don't add frame, the default frame will wrap the inner view and has the same size as the inner View. If you add a frame, it will create a space belonging to the outer view, in the UIView concept, it's a superView. Then you will see what you will need to handle.




回答3:


Position property will help you try this way

Group{ // container View
     Text("iner label")
}.position(x: UIScreen.main.bounds.width/2, y: UIScreen.main.bounds.height-50)


来源:https://stackoverflow.com/questions/59165138/position-view-bottom-without-using-a-spacer

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!