Huge black bars on top and bottom of UI - SwiftUI - ios

I have an issue with Views in the sample app I am trying to help me learn SwiftUI views.
The black bars at the top and bottom shouldn't be there. I want to extend the view to the top and bottom of the safe area limit.
Here is the code using Xcode 13.4.1 and iOS 15.5:
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
HotelView()
.tabItem {
Image(systemName: "house")
.resizable()
Text("Home")
}
HomeView(title: "My Trips")
.tabItem {
Image(systemName: "suitcase")
Text("My Trips")
}
HomeView(title: "Saved")
.tabItem {
Image(systemName: "heart")
Text("Saved")
}
HomeView(title: "Profile")
.tabItem {
Image(systemName: "person")
Text("Profile")
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
Also the HotelView file:
import SwiftUI
struct HotelView: View {
var body: some View {
NavigationView {
List(hotels) { hotel in
ScrollView(.vertical, showsIndicators: true) {
NavigationLink(destination: DetailView(hotels: hotel)) {
HStack {
Image(hotel.image)
.resizable()
.frame(height: 100)
.frame(maxWidth: .infinity)
.clipShape(RoundedRectangle(cornerRadius: 10, style: .continuous))
.overlay(
Text(hotel.city)
.fontWeight(.bold)
.foregroundColor(.white),alignment: .center)
}
}
}
}
// navtitle
}
}
}
And the result in the simulator is:
Black bars on top and bottom
import SwiftUI
#main
struct Mohsin_city_plannerApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}

So the solution is to add launch screen to your plist info file even in SwiftUI

Related

SwiftUI: How to force SwiftUI ContextMenu Preview to take up the full Width?

Context
I am currently working with the new SwiftUI ContextMenu, which supports a Preview. However, I have difficulties forcing the Preview to take up the full width of the screen.
Code
Text("Hello World")
.contextMenu { menuItems } preview: { Text("Preview") }
Question
Please Note: I already tried to add .frame(maxWidth: .infinity) to Text("Preview") but this didn't solve the problem.
How can I force the Preview to take up the full width of the screen?
You could wrap your preview view in a NavigationStack. That's easy, but it will not only expand the preview horizontally, it will also expand vertically, which may not be what you're looking for.
Another way would be to set the idealWidth for the preview:
import SwiftUI
struct ContentView: View {
#State var viewWidth = CGFloat.zero
var body: some View {
VStack {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Long press me")
}
.contextMenu {
Button("Action") {}
} preview: {
Text("Preview Text")
.padding(.vertical, 50)
.frame(idealWidth: viewWidth)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.overlay {
GeometryReader { geometry in
Color.clear
.onAppear {
self.viewWidth = geometry.frame(in: .local).size.height
}
}
}
}
}
This was deprecated.
You didn't give much code, so I used random example:
You can use Menu like this:
struct MenuExample: View {
var body: some View {
Menu {
Button("Duplicate", action: duplicate)
Button {
rename()
} label: { Label("rename", systemImage: "square.and.pencil") }
Button {
delete()
} label: { Label("delete", systemImage: "trash") }
Menu {
Button("Open in Preview", action: openInPreview)
Button("Save as PDF", action: saveAsPDF)
} label: { Label("PDF", systemImage: "doc.fill") }
} label: {
Label("Menu", systemImage: "book.fill")
.font(.title)
}
.foregroundColor(.orange)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
.padding(30)
.background(.orange.opacity(0.3))
}
func duplicate() {}
func delete() {}
func rename() {}
func saveAsPDF() {}
func openInPreview() {}
}
struct MenuTemp_Previews: PreviewProvider {
static var previews: some View {
MenuExample()
}
}

Swift UI Scroll View: Set frame for drag indicator

I have following problem. I want to create a vertical ScrollView with many rows. At the bottom of the view I have an info bar which appears over the scroll view because I put all the items in a ZStack. Here is my code and what it produces:
struct ProblemView: View {
var body: some View {
ZStack {
ScrollView(.vertical, showsIndicators: true) {
VStack {
ForEach(0..<100, id:\.self) {i in
HStack {
Text("Text \(i)")
.foregroundColor(.red)
Spacer()
Image(systemName: "plus")
.foregroundColor(.blue)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
Divider()
}
}
}
VStack {
Spacer()
HStack {
Text("Some Info here")
Image(systemName: "info.circle")
.foregroundColor(.blue)
}
.padding()
.frame(maxWidth: .infinity)
.ignoresSafeArea()
.background(.ultraThinMaterial)
}
}
}
}
struct ProblemView_Previews: PreviewProvider {
static var previews: some View {
ProblemView()
}
}
As you can see the drag indicator is hidden behind the info frame. Also the last item can't be seen because it is also behind the other frame. What
I want is that the drag indicator stops at this info frame. Why am I using a ZStack and not just a VStack? I want that this opacity effect behind the info frame, you get when you scroll.
A edit on my preview post has been added and therefore I cannot edit it... I am just gonna post the answer as an other one then.
This is the code that fixes your problem:
import SwiftUI
struct ProblemView: View {
var body: some View {
ScrollView {
VStack {
ForEach(0..<100, id:\.self) {i in
HStack {
Text("Text \(i)")
.foregroundColor(.red)
Spacer()
Image(systemName: "plus")
.foregroundColor(.blue)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
Divider()
}
}
.frame(maxWidth: .infinity)
}
.safeAreaInset(edge: .bottom) { // 👈🏻
VStack {
HStack {
Text("Some Info here")
Image(systemName: "info.circle")
.foregroundColor(.blue)
}
.padding()
.frame(maxWidth: .infinity)
.ignoresSafeArea()
.background(.ultraThinMaterial)
}
}
}
}
struct ProblemView_Previews: PreviewProvider {
static var previews: some View {
ProblemView()
}
}
We cannot control offset of indicator, but we can make all needed views visible by injecting last empty view with the same height (calculated dynamically) as info panel.
Here is possible approach. Tested with Xcode 13.2 / iOS 15.2
struct ProblemView: View {
#State private var viewHeight = CGFloat.zero
var body: some View {
ZStack {
ScrollView(.vertical, showsIndicators: true) {
VStack {
ForEach(0..<100, id:\.self) {i in
HStack {
Text("Text \(i)")
.foregroundColor(.red)
Spacer()
Image(systemName: "plus")
.foregroundColor(.blue)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
Divider()
}
Color.clear
.frame(minHeight: viewHeight) // << here !!
}
}
VStack {
Spacer()
HStack {
Text("Some Info here")
Image(systemName: "info.circle")
.foregroundColor(.blue)
}
.padding()
.frame(maxWidth: .infinity)
.ignoresSafeArea()
.background(.ultraThinMaterial)
.background(GeometryReader {
Color.clear.preference(key: ViewHeightKey.self,
value: $0.frame(in: .local).size.height)
})
}
}
.onPreferenceChange(ViewHeightKey.self) {
self.viewHeight = $0
}
}
}
struct ViewHeightKey: PreferenceKey {
static var defaultValue: CGFloat { 0 }
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = value + nextValue()
}
}

SwiftUI - NavigationLink' content is not readable when contextMenu is presented

I have a coloured NavigationLink that has context-menu. Its content is not readable when the context-menu is presened. I have epxreminted using the context-menu on the immediate sub-view of the NavigationLink, but it is stil the same issue.
NavigationLink(destination: Text("View")) {
VStack(alignment: .leading) {
Text("Context Menu")
.font(.system(size: 24, weight: .bold))
}
.frame(minWidth: 0, maxWidth: .infinity, idealHeight: 70)
.foregroundColor(.white)
.padding()
.cornerRadius(3.0)
}
.background(Color.red)
.contextMenu {
Section {
Button(action: {
}) {
Label("Edit", systemImage: "square.and.pencil")
}
}
Section(header: Text("Secondary actions")) {
Button(action: {}) {
Label("Delete", systemImage: "trash")
}
}
}
NavigatoinLinks look like in its original state.
When the context-menu is presented. The problem is even worse If I use small sized text.
I have tested on ios 14.2 both on simulator and physical device.
Info
Hierarchy of views.
ScrollView {
LazyVStack {
ForEach(data) { item in
// NavigationLink
}
}
}
Update
This is a similar project that has the same issue.
struct ContentView: View {
var body: some View {
NavigationView {
ScrollView {
LazyVStack {
ForEach(0..<10) { item in
NavigationLink(destination: Text("View")) {
VStack(alignment: .leading) {
Text("Context Menu")
.font(.system(size: 24, weight: .bold))
}
.frame(minWidth: 0, maxWidth: .infinity, idealHeight: 70)
.foregroundColor(.white)
.padding()
.cornerRadius(3.0)
}
.background(Color.red)
.contextMenu {
Section {
Button(action: {
}) {
Label("Edit", systemImage: "square.and.pencil")
}
}
Section(header: Text("Secondary actions")) {
Button(action: {}) {
Label("Delete", systemImage: "trash")
}
}
}
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I know it's been two years, but this still remains an issue with iOS 16 when you use LazyVStack. In contrast with List, SwiftUI generates a clear automatic preview. What's new with iOS 16 is that you can now define a custom preview, and SwiftUI will present that preview without the blur. If you choose to use LazyVStack for performance or another reason, this gives you an alternative, albeit with duplicate code.
From your example above, you would add:
NavigationLink(destination: Text("View")) {
// View such as your VStack containing Text
}
.contextMenu {
// Menu items
} preview: {
// View, again, but you might want to simplify or modify
}

ScrollView navigationlink still active across VStack and GeometryReader, XCode12, beta 4

Using XCode12, beta 4, I am trying to separate a header area and a ScrollView. I've tried both VStack and GeometryReader; however, when I click in the header area, the navigation link in the ScrollView item beneath it is triggered.
If I use a list, this undesired behavior is not observed. If I use the ScrollView in XCode 11.6 and build for iOS13, this undesired behavior is also not observed.
Did something change with ScrollViews in VStacks or GeometryReaders in iOS14? Why does the scrollview "slide" under the object in the VStack or GeometryReader?
struct ContentView: View {
var body: some View {
NavigationView{
//GeometryReader { geo in
VStack{
VStack{
Text("Blah")
}//.frame(height: geo.size.height*0.20)
VStack {
ScrollView {
ForEach(0..<10) { i in
NavigationLink(destination: Text("\(i)")) {
cardRow(i: i)
.frame(maxWidth: .infinity)
.foregroundColor(Color(UIColor.label))
.padding()
.background(RoundedRectangle(cornerRadius: 12))
.foregroundColor(Color(UIColor.secondarySystemFill))
.padding()
}
}
}
}//.frame(height: geo.size.height*0.90)
}
}.navigationViewStyle(StackNavigationViewStyle())
}
struct cardRow: View {
var i: Int
var body: some View {
HStack {
VStack {
Text("88")
}.hidden()
.overlay(
VStack{
Text("\(i)")
}
)
Divider()
.background(Color(UIColor.label))
Spacer()
}
}
}
}
Here is worked solution (tested with Xcode 12 / iOS 14)
VStack {
ScrollView {
ForEach(0..<10) { i in
NavigationLink(destination: Text("\(i)")) {
cardRow(i: i)
.frame(maxWidth: .infinity)
.foregroundColor(Color(UIColor.label))
.padding()
.background(RoundedRectangle(cornerRadius: 12))
.foregroundColor(Color(UIColor.secondarySystemFill))
.padding()
}
}
}.clipped().contentShape(Rectangle()) // << here !!
}

Remove circular button background in SwiftUI (WatchKit)

I'm struggling to remove the background of a custom circular Button element in SwiftUI which is defined as follows:
struct NavButton: View {
var body: some View {
Button(action: {})
VStack {
Text("Button")
}
.padding(40)
.background(Color.red)
.font(.title)
.mask(Circle())
}
}
}
This results in a rectangular light gray background around the button, where I want it to not be shown:
I tried to append a "background" modifier to the button, and it demonstrates very strange behavior: if it's set to "Color.clear", there is no effect. But if I set it to "Color.green" it does change the background as expected.
Example of setting the "Background" modifier to "Color.green":
struct NavButton: View {
var body: some View {
Button(action: {})
VStack {
Text("Button")
}
.padding(40)
.background(Color.red)
.font(.title)
.mask(Circle())
}
.background(Color.green) // has no effect if set to "Color.clear"
}
}
I wonder if I'm missing something here?
PS: I'm using Xcode 11.1 (11A1027)
Try adding .buttonStyle(PlainButtonStyle()) on the button itself.
You would have something like this:
Button(action: {}){
VStack{
Text("Button")
}
.padding(40)
.background(Color.red)
.font(.headline)
.mask(Circle())
}
.buttonStyle(PlainButtonStyle())
Declare your own ButtonStyle:
struct RedRoundButton: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding(40)
.font(.title)
.background( Circle()
.fill(Color.red))
}
}
and then use it like this:
Button("Button") {}
.buttonStyle(RedRoundButton())
Try this:
struct ContentView: View {
var body: some View {
Button(action: {}) {
Text("Button")
.frame(width: 80, height: 80)
}
.background(Color.red)
.cornerRadius(40)
.frame(width: 80, height: 80)
}
}
Try this.
struct ContentView: View {
var body: some View {
VStack {
Button(action: {}){
Text("button")
.font(.system(size: 50))
.foregroundColor(.black)
.bold()
}
.padding(30)
.background(Color.yellow)
.font(.headline)
.mask(Circle())
.buttonStyle(PlainButtonStyle())
} // end Vstack
}// end body
}

Resources