onl1ner / TabBar

📱 TabBar – highly customizable tab bar (i.e. TabView) for your SwiftUI application.
MIT License
414 stars 43 forks source link

Content is hidden behind TabBar #15

Open twodayslate opened 1 year ago

twodayslate commented 1 year ago

Simulator Screen Shot - iPhone 14 Pro - 2023-01-23 at 19 53 20

diff --git a/Example/Example/ContentView.swift b/Example/Example/ContentView.swift
index 5b7e8e3..8e591c2 100644
--- a/Example/Example/ContentView.swift
+++ b/Example/Example/ContentView.swift
@@ -61,14 +61,23 @@ struct ContentView: View {
                 Text("Hide/Show TabBar")
             }
             .tabItem(for: Item.first)
-            
-            Text("Second")
-                .tabItem(for: Item.second)
+
+            ScrollView {
+                VStack {
+                    ForEach(0..<100, id: \.self) { i in
+                        Rectangle()
+                            .fill(Color.accentColor)
+                            .overlay(
+                                TextField("\(i)", text: .constant("\(i)"))
+                            )
+                    }
+                }
+            }
+            .tabItem(for: Item.second)

             Text("Third")
                 .tabItem(for: Item.third)
         }
-        .tabBar(style: CustomTabBarStyle())
         .tabItem(style: CustomTabItemStyle())
     }
 }
onl1ner commented 1 year ago

Hello, @twodayslate!

I will look into this issue on my free time

Thanks :)

dkk commented 1 year ago

Since the TabBar can also be floating, by default, content can fall behind it. If you don't want that behaviour, add a bottom padding of the height of your TabBar.

@onl1ner maybe it would be a nice feature to be able to specify it as not floating and automatically modify the content's area.

igavrysh commented 7 months ago

My solution was based on ChildSizeReader I found somewhere on SO + modified TabView + added .edgesIgnoringSafeArea([.bottom, .leading, .trailing]) to support landscape device orientation

struct ChildSizeReader<Content: View>: View {
  @Binding var size: CGSize
  let content: () -> Content
  var body: some View {
    ZStack {
      content()
        .background(
          GeometryReader { proxy in
            Color.clear
              .preference(key: SizePreferenceKey.self, value: proxy.size)
          }
        )
    }
    .onPreferenceChange(SizePreferenceKey.self) { preferences in
      self.size = preferences
    }
  }
}

struct SizePreferenceKey: PreferenceKey {
  typealias Value = CGSize
  static var defaultValue: Value = .zero

  static func reduce(value _: inout Value, nextValue: () -> Value) {
    _ = nextValue()
  }
}

public struct TabBar<TabItem: Tabbable, Content: View>: View {
  ...
  @State var barSize: CGSize = .zero
  public var body: some View {
    return ZStack {
      self.content
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .environmentObject(self.selectedItem).edgesIgnoringSafeArea(.bottom)
        .padding(.bottom, barSize.height)
        .edgesIgnoringSafeArea(.bottom)

      GeometryReader { geometry in
        VStack {
          Spacer()
          ChildSizeReader(size: $barSize) {
            self.tabBarStyle.tabBar(with: geometry) {
              .init(self.tabItems)
            }
          }
        }
        .edgesIgnoringSafeArea([.bottom, .leading, .trailing])
        .visibility(self.visibility)
      }
    }
    .onPreferenceChange(TabBarPreferenceKey.self) { value in
      self.items = value
    }
  }
}
MartinSandeCosta commented 4 months ago

'safeAreaInset(edge:alignment:spacing:content:)' should work but it is only available in > iOS 15.0

kenzo-ai commented 3 months ago

My solution was based on ChildSizeReader I found somewhere on SO + modified TabView + added .edgesIgnoringSafeArea([.bottom, .leading, .trailing]) to support landscape device orientation

struct ChildSizeReader<Content: View>: View {
  @Binding var size: CGSize
  let content: () -> Content
  var body: some View {
    ZStack {
      content()
        .background(
          GeometryReader { proxy in
            Color.clear
              .preference(key: SizePreferenceKey.self, value: proxy.size)
          }
        )
    }
    .onPreferenceChange(SizePreferenceKey.self) { preferences in
      self.size = preferences
    }
  }
}

struct SizePreferenceKey: PreferenceKey {
  typealias Value = CGSize
  static var defaultValue: Value = .zero

  static func reduce(value _: inout Value, nextValue: () -> Value) {
    _ = nextValue()
  }
}

public struct TabBar<TabItem: Tabbable, Content: View>: View {
  ...
  @State var barSize: CGSize = .zero
  public var body: some View {
    return ZStack {
      self.content
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .environmentObject(self.selectedItem).edgesIgnoringSafeArea(.bottom)
        .padding(.bottom, barSize.height)
        .edgesIgnoringSafeArea(.bottom)

      GeometryReader { geometry in
        VStack {
          Spacer()
          ChildSizeReader(size: $barSize) {
            self.tabBarStyle.tabBar(with: geometry) {
              .init(self.tabItems)
            }
          }
        }
        .edgesIgnoringSafeArea([.bottom, .leading, .trailing])
        .visibility(self.visibility)
      }
    }
    .onPreferenceChange(TabBarPreferenceKey.self) { value in
      self.items = value
    }
  }
}

Saved my life. 👍🏻