How to center a second HStack View? - swiftui

I'm having trouble centering that second "Date" Text within the HStack. As you can see, in the image, it is a bit farther to the left. I want only the second view to be centered in the HStack. I want the first View to be latched to leading.
Here is the code.
import SwiftUI
struct DaySummariesBarChart: View {
var body: some View {
HStack {
Text("Date")
.font(.footnote)
Text("Date")
Spacer()
}
}
}
struct BarChart_Previews: PreviewProvider {
static var previews: some View {
DaySummariesBarChart()
.previewLayout(.sizeThatFits)
}
}

This is a pretty clean way to do it:
var body: some View {
ZStack {
Text("Date")
.font(.footnote)
.frame(maxWidth: .infinity, alignment: .leading)
Text("Date")
}
}
The first Text gets a maxWidth of infinity, so it takes up the whole space, but is aligned to .leading.
The second Text is centered by default in the ZStack.

The Spacer() moves the Views to the left. Your problem should be solved by adding another Spacer() on the other side.
struct DaySummariesBarChart: View {
var body: some View {
HStack {
Spacer()
Text("Date")
.font(.footnote)
Text("Date")
Spacer()
}
}
}

You can use a GeometryReader to make the width of the Views exactly half and therefore center the second one.
struct DaySummariesBarChart: View {
var body: some View {
GeometryReader { geometry in
HStack {
Text("Date")
.font(.footnote)
.frame(width: geometry.size.width / 2)
Text("Date")
.frame(width: geometry.size.width / 2)
}
}
}
}

Related

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 How to make a slide in view that pushes another view away while keeping it the same size

Before Slide
After Slide
struct SlideView: View {
#State var isClicked = false
var body: some View {
HStack{
Rectangle()
.fill(.gray)
.ignoresSafeArea()
.frame(width: isClicked ? UIScreen.main.bounds.width * 0.75 : 0)
VStack{
Text("This gets squished")
HStack{
Button{
withAnimation(.spring()) {
isClicked.toggle()
}
} label: {
Image(systemName: "menucard.fill")
.padding(.leading)
}
Spacer()
}
Spacer()
}
}
}
}
So I have this view that kind of "slides in" and it's pretty close to what I want but not exactly, the view that slides in ends up squishing the other view and compressing it to be about 25% of it's size. Of course this makes sense because it's all in a HStack and I end up taking 75% of the HStack's space but I was wondering if anybody had an idea of how I could do something like this but without squishing the second view that gets pushed away? So basically keep it the same size and just have the first 1/4 of the view visible and the other 3/4 just be gone I guess.
The problem is the view that gets squished has no explicit width. Understand how views get sized in SwiftUI. The parent view proposes a size, and the child view responds with the size it wants. Before you click the button, the parent view (the HStack) is proposing 100% to the view. That view says that I can do 100%, so no squishing. However, when you make the other view 75% of the parent, the parent can only offer 25% to the first view. The view responds, I can fit if I squish, so it does. See Laying out a simple view.
To fix it, you simply need to explicitly set the width of the first view to 100%, and then it will get pushed over like you were expecting without compression.
struct SlideInView: View {
#State var isClicked = false
var body: some View {
// I swapped out UIScreen.main.bounds for a GeometryReader
// UIScreen.main.bounds.width always returns the width of the screen
// even if the parent view does not have that much space to offer, and
// can lead to some interesting results.
GeometryReader { geometry in
HStack{
Rectangle()
.fill(.gray)
.ignoresSafeArea()
.frame(width: isClicked ? geometry.size.width * 0.75 : 0)
VStack{
Text("This gets squished")
HStack{
Button{
withAnimation(.spring()) {
isClicked.toggle()
}
} label: {
Image(systemName: "menucard.fill")
.padding(.leading)
}
Spacer()
}
Spacer()
}
.frame(width: geometry.size.width) // Explicitly set width here
}
}
}
}
Personally, I think it would make more sense to just use .offset, and put them in a ZStack:
ZStack {
VStack {
HStack {
Spacer()
Text("yellow")
Spacer()
}
Spacer()
}
.background(.yellow)
VStack {
Text("red")
HStack {
Button{
withAnimation(.spring()) {
isClicked.toggle()
}
} label: {
Image(systemName: "menucard.fill")
.padding(.leading)
}
Spacer()
}
Spacer()
}
.background(.red)
.offset(.init(width: isClicked ? UIScreen.main.bounds.width * 0.75 : 0, height: 0))
}
And you can add another .offset modifier to the yellow one to make it looks slidein:
VStack {
//...
}
.background(.yellow)
.offset(.init(width: isClicked ? 0 : -UIScreen.main.bounds.width * 0.75, height: 0))

Why do the views extend wider than the screen?

Edit: Substitute your "system name:" of choice. "pencil.circle" works fine. "edit" is not a valid SF Symbol.
(I've simplified my code so you can cut and paste. That's why you see .frame, resizable, etc. where much simpler code might your first instinct.)
I have created a view which is a vertical list of row items (table view).
Each row item has a horizontal view with two images inside it.
The images take up too much space and do not fit correctly on the screen:
import SwiftUI
#main
struct StackOverflowDemoApp: App {
var body: some Scene {
WindowGroup {
TandemView()
}
}
}
struct PaddedImageView: View {
let color: Color = .red
var body: some View {
ZStack {
color
Image(systemName: "edit")
.resizable()
.padding()
}
Spacer()
}
}
struct TandemView: View {
var body: some View {
HStack {
Spacer()
Image(systemName: "pencil")
.resizable()
.background(Color.orange)
.frame(height: 80)
.aspectRatio(1, contentMode: .fill)
PaddedImageView()
.frame(width: 200, height: 80)
}
.padding()
.fixedSize()
}
}
struct TandemView_Previews: PreviewProvider {
static var previews: some View {
TandemView()
}
}
The above is the closest I can get to the desired layout (it just needs to fit horizontally). I experimented with GeometryReader but that did not produce desired results.
Here are some things I tried:
The code as provided
NoConstraintsOnPencilOrHStack
NoConstraintsOnTandemView
NoConstraintsOnImageInPaddedViewButWithFrameConstraint
I am trying to get a row view which consists of two Images (my actual source consists of UIImage objects) that fits within the width of the screen.
Edit:
After Accepting cedricbahirwe's spot-on response, I was able to simplify the code further. New results:
I added at the top level
TandemView()
.padding(.horizontal)
I removed:
// Spacer()
at the end of PaddedImageView
updated TandemView -- changed both frames and removed 3 lines:
struct TandemView: View {
var body: some View {
HStack {
Spacer()
Image(systemName: "pencil")
.resizable()
.background(Color.orange)
.frame(width: 80, height: 80)
// .aspectRatio(1, contentMode: .fill)
PaddedImageView()
.frame(height: 80)
}
// .padding()
// .fixedSize()
}
}
This is happening because of the layout of PaddedImageView View, you can actually remove the Spacer since it is not needed there.
So change
struct PaddedImageView: View {
let color: Color = .red
var body: some View {
ZStack {
color
Image(systemName: "edit")
.resizable()
.padding()
}
Spacer()
}
}
to
struct PaddedImageView: View {
let color: Color = .red
var body: some View {
ZStack {
color
Image(systemName: "edit")
.resizable()
.padding()
}
}
}
Note:
SwiftUI Engine infers the layout of your view from the implementation of the body property. It's recommended to have one Parent View inside the body property.

How to make this simple view with swiftui?

I am trying to do this view with swiftui but i am stuck.
I want the text("Mes évènements") to be centered and I want it to take all the place it can.
The two horizontal line should only take the place left.
I tried with HStack but I couldn't make it work as i would like to.
Here is a possible solution.
struct ContentView: View {
var body: some View {
HStack{
VStack{
OrangeLine()
}
Text("Mes évènements")
.font(.subheadline)
.fontWeight(.bold)
.foregroundColor(Color.orange)
VStack{
OrangeLine()
}
}
}
}
struct OrangeLine: View {
var body: some View {
Rectangle()
.fill(Color.orange)
.frame(height: 2)
.edgesIgnoringSafeArea(.horizontal)
}
}

How position HStack in bottom of my screen no use the spacer()

I want move the HStack in bottom of my screen no use the spacer() because when use the spacer move the logo for top of my screen.
Here is a solution without using Spacer:
struct ContentView: View {
var body: some View {
VStack {
VStack {
Text("Image")
Text("Some text")
}.frame(minHeight: 0, maxHeight: .infinity)
HStack {
Text("Bottom")
}
}
}
}
I know you asked for no spacer, but this code shows you can use them without your logo going to the top of the screen. Alternatively you can use ".position(CGPoint(...))"
struct ContentView: View {
var body: some View {
VStack {
Spacer()
VStack (alignment: .center) {
Image("your-image").resizable().frame(width: 90, height: 95)
Text("TCheck time").font(.title).foregroundColor(.gray)
}.padding()
Spacer()
HStack (alignment: .bottom) {
Text("2020 SplitWay").font(.subheadline).foregroundColor(.gray)
}
}
}
}