SwiftUI sheet modal background not working with edgesIgnoreSafeArea(.all) - WHY? - background

I'm running iOS 13 simulator with a SwiftUI sheet modal - trying to paint the sheet background and ignore safe areas - but there's still white sheet showing. Any ideas on how to do this properly?
var body: some View {
VStack(alignment: .center, spacing: 0) {
... redacted ...
} // VStack
.background(Color.gray.edgesIgnoringSafeArea(.all))
iPhone Simulator with sheet modal
See the image (attached)
Any ideas what I'm doing wrong?

Expand top container (VStack in your case) to full sheet area, like
VStack {
// ... your content
}
.frame(maxWidth: .infinity, maxHeight: .infinity) // << here !!
.background(Color.gray.edgesIgnoringSafeArea(.all))

Best way to paint the background is using a ZStack:
var body: some View {
ZStack {
// replace with the color you want
Color.green
.edgesIgnoringSafeArea(.all)
VStack {
// put view's Content here
}
}
}

Related

NavigationStack, NavigationLink and onLongPressGesture together

I have a view inside a NavigationStack (iOS16+) that shows a horizontal list of items (game). When tapping on it the app will proceed to the next screen in my app. But I also want to be able to show a sheet to be able to edit the details of game. I got both working, just not together. The edit sheet should be shown after a long press, but as soon as I add the onLongPress gesture, I no longer can scroll through my list, nor does the NavigationLink work. How to get this working?
.navigationDestination(for: Game.self) { game in
TestView(game: game)
}
(...)
// Show and edit game details
func gameDetailsView(for game: Game) {
gamesViewModel.selectedGame = game
showingGameDetailsView.toggle()
}
(...)
#ViewBuilder var horizontalList: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 20) {
ForEach(gamesViewModel.filteredGames(with: filterText)) { game in
NavigationLink(value: game) {
gameCard(game)
.listRowBackground(Color.clear)
.frame(width: uiProperties.isiPad ? getScreenRectangle().width / 3 : getScreenRectangle().width - 30)
.frame(height: uiProperties.isiPad ? getScreenRectangle().height / 1.5 : getScreenRectangle().height / 1.6)
.onLongPressGesture(minimumDuration: 0.3) {
gameDetailsView(for: game)
}
// .simultaneousGesture(LongPressGesture(minimumDuration: 0.3).onEnded { hasEnded in
// if hasEnded { gameDetailsView(for: game) }
// })
}
}
}
.padding(.horizontal)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
Another solution would be to have two destinations for game, but I don't know if that's possible and how to do that ...

In SwiftUI, supporting iOS 14 and above, how do I get a ScrollView child view to ignore the safe area

I have a VStack that contains a Rectangle. The Rectangle has an edgesIgnoresSafeArea(.top) view modifier on it to extend it through the top safe area.
import SwiftUI
struct ScrollViewSafeArea: View {
var body: some View {
ScrollView {
VStack {
Rectangle()
.fill(Color.orange)
.frame(height: 200)
.edgesIgnoringSafeArea(.top)
Spacer()
}
}
.background(Color.green.ignoresSafeArea())
}
}
Nice!
However, when I embed this inside a ScrollView, the Rectangle no longer extends through the safe area.
import SwiftUI
struct ScrollViewSafeArea: View {
var body: some View {
ScrollView {
VStack {
Rectangle()
.fill(Color.orange)
.frame(height: 200)
.edgesIgnoringSafeArea(.top)
Spacer()
}
}
.background(Color.green.ignoresSafeArea())
}
}
I can add a negative top padding to the Rectangle to extend it through the safe area, but this feels hacky to me.
Does anyone have a better way?
So I figured it out. I feel kind-of stupid actually. I wasn't ignoring the safe areas properly. Here is the code that does what I want it to do.
import SwiftUI
struct ScrollViewSafeArea: View {
var body: some View {
ScrollView {
VStack {
Rectangle()
.fill(Color.orange)
.frame(height: 200)
Spacer()
}
}
.ignoresSafeArea()
// Need to ignoreSafeArea again on the background color so
// the color extends to the horizontal edges in landscape.
.background(Color.green.ignoresSafeArea())
}
}
struct ScrollViewSafeArea_Previews: PreviewProvider {
static var previews: some View {
ScrollViewSafeArea()
}
}

SwiftUI NavigationLink not displaying view until physical rotation then all is ok?

The opening view of App is blank with a Back Button. However, the intended view will appear after complete rotation of physical device (before touching anything) or by tapping the Back Button on the displayed empty view.
This is a weird bug. After that rotation (to landscape and back to protrait) everything is peachy-keen-o.
I am aware that adding: .navigationViewStyle(StackNavigationViewStyle()) to the NavigationView will sorta resolve the problem. But this solution is a poor fix for my App's needs.
Is there a command to intentionally rotate device in code to resolve this? Or some other fix to get that first view to appear without counting on the user to rotate the device?
I've tried various solutions with no luck.
Below is a quick setup of the problem.
struct FirstView: View {
#Binding var viewNum: Int?
var body: some View {
VStack {
Text("View One")
.padding(20)
Button {
viewNum = 2
} label: {
Text("Go to 2nd view")
}
}
.onAppear {
viewNum = 1
}
}
}
struct MainView: View {
#State var selection: Int? = 1
var body: some View {
// VStack {
NavigationView {
List {
NavigationLink("First View", tag: 1, selection: $selection){ FirstView(viewNum: $selection)}
NavigationLink("Second View", tag: 2, selection: $selection){
Text("View 2").padding(20)
Button {
selection = 1
} label: {
Text("Go to first view")
}
}
}
}
// .navigationViewStyle(StackNavigationViewStyle())
//}
}
}

How can I present an overlay above the keyboard in SwiftUI?

I have a screen in my app that automatically displays a keyboard when the screen is presented. The screen allows users to enter their mobile number. In order to select a dialling code, the user needs to tap a button which will then trigger the presentation of an overlay.
Problem
The overlay is being presented, but it's showing up behind the currently present keyboard.
Question
How can I make this overlay be the very top view?
There is no way for me to use the zIndex modifier on the keyboard for obvious reasons. I'm wondering if there is a way to make the overlay the top view when it's about to be presented, or if the overlay can be added to the window.
Thanks in advance
You should probably only have one source of input at any given time — either the keyboard should be presented to enter a number, or the overlay should be presented to pick the dialing code, not both. Here's an example which hides the keyboard when overlay appears, and vice versa. (Keyboard dismissal code from this answer.)
struct ContentView: View {
#State private var number = ""
#State private var showingOverlay = false
var body: some View {
GeometryReader { proxy in
ZStack(alignment: .top) {
// Just here to force ZStack to use the whole screen
Rectangle()
.fill(Color.clear)
VStack(alignment: .leading) {
Button("Select Dialing Code") {
UIApplication.shared.endEditing()
self.showingOverlay = true
}
TextField("Enter your number", text: self.$number, onEditingChanged: {
if $0 { self.showingOverlay = false }
})
.keyboardType(.phonePad)
}
Overlay(showing: self.$showingOverlay)
.frame(height: 400)
.offset(x: 0, y: proxy.size.height + (self.showingOverlay ? -300 : 100))
.animation(.easeInOut)
}
}
}
}
struct Overlay: View {
#Binding var showing: Bool
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 15)
.fill(Color(.systemGray4))
Button("Dismiss") {
self.showing = false
}
}
}
}
extension UIApplication {
func endEditing() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}

Why isn't the animateActiveItem function animating in Sencha Touch

I have the following code in my app class:
switchMainView: function (newView, config) {
if (this.currentView != false) {
Ext.Viewport.remove(this.currentView);
}
this.currentView = Ext.create(newView, config);
Ext.Viewport.animateActiveItem(this.currentView, { type: 'slide', direction: 'right' })
},
Which can be called from any controller. However, it is not showing the animation. Any ideas what is wrong with it?
According to sencha guys :
AnimateActiveItem(activeItem,animation ) will
Animates to the supplied activeItem with a specified animation. Currently this only works with a Card layout. This passed animation will override any default animations on the container, for a single card switch. The animation will be destroyed when complete.
viewport: {
layout: {
type: 'card'
}
}
add above code in app.js
This is because the "this.currentView" view isn't part of the viewport yet. Use this line before the animateActiveItem line:
Ext.Viewport.add(this.currentView);
This should make it work.