Styling with VStack and HStacks so text align - WidgetKit SwiftUI - swiftui

I'm trying to get the last styling done on my Widget but I just can't seem to get the number "+1.75" and the Orange dot to align with the "Wheat" text. How do I properly align this row?
I've tried using Spacer() but it just doesn't seem to work?
struct CropPriceView: View {
#Environment(\.widgetFamily) var family: WidgetFamily
var body: some View {
if family == .systemSmall{
VStack{
HStack{
VStack{
HStack{
Circle()
.fill(Color(#colorLiteral(red: 0.9333333333, green: 0.6784313725, blue: 0.262745098, alpha: 1)))
.frame(width: 10, height: 10)
VStack(alignment: .leading){
Text("Wheat")
.foregroundColor(Color(#colorLiteral(red: 0.168627451, green: 0.1647058824, blue: 0.1647058824, alpha: 1)))
.font(Font.custom("TPFrank-Bold", size: 14))
.lineSpacing(0.18)
Text("MATIF")
.font(Font.custom("TPFrank-Regular", size: 12))
.foregroundColor(Color(#colorLiteral(red: 0.5921568627, green: 0.5921568627, blue: 0.5921568627, alpha: 1)))
.lineSpacing(0.15)
}
Spacer()
}
}
Spacer()
Text("+1.75")
.foregroundColor(Color(#colorLiteral(red: 0.4431372549, green: 0.7490196078, blue: 0.3882352941, alpha: 1)))
.font(Font.custom("TPFrank-Medium", size: 14))
.lineSpacing(0.35)
}
Spacer()
HStack{
Spacer()
Text("168.02")
.foregroundColor(Color(#colorLiteral(red: 0.168627451, green: 0.1647058824, blue: 0.1647058824, alpha: 1)))
.font(Font.custom("TPFrank-Bold", size: 22))
.lineSpacing(0.55)
}
}.padding(EdgeInsets(top: 15, leading: 15, bottom: 15, trailing: 15))
}
}
}

Hopefully this helps, let me know if it works for you. I believe you were looking for .firstTextBaseline to align with the first Text.
struct Example_WidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack {
HStack(alignment: .firstTextBaseline) {
Image(systemName: "circle.fill")
.resizable()
.frame(width: 10, height:10)
.foregroundColor(Color.orange)
VStack (alignment: .leading){
Text("Wheat")
.font(.subheadline)
.fontWeight(.bold)
.allowsTightening(true)
Text("MATIF")
.font(.footnote)
.fontWeight(.bold)
.foregroundColor(Color.secondary)
.allowsTightening(true)
}
Spacer()
Text("+1.75")
.font(.footnote)
.fontWeight(.bold)
.foregroundColor(Color.green)
.allowsTightening(true)
}
Spacer()
HStack {
Spacer()
Text("168.02")
.font(.title)
.fontWeight(.bold)
}
}
.padding(.all, 10)
}
}

Set HStack alignment: .top
var body: some View {
if family == .systemSmall{
VStack{
HStack(alignment: .top) { //<<--Here
VStack{
HStack(alignment: .top) { //<<--Here

Related

Swift ScrollView goes on top again

I have a simple screen in which content are going on bottom so I use ScrollView on it issue is when I release scroll its going to top again. I need to replace scrollview to something Because I try with with List but that's not working properly with background image so I use Scrollview
struct signupView: View {
#StateObject var signUpViewModel = signupViewModel()
var body: some View {
ZStack{
GeometryReader { geo in
ScrollView {
VStack{
VStack{
Image("Untitled-2")
.resizable()
.frame(width: geo.size.width * 0.45, height: geo.size.width * 0.45)
}
.padding(.top, geo.size.height * 0.03)
HStack(spacing: 0){
VStack{
Text("Student")
.foregroundColor(signUpViewModel.isStudent ? Color("secondarycolor") : Color("authColorText"))
Rectangle()
.fill(signUpViewModel.isStudent ? Color("secondarycolor") : Color("authColorText"))
.frame(width: geo.size.width * 0.4, height: 2)
}
.onTapGesture {
signUpViewModel.isStudent = true
}
VStack{
Text("Facilitator")
.foregroundColor(!signUpViewModel.isStudent ? Color("secondarycolor") : Color("authColorText"))
Rectangle()
.fill(!signUpViewModel.isStudent ? Color("secondarycolor") : Color("authColorText"))
.frame(width: geo.size.width * 0.4, height: 2)
}
.onTapGesture {
signUpViewModel.isStudent = false
}
}
VStack{
VStack{
Spacer().frame(height: geo.size.height * 0.7)
TextField("", text: $signUpViewModel.nameField)
.modifier(PlaceholderStyle(showPlaceHolder: signUpViewModel.nameField.isEmpty,
placeholder: "Name"))
.padding()
.background(RoundedRectangle(cornerRadius: 50).fill(Color("primarycolorwithopacity")))
.foregroundColor(Color("authColorText"))
.foregroundColor(Color("authColorText")).font(Font.headline.weight(.medium))
.padding(.bottom, 10)
TextField("", text: $signUpViewModel.emailField)
.modifier(PlaceholderStyle(showPlaceHolder: signUpViewModel.emailField.isEmpty,
placeholder: "Email"))
.padding()
.background(RoundedRectangle(cornerRadius: 50).fill(Color("primarycolorwithopacity")))
.foregroundColor(Color("authColorText"))
.foregroundColor(Color("authColorText")).font(Font.headline.weight(.medium))
.padding(.bottom, 10)
SecureField("", text: $signUpViewModel.passwordField)
.modifier(PlaceholderStyle(showPlaceHolder: signUpViewModel.passwordField.isEmpty,
placeholder: "Password"))
.padding()
.background(RoundedRectangle(cornerRadius: 50).fill(Color("primarycolorwithopacity")))
.foregroundColor(Color("authColorText"))
.foregroundColor(Color("authColorText")).font(Font.headline.weight(.medium))
.padding(.bottom, 10)
SecureField("", text: $signUpViewModel.passwordRepeatField)
.modifier(PlaceholderStyle(showPlaceHolder: signUpViewModel.passwordRepeatField.isEmpty,
placeholder: "Repeat Password"))
.padding()
.background(RoundedRectangle(cornerRadius: 50).fill(Color("primarycolorwithopacity")))
.foregroundColor(Color("authColorText"))
.foregroundColor(Color("authColorText")).font(Font.headline.weight(.medium))
.padding(.bottom, 10)
TextField("", text: $signUpViewModel.countryField)
.modifier(PlaceholderStyle(showPlaceHolder: signUpViewModel.countryField.isEmpty,
placeholder: "Select Country"))
.padding()
.background(RoundedRectangle(cornerRadius: 50).fill(Color.black))
.foregroundColor(Color("authColorText"))
.foregroundColor(Color("authColorText")).font(Font.headline.weight(.medium))
.padding(.bottom, 10)
.overlay(
ZStack{if signUpViewModel.hasOptions {
Spacer().frame(height: 70)
VStack(alignment: .center) {
ForEach(signUpViewModel.countryoptions, id: \.self) {d in
Text(d).frame(maxWidth: .infinity).padding(8).onTapGesture {
signUpViewModel.countryField = d
signUpViewModel.hasOptions = false
}
Divider()
}
}.frame(maxWidth: .infinity).background(RoundedRectangle(cornerRadius: 6).foregroundColor(.white).shadow(radius: 4))
}
}.offset(y: 50)
, alignment: .topLeading)
.overlay(
Image("Untitled-42")
.resizable()
.foregroundColor(.white)
.frame(width: 15, height: 10).padding().padding(.bottom,2).onTapGesture {
signUpViewModel.hasOptions = !signUpViewModel.hasOptions
}
, alignment: .trailing).zIndex(1)
SecureField("", text: $signUpViewModel.passwordRepeatField)
.modifier(PlaceholderStyle(showPlaceHolder: signUpViewModel.passwordRepeatField.isEmpty,
placeholder: "Repeat Password"))
.padding()
.background(RoundedRectangle(cornerRadius: 50).fill(Color("primarycolorwithopacity")))
.foregroundColor(Color("authColorText"))
.foregroundColor(Color("authColorText")).font(Font.headline.weight(.medium))
.padding(.bottom, 10)
}.padding([.top, .leading, .trailing], 8).frame(height: 45)
}
}
.padding()
}
}
}.background(Image("Untitled-7").resizable()).edgesIgnoringSafeArea(.all)
}
}
When I release its going back to top. Don't get it why its happening on this. Or I need to use something else
One way of doing it is with introspect package, you can add the package here https://github.com/siteline/SwiftUI-Introspect.git
scrollView.bounces = false
Here's how I would do it with Introspect:
struct ContentView: View {
var body: some View {
ScrollView {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
}
.padding()
}.introspectScrollView { scrollView in
scrollView.bounces = false
}
}
}
also don't forget the imports
import Introspect

Responsive design swiftUI

How can I make sure that my UI looks good on different devices such as the iPhone 13 and the iPhone 8?
Here is my code that is unresponsive
It is just a simple layout
import SwiftUI
let grey = Color(red: 0.928, green: 0.928, blue: 0.928)
let i = 0
var columns: [GridItem] =
Array(repeating: .init(.flexible()), count: 3)
let categories: [Category] = [
.init(name: "Pasta", imageName: "square.and.arrow.up"),
.init(name: "Asian", imageName: "square.and.arrow.down.fill"),
.init(name: "Main", imageName: "rectangle.portrait.and.arrow.right"),
.init(name: "Quick", imageName: "pencil.slash"),
.init(name: "Veg", imageName: "scribble.variable"),
.init(name: "Dessert", imageName: "pencil.circle.fill"),
]
struct SearchView: View {
var body: some View {
VStack{
Text("Search For Recipes")
.font(.system(size: 35))
.padding(.top, 80)
.padding(.horizontal, -70)
.frame(width: 200, height: 10, alignment: .leading)
Spacer()
SearchBox()
.padding(.top, 50)
Spacer()
Recomend()
.padding(.top)
.padding(.leading, -100)
Spacer()
LazyVGrid(columns: columns){
ForEach((0...5), id: \.self) { _ in
MenuChoice()
}
}
.padding(20)
.padding(.bottom, 100)
.padding(.top)
.frame(maxWidth: .infinity)
.frame(height:500)
}
}
}
struct SearchBox: View {
var body: some View{
VStack{
HStack{
Image(systemName: "magnifyingglass")
Text("Search for recipes")
}
.frame(width: 200, height: 10, alignment: .leading)
.padding(.trailing, 60)
}
.frame(width: 300, height: 50)
.background(grey)
.cornerRadius(8)
.padding(.trailing, 50)
}
}
struct MenuChoice: View{
var body: some View{
ZStack{
ForEach(categories, id: \.self) { category in
VStack{
Spacer()
.frame(width: 100, height: 100)
.background(Color(red: 50, green: 207, blue: 255))
.cornerRadius(5)
.shadow(color: .init(.sRGB, white: 0.7, opacity: 1), radius: 4, x: 0.0, y: 2)
.padding(.bottom)
.overlay(
VStack(spacing: 8) {
Image(systemName: category.imageName)
.padding(.top, -10)
.font(.system(size: 30))
Text(category.name)
.foregroundColor(.black)
.font(.system(size: 20))
.padding(.top, 5)
}
)
}
}
}
}
}
struct Recomend: View{
var body: some View{
Button {
print("Image tapped!")
} label: {
ZStack{
RoundedRectangle(cornerRadius: 8)
.frame(width: 250, height: 50)
.foregroundColor(grey)
Text("See All Recomended Recipes")
.foregroundColor(Color.black)
}
}
}
}
struct SearchView_Previews: PreviewProvider {
static var previews: some View {
SearchView()
.previewDevice(PreviewDevice(rawValue: "iPhone 13"))
SearchView()
.previewDevice(PreviewDevice(rawValue: "iPhone 8"))
}
}
On the iPhone 13 it looks good but on the iPhone 8 it looks squashed and not good.
How can i make my code responsive for different screen heights/widths?
Following the comments you could go in this direction:
This adapts nicely and also is a lot less code.
struct ContentView: View {
var body: some View {
VStack{
Text("Search For Recipes")
.font(.system(size: 35))
.frame(maxWidth: .infinity, alignment: .leading)
SearchBox()
.padding(.bottom)
.padding(.bottom)
Recomend()
Spacer()
LazyVGrid(columns: columns, spacing: 18){
ForEach(categories) { category in
MenuChoice(category: category)
}
}
Spacer()
}
.padding()
}
}
struct SearchBox: View {
var body: some View{
VStack {
HStack{
Image(systemName: "magnifyingglass")
Text("Search for recipes")
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.background(grey)
.cornerRadius(8)
}
}
struct MenuChoice: View{
let category: Category
var body: some View{
VStack(spacing: 8) {
Image(systemName: category.imageName)
.padding(.top)
.font(.system(size: 30))
Text(category.name)
.foregroundColor(.black)
.font(.system(size: 20))
.padding(.bottom)
}
.frame(width: 100, height: 100)
.background(Color(red: 50, green: 207, blue: 255))
.cornerRadius(5)
.shadow(color: .init(.sRGB, white: 0.7, opacity: 1), radius: 4, x: 0.0, y: 2)
}
}
struct Recomend: View{
var body: some View{
Button {
print("Image tapped!")
} label: {
Text("See All Recomended Recipes")
.padding()
.foregroundColor(Color.black)
.frame(maxWidth: .infinity, alignment: .leading)
.background(grey)
.cornerRadius(8)
}
}
}

HStack background color blending into safe area

I am trying to prevent the background of my HStack from going into my safearea.
There is a ZStack that is setting the background color. I am using green just to be more defined for now.
struct AccountView: View {
var body: some View {
ZStack{
Color(.green)
.ignoresSafeArea()
VStack(spacing: 32){
HStack {
Image(systemName: "person")
.resizable()
.scaledToFill()
.frame(width: 64, height: 64)
.clipShape(Circle())
.padding(.leading)
VStack(alignment: .leading, spacing: 4) {
Text("First Last")
.font(.system(size: 18))
Text("Available")
.foregroundColor(.gray)
.font(.system(size: 14))
}
Spacer()
}
.frame(height: 80)
.background(Color("ItemBG"))
Spacer()
}
}
}
}
We need to use shape as background instead of pure-colour, then it is not spread outside.
Here is simplified demo. Tested with Xcode 13.2 / iOS 15.2
var body: some View {
VStack {
HStack {
Text("Hello")
}
.frame(maxWidth: .infinity, maxHeight: 80)
.background(Rectangle().fill(.yellow)) // << here !!
Spacer()
}
.background(Color.green.ignoresSafeArea())
}
I was able to figure it out...
I had to give by HStack a padding of 1 on the top. Apparently with IOS 15 if it touches the safe area it bleeds.
HStack {
Image(systemName: "person")
.resizable()
.scaledToFill()
.frame(width: 64, height: 64)
.clipShape(Circle())
.padding(.leading)
VStack(alignment: .leading, spacing: 4) {
Text("First Last")
.font(.system(size: 18))
Text("Available")
.foregroundColor(.gray)
.font(.system(size: 14))
}
Spacer()
}
.frame(height: 80)
.background(Color("ItemBG"))
.padding(.top, 1)

how to make a VStack span all space?

I'm trying to eliminate the space that the top stack covers, but as much as I need the image to cover the space where the time is shown and the battery is not successful, does anyone have any idea how to do it?
I leave a photo of what I want to eliminate, it is circled with yellow, I also leave my code.
import SwiftUI
struct LoginView: View {
#ObservedObject var LoginViewM:LoginViewModel
var body: some View {
GeometryReader{ geo in
NavigationView{
VStack(spacing:10){
topImage
.frame(width: geo.size.width, height: 270)
.padding(.bottom)
VStack{
usernameTextField
errorUsernameLabel
passwordTextField
errorPasswordLabel
}
.aspectRatio(contentMode: .fill)
Spacer(minLength: 10)
VStack{
buttonLogin
}
Spacer(minLength: 10)
VStack{
textInBottom
}
Spacer(minLength: 10)
}
.padding(.all)
.background(Color.black)
}
.padding(.all)
.background(Color.black)
.frame(width: geo.size.width, height: geo.size.height,alignment: .bottom)
}
.padding(.vertical)
.background(Color.black, alignment: .bottom)
.ignoresSafeArea(.all)
}
}
extension LoginView{
var topImage:some View{
Image("header2")
.resizable()
.overlay( ImageOverlay() , alignment: .center)
.background(Color.black)
}
var usernameTextField:some View{
HStack{
TextField("Phone number, username or email", text: $LoginViewM.username)
.font(.custom("Montserrat-Regular", fixedSize: 16.4))
.foregroundColor(.white)
.placeholder(Text("Phone number, username or email").padding().foregroundColor(.white), show: LoginViewM.password.isEmpty)
.background(Color.black)
// need to hide this icon
Image("menuCloseSmall")
.padding(.init(top: 0, leading: 0, bottom: 0, trailing: 14))
}
.overlay(RoundedRectangle(cornerRadius: 4).stroke(Color.gray, lineWidth: 3))
.clipShape(RoundedRectangle(cornerRadius: 4))
.padding()
}
var errorUsernameLabel:some View{
Text(" Hey you, no user found. Make sure you’ve provided the \n correct information.")
.foregroundColor(.redBlueParrot)
.font(.custom("Montserrat-Regular", size: 12.1))
}
var passwordTextField:some View{
HStack{
TextField("Password", text: $LoginViewM.password)
.font(.custom("Montserrat-Regular", fixedSize: 16.4))
.padding(.bottom)
.foregroundColor(.white)
.placeholder(Text("Password").padding().foregroundColor(.white), show: LoginViewM.username.isEmpty)
.background(Color.black)
Image("editShow")
.padding()
}
.overlay(RoundedRectangle(cornerRadius: 4).stroke(Color.gray, lineWidth: 3))
.clipShape(RoundedRectangle(cornerRadius: 4))
.padding()
}
var errorPasswordLabel:some View{
Text(" Incorrect password for \(LoginViewM.password). Please try again.")
.foregroundColor(.redBlueParrot)
.font(.custom("Montserrat-Regular", size: 12.1))
}
var buttonLogin:some View{
Button(action: {
}) {
Text("Log In")
}
.font(.custom("Montserrat-Medium", size: 16))
.foregroundColor(Color.ligthGray)
.frame(width: 174, height: 42, alignment: .center)
.overlay(RoundedRectangle(cornerRadius: 18)
.stroke(Color.gray, lineWidth: 1.5))
}
var textInBottom:some View{
HStack(spacing:5){
Text("Forgot")
.foregroundColor(.white)
.font(.custom("Montserrat-Regular", size: 16))
Button("password"){
}
.foregroundColor(.yellow)
.font(.custom("Montserrat-Regular", size: 16))
Text("or")
.foregroundColor(.white)
.font(.custom("Montserrat-Regular", size: 16))
Button("username"){
}
.foregroundColor(.yellow)
.font(.custom("Montserrat-Regular", size: 16))
}
.padding()
}
}
struct LoginView_Previews: PreviewProvider {
static var previews: some View {
LoginView(LoginViewM: LoginViewModel())
}
}
That gap is for navigation bar's title gap. You can set .navigationTitle("Example") to see that. If you want to hide it you need to set .navigationBarHidden(true).
NavigationView {
VStack(spacing: 10) {
// ...
}
.navigationBarHidden(true) // <-- Here
}

VStack Lower Than Expected SwiftUI

Even though in preview VStack looks promising when I run the app on the simulator or on the phone it appears lower than expected. You can see there is a big gap at the leading of the view from comparing the two images. I have also added layer's image to help you understand the problem. Which I can not understand obviously.
In preview
In the simulator
Layers
Code
var body: some View {
// NavigationView {
ZStack(alignment: .leading) {
Image("stepsTabBG")
.resizable()
.ignoresSafeArea(.all)
VStack {
HStack {
ScrollView(.horizontal) {
HStack(spacing: 30) {
ForEach(steps, id: \.id) { day in
Text("\(Calendar.current.dateComponents([.day], from: day.date).day!)")
.onTapGesture {
selectedDay = day
}
}
}
}
.frame(width: UIScreen.main.bounds.width / 2)
.padding(10)
Spacer()
}
CircularProgress(steps: selectedDay.count)
// Text(selectedDay.date, style: .date)
// .font(Font.custom("SFCompactDisplay", size: 14))
// .foregroundColor(Color(#colorLiteral(red: 0.4392156863, green: 0.4392156863, blue: 0.4392156863, alpha: 1)))
// .padding()
HStack {
Text("Min 500")
.padding()
.padding()
Text("Max 15000")
}
.font(Font.custom("SFCompactDisplay", size: 14))
.foregroundColor(Color(#colorLiteral(red: 0.4392156863, green: 0.4392156863, blue: 0.4392156863, alpha: 1)))
Text("BLA BLA BLA")
.font(Font.custom("SFCompactDisplay-Bold", size: 34))
.foregroundColor(Color(#colorLiteral(red: 0.4392156863, green: 0.4392156863, blue: 0.4392156863, alpha: 1)))
.padding()
Text("Bla bla bla")
.font(Font.custom("SFCompactDisplay", size: 14))
.foregroundColor(Color(#colorLiteral(red: 0.4392156863, green: 0.4392156863, blue: 0.4392156863, alpha: 1)))
Spacer()
}
.frame(maxWidth: .infinity, alignment: .topLeading)
}
// }
.onAppear() {
if let healthStore = healthStore {
healthStore.requestAuthorization { (success) in
if success {
healthStore.calculateSteps { (statisticsCollection) in
if let statisticsCollection = statisticsCollection {
updateUIFromStatistics(statisticsCollection)
}
}
}
}
}
}
}
}
I have one NavigationView in Welcome Page. I am using that NavigationView to be able to click sign in or sign up buttons.
struct WelcomeView: View {
#State var isLogin : Bool = false
#State var isRegister : Bool = false
var body: some View {
NavigationView {
VStack {
ZStack(alignment: .top) {
Image("Welcomebg")
.resizable()
// .aspectRatio(contentMode: .fit)
.edgesIgnoringSafeArea(.all)
Image("WelcomeImage")
.padding(.vertical, 30)
HStack {
Text("Walker")
Image("logo")
Text("App")
}
.font(Font.custom("SFCompactDisplay-Bold", size: 16))
.foregroundColor(.black)
}
Spacer()
Text("Title")
.font(Font.custom("SFCompactDisplay-Bold", size: 30))
Text("Description")
.font(Font.custom("SFCompactDisplay", size: 16))
.foregroundColor(.gray)
.padding(.vertical, 20)
Spacer()
NavigationLink("", destination: LoginView(), isActive: $isLogin)
Button(action: {
self.isLogin.toggle()
}) {
Text("GIRIS YAP")
.foregroundColor(.white)
.padding(.vertical,25)
.padding(.horizontal,UIScreen.main.bounds.width / 3)
.font(Font.custom("SFCompactDisplay-Bold", size: 14))
}
.background(Color("ColorOnboarding"))
.clipShape(Capsule())
.padding(.top,20)
HStack {
Text("HESABINIZ YOK MU?")
.foregroundColor(.gray)
NavigationLink("", destination: SignupView(), isActive: $isRegister)
Button(action: {
self.isRegister.toggle()
}) {
Text("UYE OL")
.foregroundColor(Color("ColorOnboarding"))
.padding(.vertical,25)
}
}
.font(Font.custom("SFCompactDisplay", size: 14))
}
.navigationBarHidden(true)
}
}
}
The empty space looks like an empty navigation bar title in automatic mode (which in this case is large).
Try setting .navigationBarTitleDisplayMode(.inline) in this view (this will not modify the parent view):
var body: some View {
ZStack(alignment: .leading) {
// ...
}
.navigationBarTitleDisplayMode(.inline)
}