SwiftUI - Can't fill screen on the bottom of sheet - swiftui

The bottom of my sheet is not filling up with color for some reason. Tried the below code, but can only fill the top safe space. Any clue?
var body: some View {
GeometryReader { geometry in
VStack {
Text("Hi")
.font(.title)
}
.frame(width: geometry.size.width, height: geometry.size.height)
.background(LinearGradient(gradient: Gradient(colors: [Color(hex: 0x71A2B6), Color(hex: 0xF09D51)]), startPoint: .top, endPoint: .bottom))
.edgesIgnoringSafeArea(.all)
}
}

You have set .frame(width: geometry.size.width, height: geometry.size.height) which will not cover the bottom area.
And if your goal is just to have your View fill the whole screen you may not need a GeometryReader.
You can try using a ZStack instead:
struct ContentView: View {
var body: some View {
ZStack {
LinearGradient(gradient: Gradient(colors: [Color(hex: 0x71A2B6), Color(hex: 0xF09D51)]), startPoint: .top, endPoint: .bottom)
VStack {
Text("Hi")
.font(.title)
}
}
.edgesIgnoringSafeArea(.all)
}
}

I moved .edgesIgnoringSafeArea(.all) down to cover the GeometryRender so that it would fill the device, thus providing the correct screen dimensions.
import SwiftUI
struct ContentView: View {
var body: some View {
GeometryReader { geometry in
VStack {
Text("Hi")
.font(.title)
}
.frame(width: geometry.size.width,
height: geometry.size.height)
.background(LinearGradient(gradient: Gradient(colors: [Color.red, Color.blue]),
startPoint: .top,
endPoint: .bottom))
}.edgesIgnoringSafeArea(.all)
}
}

Related

How to prevent view from leaving screen in a ScrollView SwiftUI

I want to prevent the 3 bars from leaving the screen. Once they have reached the top of the screen they will remain there until scrolling has been reset. So only the circle and remaining elements will continue to scroll.
If possible it would also make sense for the circle to rest as well but further off screen.
import SwiftUI
struct ContentView: View {
var body: some View {
ScrollView {
LazyVStack {
Circle()
HStack {
Rectangle()
.frame(height: 50)
.padding()
Rectangle()
.frame(height: 50)
.padding()
Rectangle()
.frame(height: 50)
.padding()
}
ForEach(0..<20) { index in
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
}
.padding()
}
}
.padding()
}
}
}
You could turn the rectangles into a section for your LazyVStack list and then set the
stack view to pin the section headers using LazyVStack(pinnedViews:[.sectionHeaders]) Please see Apple documentation for more details.
struct ContentView: View {
var body: some View {
ScrollView {
LazyVStack(pinnedViews:[.sectionHeaders]) {
Circle()
Section(header:
HStack {
Rectangle()
.frame(height: 50)
.padding()
Rectangle()
.frame(height: 50)
.padding()
Rectangle()
.frame(height: 50)
.padding()
}) {
ForEach(0..<20) { index in
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
}
.padding()
}
}
}
.padding()
}
}
}

Utilize HStack to confirm to logo and skip text

Does anyone know how to make the following view in SwiftUI?
HStack:
[ blank logo(centered) Skip(text)]
So I have the following HStack:
Zstack(alignment: .topLeading) {
VStack{
HStack {
Image("onboarding-logo")
.resizable()
.scaledToFit()
.frame(width: 150.0, height: 150.0)
.padding(.top, 35)
}
}
}
Does anyone know how I can have a "Skip" text in the top right corner of the screen, but also keep my logo centered and not have anything on the left side? I've tried Spacers and all, but I'm having no luck.
I would like to click "Skip" and then lead to another view.
There are many ways to achieve this. Here I have used LazyVGrid since other answers based on Stacks
struct ContentView: View {
var body: some View {
VStack {
LazyVGrid(columns: [GridItem(), GridItem(), GridItem()], content: {
Spacer()
Image(systemName: "star.fill")
.frame(width: 150, height: 150, alignment: .center)
.border(.gray)
Button(action: {
}, label: {
Text("Skip")
})
})
.border(.gray)
Spacer()
}
}
}
Is this the screen configuration you want?
The Zstack is used to center the Hstack into which the image is placed, and the new HStack uses a spacer to move the Text to the right.
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
VStack {
HStack(alignment: .center) {
Image("farnsworth")
.resizable()
.scaledToFit()
.frame(width: 150.0, height: 150.0)
}
Spacer()
}
VStack {
HStack {
Spacer()
Button {
// do Something...
} label: {
Text("Skip>>")
.padding(.top, 10)
}
}
Spacer()
}
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

SwiftUI transition is not working when in HSack

I have a VStack which wraps a number elements wrapped inside another HStack, I want to add a simple bottom to top transition on load, but it does not have any effect on the output:
var body: some View {
let bottomPadding = ScreenRectHelper.shared.bottomPadding + 150
GeometryReader { geometry in
ZStack {
VisualEffectViewSUI(effect: UIBlurEffect(style: .regular))
.edgesIgnoringSafeArea(.all)
VStack(alignment: .center) {
Spacer()
HStack {
VStack(alignment: .leading, spacing: 15) {
ForEach(items, id: \.id) { item in
HStack(alignment: .center) {
Image(item.imageName)
.resizable()
.scaledToFit()
.frame(width: 24)
Spacer()
.frame(width: 15)
Text("\(item.text)")
.foregroundColor(.white)
.transition(.move(edge: .bottom))
}
.contentShape(Rectangle())
.onTapGesture {
/// Do something
}
}
}
}
.frame(width: geometry.size.width, height: nil, alignment: .center)
}.zIndex(1)
.frame(width: geometry.size.width, height: nil, alignment: .center)
.padding(.bottom, bottomPadding)
}.background(
LinearGradient(gradient: Gradient(colors: [gradientColor.opacity(0),gradientColor]), startPoint: .top, endPoint: .bottom)
)
}.edgesIgnoringSafeArea(.all)
}
This SwiftUI view is added to a UIKit view controller and that view controller is presented modally.
.transition only works if you insert something conditionally into the view.
I'm not totally sure what you want to achieve, but if you want the whole view to slide from the bottom, this would work.
struct ContentView: View {
#State private var showText = false
let bottomPadding: CGFloat = 150
var body: some View {
ZStack {
if showText { // conditional view to make .transition work
// VisualEffectViewSUI(effect: UIBlurEffect(style: .regular))
// .edgesIgnoringSafeArea(.all)
VStack(alignment: .center) {
Spacer()
HStack {
VStack(alignment: .leading, spacing: 15) {
ForEach(0 ..< 3) { item in
HStack(alignment: .center) {
Image(systemName: "\(item).circle")
.resizable()
.scaledToFit()
.frame(width: 24)
Spacer()
.frame(width: 15)
Text("Item \(item)")
.foregroundColor(.white)
}
}
}
}
}
.frame(maxWidth: .infinity)
.padding(.bottom, bottomPadding)
.background(
LinearGradient(gradient: Gradient(colors: [.blue.opacity(0), .blue]),
startPoint: .top, endPoint: .bottom)
)
.edgesIgnoringSafeArea(.all)
.transition(.move(edge: .bottom)) // here for whole modal view
}
Button("Show modal") {
withAnimation {
showText.toggle()
}
}
}
}
}

Scrollable content not working as expected in SwiftUI

I'm trying to create a scroll view with my custom view, but when I add scroll to view it's not working as expected, without scroll view working fine.
struct ContentView: View {
var body: some View {
ScrollView(.vertical) {
VStack {
ForEach (0..<2) { _ in
ListItem()
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
// But the below code is working fine.
struct ContentView: View {
var body: some View {
VStack {
ForEach (0..<2) { _ in
ListItem()
}
}
}
}
// List Item
struct ListItem: View {
var body: some View {
VStack {
HStack {
Image("steve")
.resizable()
.clipShape(Circle())
.aspectRatio(contentMode: .fit)
.frame(maxWidth:44, maxHeight: 44)
VStack {
Text("Steve Jobs")
.font(.headline)
.frame(maxWidth: .infinity, alignment: .leading)
Text("1 hour ago")
.font(.footnote)
.frame(maxWidth: .infinity, alignment: .leading)
}
Spacer()
}
ZStack(alignment:.top) {
GeometryReader { geometry in
VStack {
ZStack {
Image("poster_1")
.resizable()
.aspectRatio(contentMode: .fit)
.cornerRadius(8)
.shadow(color: Color.black.opacity(0.12),
radius: 4, x: 1, y: 1)
.frame(width: geometry.size.width - 64,
height: geometry.size.height * 0.35)
.padding([.horizontal], 32)
.clipped()
ZStack {
Rectangle()
.fill(Color.black.opacity(0.75))
.frame(maxWidth:84 , maxHeight: 84)
.cornerRadius(12)
Image(systemName: "play.fill")
.font(.system(size: 44, weight: .bold))
.foregroundColor(.white)
}
}
VStack {
Text("Game of Thrones")
.accentColor(Color.gray.opacity(0.25))
.font(Font.subheadline.weight(.bold))
.padding([.horizontal], 32)
.padding([.bottom], 2)
.frame(maxWidth: .infinity,
alignment: .leading)
VStack {
Text("Game of Thrones is an American fantasy drama television series created by David Benioff and D. B. Weiss for HBO. ")
.accentColor(Color.gray.opacity(0.25))
.font(.footnote)
.frame(maxWidth: .infinity,
alignment: .leading)
.padding([.horizontal], 32)
Text("Show more...")
.accentColor(Color.gray.opacity(0.01))
.font(Font.footnote.weight(.bold))
.frame(maxWidth: .infinity,
alignment: .trailing)
.padding([.trailing], 32).onTapGesture {
print("okay")
}
}
}
}
}
}
}
}
}
ListItem contains multiple views which creates publisher info and movie information as shown below image.
Scrollview is scrolling but images are not shown in view as first image.
It is the geometry reader that you have in ListItem. Because neither a GeometryReader nor a Scrollview have their own size. Since neither no what size to render, they collapse. This is what you are seeing in your view. See this answer. The solution is to put the GeometryReader into ContentView outside the Scrollview and send the GeometryProxy that you called geometry into ListItem something like this:
struct ContentView: View {
var body: some View {
GeometryReader { geometry in
ScrollView(.vertical) {
VStack {
ForEach (0..<2) { _ in
ListItem(geometry: geometry)
}
}
} // Scrollview
} // GeometryReader
}
}
struct ListItem: View {
let geometry: GeometryProxy
var body: some View {
...
}
This seems to fix it in Preview, though you may have to change your multipliers in the .frame() that uses geometry to size it how you want.

full screen background image with vstack

i want to have a full screen background image with a navigationview (must be on top because it is from the basis view and not in "this" view normally).
In this view i want a VStack which is just inside the secure area, so between navigationbar and bottom layout.
unfortunately i got (see picture)
I expected the texts inside...
struct ContentView: View {
var body: some View {
NavigationView {
ZStack(alignment: .center) {
Image("laguna")
.resizable()
.edgesIgnoringSafeArea(.all)
.scaledToFill()
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
VStack(alignment: .center) {
Text("just a test")
.font(.largeTitle)
.foregroundColor(Color.white)
Spacer()
Text ("not centered....why?")
.font(.largeTitle)
.foregroundColor(Color.white)
}
.zIndex(4)
.navigationBarTitle("nav bar title")
}
}
}
}
Here is a bit modified variant. Tested with Xcode 11.4 (finally released) / iOS 13.4
struct TestFullScreenImage: View {
var body: some View {
NavigationView {
ZStack {
Image("large_image")
.resizable()
.edgesIgnoringSafeArea(.all)
.scaledToFill()
VStack {
Text("Just a test")
.font(.largeTitle)
.foregroundColor(.white)
Spacer()
Text("centered")
.font(.largeTitle)
.background(Color.green)
}
.navigationBarTitle("Navigation Title")
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
If need to use NavigationView, and maintain the image's aspect ratio, you can do this:
import SwiftUI
struct FullScreenPictureDemo: View {
var body: some View {
NavigationView {
ZStack {
Image("your_full_screen_background_picture")
.resizable()
.aspectRatio(contentMode: .fill)
.edgesIgnoringSafeArea(.all)
.scaledToFill()
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}