简体   繁体   中英

how to make a bottom bar which has absolute position with SwiftUI

Hi I'm novice in SwiftUI and have a problem.

I want to make a bottom bar (reusable module) to use in multiple Views.

But its position is different in every single views because of its sibling views

These are what I tried:

  1. GeometryReader But Each View's geometry is different.
  2. overlay & position(x:y:) This also doesn't work
  3. ZStack

My questions are

  1. How can I make fixed position View? (like position: absolute in css)
  2. What is the normal solution for this problem?
  3. Is there any helpful references for SwiftUI?

I want use this Module as Bottom Button Bar

struct BaseBottomButton: View {
    let screen = UIScreen.main.bounds
    
    var body: some View {
        Button(action: {
            print("hello")
        }) {
            Text("Hello")
        }
        .frame(width: self.screen.width ,height: 40)
        .background(Color.red)
    }
}

In this view, it works

struct ContentView: View {
    var body: some View {
        GeometryReader { proxy in
            VStack {
                VStack {
                    Text("What")
                        .frame(width: 400, height: 50)
                        .background(Color.green)
                }
                
                Spacer()
                
                Group {
                    VStack {
                        Text("Some Text")
                        Text("")
                        .frame(width: 200, height: 200)
                            .background(Color.yellow)
                    }
                }
                
                Spacer()
                
                BaseBottomButton()
            }
        }
    }
}

But in this complex view, it doesn't work

struct NewView: View {
    var body: some View {
        GeometryReader { geometry in
            ScrollView(showsIndicators: false) {
                VStack(spacing: 0) {
                    Text("hello")
                        .frame(width: 200, height: 200)
                        .background(Color.blue)
                    ZStack(alignment: .leading) {
                        VStack {
                            Spacer()
                                .frame(height: 24)
                            
                        }
                        .padding(.leading, 20)
                        .padding(.bottom, 138)
                        
                        Text("some box")
                        .frame(width: 200, height: 100)
                        .background(Color.yellow)
                        
                    }
                    .frame(minWidth: 0, maxWidth: .infinity)
                    .background(Color.gray)
                    
                    Spacer(minLength: 40)
                }
                
                BaseBottomButton()
            }
        }
    }
}

This is not answer to the question

How can I make fixed position View? (like position : absolute in css )

but you can first use something like this:

VStack(spacing: 0) {
     Spacer()
     Button(action: {
         print("button clicked")
     }) {
         Text("MY BUTTON")
     }
}

This will give you a button appearing at the bottom of the screen. If you want a view to appear on the top side the screen simply place it before the Spacer like this:

VStack(spacing: 0) {
     SomeView()
     Spacer()
     Button(action: {
         print("button clicked")
     }) {
         Text("MY BUTTON")
     }
}

and finally if the View is too large vertically simply place it in a ScrollView (but do not place the button inside it). Thus you will achieve an effect in which the button is always displayed at the bottom and in the front and the view is scrollable behind it.

If you copy and paste the following final code of my simple example you will see this effect and will quickly understand how it works and how to apply it to your scenario:

VStack(spacing: 0) {
    ScrollView(.vertical, showsIndicators: false) {
       Text("some text").font(.system(size: 60)).padding()
       Text("some text").font(.system(size: 60)).padding()
       Text("some text").font(.system(size: 60)).padding()
       Text("some text").font(.system(size: 60)).padding()
       Text("some text").font(.system(size: 60)).padding()
       Text("some text").font(.system(size: 60)).padding()
       Text("some text").font(.system(size: 60)).padding()
       Text("some text").font(.system(size: 60)).padding()
       Text("some text").font(.system(size: 60)).padding()
    }
    Spacer()
    Button(action: {
       print("button clicked")
    }) {
       Text("MY BUTTON")
    }
}

You need explicit view container to manage bottom bar, like

struct BottomBarContainer<Content: View>: View {
    let content: () -> Content

    init(@ViewBuilder _ content: @escaping () -> Content) {
        self.content = content
    }

    var body: some View {
        VStack {
            content()
            Spacer() // << always pushes below bar to bottom
            BaseBottomButton() // or any bar container here
        }
    }
}

so independently of used content bottom bar would be always at bottom.

As a result we can remove BaseBottomButton() from NewView and use it instead in the same way as other SwiftUI container used:

BottomBarContainer {
   NewView()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM