How to Hide the Home Indicator with Swiftui

How to hide the home indicator with SwiftUI?

iOS 16

you can use the .persistentSystemOverlays and pass in .hidden to hide all non-transient system views that are automatically placed over our UI

Text("Goodbye home indicator, the multitask indicator on iPad, and more.")
.persistentSystemOverlays(.hidden)

How to dynamically hide the status bar and the home indicator in SwiftUI?

I was able to solve the problem with the SwiftUI view not extending beyond the safe area insets for the status bar and the home indicator by completely switching to a storyboard based project template and embedding my views through a custom UIHostingController as described in this solution by Casper Zandbergen.
Before I was re-integrating the hosting controller into the SwiftUI view hierarchy by wrapping it with a UIViewRepresentable instance, which must have caused the complications in handling the safe area.

By managing the whole app through the custom UIHostingController subclass it was even easier to get the hiding of the home indicator working. As much as I love SwiftUI I had to realize that, with its current limitations, UIKit was the better option here.

Final code (optimized version of the solution linked above):

ViewController.swift

import SwiftUI
import UIKit

struct HideUIPreferenceKey: PreferenceKey {
static var defaultValue: Bool = false

static func reduce(value: inout Bool, nextValue: () -> Bool) {
value = nextValue() || value
}
}

extension View {
func userInterfaceHidden(_ value: Bool) -> some View {
preference(key: HideUIPreferenceKey.self, value: value)
}
}

class ViewController: UIHostingController<AnyView> {
init() {
weak var vc: ViewController? = nil
super.init(
rootView: AnyView(
ContentView()
.onPreferenceChange(HideUIPreferenceKey.self) {
vc?.userInterfaceHidden = $0
}
)
)
vc = self
}

@objc required dynamic init?(coder: NSCoder) {
weak var vc: ViewController? = nil
super.init(
coder: coder,
rootView: AnyView(
ContentView()
.onPreferenceChange(HideUIPreferenceKey.self) {
vc?.userInterfaceHidden = $0
}
)
)
vc = self
}

private var userInterfaceHidden = false {
didSet { setNeedsUpdateOfHomeIndicatorAutoHidden() }
}

override var prefersStatusBarHidden: Bool {
userInterfaceHidden
}

override var prefersHomeIndicatorAutoHidden: Bool {
userInterfaceHidden
}
}

Strange home bar appearance in SwiftUI app

That is not an issue, it should be like that, since we have no touch id in new iPhone models, that things play as kind of help in Screen. And when you use edgesIgnoringSafeArea in your code, you get access to under area and back area of that shape for Color works!

That shape is used for Swipe up to go iPhone main screens.

Look at the iPhone 8, it has touch, and look at iPhone 11, No touch ID!


Sample Image

Move Index View above home indicator in Tab View

EDIT: See also @nekno's fantastic additions!


This is possible if you create a custom UIPageControl, manually tag each tab in the TabView, and make sure to keep track of the numberOfPages:

struct PageControlView: UIViewRepresentable {
@Binding var currentPage: Int
@Binding var numberOfPages: Int

func makeUIView(context: Context) -> UIPageControl {
let uiView = UIPageControl()
uiView.backgroundStyle = .prominent
uiView.currentPage = currentPage
uiView.numberOfPages = numberOfPages
return uiView
}

func updateUIView(_ uiView: UIPageControl, context: Context) {
uiView.currentPage = currentPage
uiView.numberOfPages = numberOfPages
}
}

struct ContentView: View {
@State var isSheetUp = false

var body: some View {
Button("Present") {
isSheetUp.toggle()
}
.sheet(isPresented: $isSheetUp) {
Sheet()
}
}

struct Sheet: View {
@State var currentPage = 0
@State var numberOfPages = 3

var body: some View {
NavigationView {
ZStack {
TabView(selection: $currentPage) {
Page().tag(0)
Page().tag(1)
Page().tag(2)
}
// Comment this to switch layout issue
.ignoresSafeArea(edges: .bottom)
.tabViewStyle(.page(indexDisplayMode: .never))
.indexViewStyle(.page(backgroundDisplayMode: .always))
.navigationTitle("Title")
.navigationBarTitleDisplayMode(.inline)

VStack {
Spacer()
PageControlView(currentPage: $currentPage, numberOfPages: $numberOfPages)
}
}
}
}
}

struct Page: View {
var body: some View {
ScrollView {
VStack {
Rectangle()
.foregroundColor(.teal)
.padding()
.frame(minHeight: 10000)
}
}.background(Color.brown)
}
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}


Related Topics



Leave a reply



Submit