Padding HStack in the top of any screen - ios

I want to put an HStack which contains two Texts in the top of any device screen.
the problem is when I use padding that I have to decide fixed size of padding.

struct ContentView: View {
var body: some View {
VStack(alignment: .leading) {
HStack(spacing: 10) {
Text("Hello world!")
Text("Hello world!")
}.padding(.top, 100)
Spacer()
}
}
}

Related

How to align text to the top of screen?

I'm looking how to align text to the top of screen, do you know how to?
import SwiftUI
struct RegisterSignInScreen: View {
var body: some View {
VStack {
Text("Welcome Back!")
.font(.title)
.fontWeight(.bold)
.multilineTextAlignment(.center)
.padding(.bottom, 5.0)
Text("Please sign in to your account")
.font(.subheadline)
.fontWeight(.bold)
.foregroundColor(Color.gray)
.multilineTextAlignment(.center)
}
}
}
struct RegisterSignInScreen_Previews: PreviewProvider {
static var previews: some View {
RegisterSignInScreen()
}
}
image
I tried to embed my VStack in a ZStack:
ZStack(alignment: .top)
But it didn't work.
To see why this is happening you can add a background to your VStack or ZStack
ZStack {
VStack {
//Text items
}
}
.background(.red)
What you will notice (maybe unexpectedly) is that the stack is only as big as it needs to be to contain the text items.
When you add alignment to the stack it aligns the content within the stack to the specified edge of the relatively small stack. It doesn't align the stack to an edge of the screen, or change the size of the stack. What you're actually looking to do is align the stack, not it's content.
In order to align to the top of the screen you can make the stack fill the entire height of the screen. Either by adding a Spacer() at the bottom of the VStack that will fill the remaining vertical space pushing the content upwards, or by applying a frame with .infinity maxHeight: and top aligned content to the VStack.
VStack {
Text("Hello World!")
Spacer()
}
VStack {
Text("Hello World!")
}
.frame(maxHeight: .infinity, alignment: .top)
Alternatively if required for your view, you can do a similar thing with a second stack containing your text stack like so:
var body: some View {
VStack {
welcomeText
Spacer()
}
}
var welcomeText: some View {
VStack {
Text("Welcome Back!")
.font(.title)
.fontWeight(.bold)
.multilineTextAlignment(.center)
.padding(.bottom, 5.0)
Text("Please sign in to your account")
.font(.subheadline)
.fontWeight(.bold)
.foregroundColor(Color.gray)
.multilineTextAlignment(.center)
}
}
You can do this in a couple of ways, but the most obvious way is to simply add a Spacer() in the bottom of the VStack
Like so:
struct RegisterSignInScreen: View {
var body: some View {
VStack {
Text("Welcome Back!")
Text("Please sign in to your account")
Spacer() // <- HERE
}
}
}
This will push your content in the VStack to the top.
Alternatively, you can add a frame modifier and force your VStack height and add the alignment there using .frame
struct RegisterSignInScreen: View {
var body: some View {
VStack {
Text("Welcome Back!")
Text("Please sign in to your account")
}
.frame(maxHeight: .infinity, alignment: .top) // <- HERE
}
}
ZStack(alignment: .top) works, but not the same way as you think)
try to do:
ZStack(alignment: .top){
}
.background(Color.green)
and you will understand why so :)
you need to use spacer :)
VStack {
YourView()
Spacer()
}

Animate only one view inside VStack

My main view is as simple as follows:
VStack(alignment: .center, spacing: .spacing4) {
ExpandableView() // some params for title etc, not relevant
ExpandableView()
}
.padding(.horizontal, 10)
.padding(.vertical, 18)
While my ExpandableView is as follows:
public struct ExpandableView: View {
#State var showExpanded = false
public var body: some View {
VStack(alignment: .leading, spacing: .spacing2) {
HStack(spacing: .spacing2, content: {
Text("Title")
Spacer()
arrowView // The chevron image
})
.contentShape(Rectangle()) // so the complete HStack is tappable
.onTapGesture {
withAnimation(.spring()) {
showExpanded.toggle()
}
}
.animation(nil)
if showExpanded {
Text("The expanded text underneath the title goes here")
.transition(.opacity.combined(with: .flipFromTop))
}
}
}
As you can see in the image, when I expand the second view in the main VStack, the first one animates too, what am I doing wrong here?

SwiftUI Content View random padding

I am currently creating a content view for my application and am experiencing some strange behavior with padding. As seen in the photo below, there is quite a bit of space below the navigation bar at the top of the phone. I don't specify any padding here so I'm wondering why there is so much space between the top and where the image is displayed. The image doesn't have that large of a white box around it either.
My code does not specify any kind of margin or padding. I'm new to Swift and SwiftUI so I'm curious if there is some automatic padding applied to navigation views?
import Kingfisher
struct BottleView: View {
let bottle: Bottle
var body: some View {
VStack {
KFImage(URL(string: bottle.image ?? "")!)
.resizable()
.frame(width: 128, height: 256)
VStack(alignment: .leading) {
HStack {
Text(bottle.name)
.font(.title)
Spacer()
Text("Price")
}
HStack {
Text(bottle.varietal ?? "")
Spacer()
Text("$\(bottle.price ?? "")")
}
.font(.subheadline)
.foregroundColor(.secondary)
VStack(alignment: .leading) {
Text("Information")
.font(.title2)
Text(bottle.information ?? "")
}
}
}
}
}
If you apply a .background(Color.red) to the VStack, you'll see that it's centered in the screen.
var body: some View {
VStack {
Image("TestImage")
.resizable()
.frame(width: 128, height: 256)
/// ... more code
}
.background(Color.red)
}
This is because, by default, most SwiftUI views are centered. For example, try just a Text:
struct ContentView: View {
var body: some View {
Text("Hello, I'm centered!")
}
}
So if you don't want it centered, this is where Spacers come in. These expand to fill all available space, pushing all other views. Here's the code that gets rid of the "bit of space below the navigation bar at the top of the phone":
(note that I replaced your Bottle properties with static text, make sure you change them back)
struct BottleView: View {
// let bottle: Bottle
var body: some View {
VStack {
Image("TestImage")
.resizable()
.frame(width: 128, height: 256)
VStack(alignment: .leading) {
HStack {
Text("Blantons")
.font(.title)
Spacer()
Text("Price")
}
HStack {
Text("Bourbon")
Spacer()
Text("$59.99")
}
.font(.subheadline)
.foregroundColor(.secondary)
VStack(alignment: .leading) {
Text("Information")
.font(.title2)
Text("Product info here")
}
}
Spacer() /// spacer right here! pushes the other views up
}
.background(Color.red)
.navigationBarTitleDisplayMode(.inline) /// get rid of the additional top gap that the default Large Title navigation bar produces
}
}
Result:

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 !!
}

leading edge for VStack in SwiftUI

I want to create a VStack of many Texts with 20 points of spacing between each Text. I want my VStack to be aligned to left side of the screen(or leading side of parent View).
Try this:
struct ContentView: View {
var body: some View {
HStack(){
//alignment options: .center , .leading , .trailing
VStack(alignment: .leading, spacing: 20){
Text("Salam")
Text("chetori")
Text("Arsalan")
Text("?")
}
Spacer()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
and if you want your VStack to be on right side of your screen, put the Spacer above the VStack
VStack(alignment: .leading, spacing: 20){
ForEach(0..<20) { i in
HStack {
Text("\(i)")
.multilineTextAlignment(.leading) // needed only if your text has multiple lines
Spacer()
}
}
}.padding()
And the result:

Resources