How to : Format Swift UI Buttons - ios

I am figuring out Swift UI one step at a time. Here I have a VStack with a nested HStack setup holding some Buttons. I need to format them so they look a little less jumbled together.. what is the correct property to use? Is there a property I can use for the whole HStack view to handle this formatting automatically?
Simulator: https://gyazo.com/d566bc3ba8ea4de446f346d7098c1424
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
Color.init(hue: 0.2722, saturation: 0.89, brightness: 0.29, opacity: 1.0) .edgesIgnoringSafeArea(.all)
VStack {
HStack {
Button(action: {}){
Text("Today's List")
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
}
Button(action: {}){
Text("Tomorrow's List")
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
}
}
VStack {
HStack {
Button(action: {}){
Text("This Month")
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
}
Button(action: {}){
Text("Next Month")
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
}
}
}
VStack {
HStack {
Button(action: {}){
Text("3% Yeild Or Higher")
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
}
Button(action: {}){
Text("5% Yeild Or Higher")
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
}
}
}
VStack {
HStack {
Button(action: {}){
Text("App Help")
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
}
Button(action: {}){
Text("More Apps")
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
}
}
}
}
}
}
}
//Header
//Data
//Buttons
struct StrokeText: View {
let text: String
let width: CGFloat
let color: Color
var body: some View {
ZStack{
ZStack{
Text(text).offset(x: width, y: width)
Text(text).offset(x: -width, y: -width)
Text(text).offset(x: -width, y: width)
Text(text).offset(x: width, y: -width)
}
.foregroundColor(color)
Text(text)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
EDIT: What can I do to make the buttons take this shape? Formatted into more of a box layout.
image for reference: https://gyazo.com/e142e7358083987f3ebde48b66841f52

First off, you may want to refactor your code, clean it up. Say add a method that returns some View to generate Text objects for you. I haven't used SwiftUI much so it was interesting to me to go through your code for a couple of minutes.
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
Color.init(hue: 0.2722, saturation: 0.89, brightness: 0.29, opacity: 1.0) .edgesIgnoringSafeArea(.all)
VStack(alignment: .center, spacing: 8) {
HStack(alignment: .firstTextBaseline, spacing: 8) {
Button(action: {}){
self.newText("Today's List")
}
Button(action: {}){
self.newText("Tomorrow's List")
}
}
HStack(alignment: .firstTextBaseline, spacing: 8) {
Button(action: {}){
self.newText("This Month")
}
Button(action: {}){
self.newText("Next Month")
}
}
HStack(alignment: .firstTextBaseline, spacing: 8) {
Button(action: {}){
self.newText("% Yeild Or Higher")
}
Button(action: {}){
self.newText("5% Yeild Or Higher")
}
}
HStack(alignment: .firstTextBaseline, spacing: 8) {
Button(action: {}){
self.newText("App Help")
}
Button(action: {}){
self.newText("More Apps")
}
}
}
}
}
func newText(_ text: String) -> some View {
let text = Text(text)
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
return text
}
}
As you can see, you can remove the unnecessary VStacks, make a "Text factory" method that returns Text objects, utilize the stacks' alignment and spacing.
And here's your output:
Edit: You wanted to distribute the buttons equally? I took time to experiment, tinkering the views' frames.
You need to set the button's bg color instead of the text. And with that, you can refactor further your code by making a button factory method that returns some View.
struct ContentView: View {
var body: some View {
ZStack {
Color.init(hue: 0.2722, saturation: 0.89, brightness: 0.29, opacity: 1.0) .edgesIgnoringSafeArea(.all)
VStack(alignment: .center, spacing: 4) {
HStack(alignment: .center, spacing: 4) {
self.newButton(text: "Today's List") { }
self.newButton(text: "Tomorrow's List") { }
}
HStack(alignment: .firstTextBaseline, spacing: 4) {
self.newButton(text: "This Month") { }
self.newButton(text: "Next Month") { }
}
HStack(alignment: .firstTextBaseline, spacing: 4) {
self.newButton(text: "% Yeild Or Higher") { }
self.newButton(text: "5% Yeild Or Higher") { }
}
HStack(alignment: .firstTextBaseline, spacing: 4) {
self.newButton(text: "App Help") { }
self.newButton(text: "More Apps") { }
}
}
}
}
func newButton(text: String, action: #escaping () -> Void) -> some View {
let button = Button(action: action){
self.newText(text)
}.background(Color.green)
.cornerRadius(12)
.frame(minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: 100.0)
return button
}
func newText(_ text: String) -> some View {
let text = Text(text)
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(8)
.foregroundColor(Color.white)
.frame(maxWidth: .infinity, maxHeight: 100.0)
return text
}
}
And here's your new output:

For a start, you can add padding to the VStacks. And do a bit of refactoring for VStack.
struct ContentView: View {
var body: some View {
ZStack {
Color.init(hue: 0.2722, saturation: 0.89, brightness: 0.29, opacity: 1.0) .edgesIgnoringSafeArea(.all)
VStack {
CustomBlock(leading: "Today's List", trailing: "Tomorrow's List")
CustomBlock(leading: "This Month", trailing: "Next Month")
CustomBlock(leading: "3% Yeild Or Higher", trailing: "5% Yeild Or Higher")
CustomBlock(leading: "App Help", trailing: "More Apps")
}
}
}
}
struct CustomBlock: View {
var leading: String
var trailing: String
var body: some View {
VStack {
HStack {
Button(action: {}){
Text(leading)
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
}
Button(action: {}){
Text(trailing)
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
}
}
}.padding()
}
}

Related

iOS 15 Keyboard hides textfield

I am trying to create a messaging page layout but the keyboard hides the textfield and moves everything to the the top. I have looked at many tutorials online and replicated them exactly but none of them seem to work.
Here is all the code I have written:
struct MessagingPage: View {
var user: OfficialUserModel
#ObservedObject private var vm = TheUserModel()
#State var screenWidth = UIScreen.main.bounds.width
#State var imageSize = UIScreen.main.bounds.width / 12
#State var text = ""
#State var show = false
#Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView{
ZStack{
VStack{
HStack{
Spacer()
NavigationLink(destination: UserDisplayPage(user: user)) {
HStack{
WebImage(url: URL(string: user.imageURL ))
.resizable()
.aspectRatio( contentMode: .fill)
.frame(width: imageSize, height: imageSize
)
.cornerRadius(imageSize/2)
VStack(alignment: .leading){
Text(user.FullName)
.font(.body)
.fontWeight(.bold)
.foregroundColor(.white)
Text("\(user.City) , \(user.Country)")
.font(.caption)
.fontWeight(.semibold)
.foregroundColor(.white)
}
}
}
Spacer()
HStack{
Button{
presentationMode.wrappedValue.dismiss()
} label: {
Image(systemName: "chevron.down")
.font(.title)
.foregroundColor(.myWhite)
}
}
.padding(.trailing)
}
.padding(.top, 30)
.frame(height: 75)
.background(Color.mainBlack)
ScrollView{
Spacer()
ForEach(0..<2){ num in
HStack{
Spacer()
HStack{
Text("Hello \(user.firstName)")
.foregroundColor(.orange)
}
.padding()
.background(Color.mainBlack)
.cornerRadius(15)
.shadow(color: .orange, radius: 2)
}
.padding(.horizontal)
.padding(.top, 8)
}
HStack{Spacer()}
HStack{
HStack{
Text("\(user.FullName) is unable to recieve your message at this time. Please try again at a later time.")
.foregroundColor(.green)
}
.padding()
.background(Color.mainBlack)
.cornerRadius(15)
.shadow(color: .green, radius: 2)
Spacer()
}
.padding(.horizontal)
.padding(.top, 8)
HStack{Spacer()}
}
.background(Color.mainBlack)
ZStack{
HStack{
HStack{
HStack{
TextField("Say Something...", text: self.$text)
.placeholder(when: text.isEmpty) {
Text("Say Something...").foregroundColor(.myWhite.opacity(0.5))
}
.frame(width: screenWidth - 200, height: screenWidth/25)
.foregroundColor(.myCyan)
.accentColor(.myCyan)
.background(Color.mainBlack)
.textContentType(.emailAddress)
if !text.isEmpty{
Button{
print(text)
self.text = ""
}label: {
Image(systemName: "paperplane")
.foregroundColor(.myCyan)
.font(.system(size: 20))
}
}
else{
Button{
print("Show more options")
}label: {
Image(systemName: "plus")
.foregroundColor(.myCyan)
.font(.system(size: 20))
}
}
}
.frame(width: screenWidth - 150, height: screenWidth/25)
.padding()
.background(Color.mainBlack)
.cornerRadius(30)
.shadow(color: .myCyan, radius: 5)
.padding(.bottom,5)
}
}
.padding(.bottom, 50)
.frame(width: screenWidth)
}
}
}
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
.background(Color.mainBlack)
.navigationBarTitle("")
.navigationBarHidden(true)
}
}
}
I want the the textfield to move up as well as the messages in the scrollview but the top HStack with the user image and back/dismiss button should remain in place.
You really have a lot of code in there - and two reasons to clean it up:
To get a good answer, you need to post a minimal, reproducible example, which may also help you debug the code before posting it
Many lines of code are redundant or useless, for example:
Why using things like HStack{Spacer()} instead of Spacer(), which by the way is not needed in this context?
Why having a stack that has only another stack inside?
Coming to your issue, the problem is that one of the redundant modifiers is preventing the text file to move up, and this is the line to delete:
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
Why setting a frame that is as high and large as much as the screen? This is forcing the text field to stay at the bottom.
I tried to do some clean up, I bet some more can be done - see the code below, now the keyboard does not cover the text field anymore:
struct MessagingPage: View {
// Removed some lines of code to reproduce your issue
#State var screenWidth = UIScreen.main.bounds.width
#State var imageSize = UIScreen.main.bounds.width / 12
#State var text = ""
#State var show = false
#Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView{
// What is the purpose of this ZStack???
// ZStack{
VStack{
HStack{
Spacer()
NavigationLink(destination: Text("Hello")) {
Text("Top bar")
}
Spacer()
HStack{
Button{
presentationMode.wrappedValue.dismiss()
} label: {
Image(systemName: "chevron.down")
.font(.title)
.foregroundColor(.white)
}
}
.padding(.trailing)
}
.padding(.top, 30)
.frame(height: 75)
.background(Color.black)
ScrollView{
// All the views inside the Scrollview need to be inside a VStack
VStack {
// Why this spacer???
// Spacer()
ForEach(0..<2){ num in
HStack{
Spacer()
HStack{
Text("Hello username")
.foregroundColor(.orange)
}
.padding()
.background(Color.black)
.cornerRadius(15)
.shadow(color: .orange, radius: 2)
}
.padding(.horizontal)
.padding(.top, 8)
}
HStack{Spacer()}
HStack{
HStack{
Text("User is unable to receive your message at this time. Please try again at a later time.")
.foregroundColor(.green)
}
.padding()
.background(Color.black)
.cornerRadius(15)
.shadow(color: .green, radius: 2)
Spacer()
}
.padding(.horizontal)
.padding(.top, 8)
// Why a Spacer inside an HStack???
// HStack{Spacer()}
}
.background(Color.black)
}
// What is the purpose of this ZStack???
// ZStack{
// Why an HStack that has only an HStack inside??
// HStack{
// Why an HStack that has only an HStack inside??
// HStack{
HStack{
TextField("Say Something...", text: self.$text)
.frame(width: screenWidth - 200, height: screenWidth/25)
.foregroundColor(.cyan)
.accentColor(.cyan)
.background(Color.white)
.textContentType(.emailAddress)
if !text.isEmpty{
Button{
print(text)
self.text = ""
}label: {
Image(systemName: "paperplane")
.foregroundColor(.cyan)
.font(.system(size: 20))
}
}
else{
Button{
print("Show more options")
}label: {
Image(systemName: "plus")
.foregroundColor(.cyan)
.font(.system(size: 20))
}
}
}
// Are you sure you want set the height of this stack based on the width?
// .frame(width: screenWidth - 150, height: screenWidth/25)
.frame(width: screenWidth - 150)
.padding()
.background(Color.black)
.cornerRadius(30)
.shadow(color: .black, radius: 5)
.padding(.bottom,5)
// }
// }
.padding(.bottom, 50)
.frame(width: screenWidth)
// }
}
// }
// Why setting a frame that is high and large as much as the screen??
// .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
.background(Color.black)
.navigationBarTitle("")
.navigationBarHidden(true)
}
}
}

iOS: How to make my image logo at the top of the page SwiftUI

firstly I am really new to iOS development and Swift (2 weeks coming here from PHP :))
I am building my simple Login page and wondering how to make my Logo image at the top of the page. Also I am wondering if I have done my layout wrong to get the desired layout as in the screenshot. Would appreciate the help on this.
(Logo scribbled out in the screen shot needs to go to the top outside the white background)
Thanks
LoginView:
import SwiftUI
struct LoginView: View {
#State private var email: String = ""
#State private var password: String = ""
let verticalPaddingForForm = 40
var body: some View {
ZStack {
Color(red: 20/225.0 ,green: 22/225.0 , blue: 25/225.0)
VStack(spacing: CGFloat(verticalPaddingForForm)) {
Image("logo")
.resizable()
.scaledToFit()
Divider()
VStack {
TextField("Email", text: $email)
.padding(.horizontal, 30).padding(.top, 20)
Divider()
.padding(.horizontal, 30)
SecureField("Password", text: $password)
.padding(.horizontal, 30).padding(.top, 20)
Divider()
.padding(.horizontal, 30)
}
.background(Color(.white))
Text("Forgotten Password")
.foregroundColor(.blue)
.font(.system(size: 15))
Button(action: /*#START_MENU_TOKEN#*/{}/*#END_MENU_TOKEN#*/) {
Text("Login")
.padding()
.font(.system(size: 20))
}
.background(Color.black)
.foregroundColor(Color.white)
.cornerRadius(10)
.padding(.top, 0)
.padding(.bottom, 20)
}
.padding(.horizontal, CGFloat(verticalPaddingForForm))
.background(Color(.white))
VStack{
Spacer()
Button(action: /*#START_MENU_TOKEN#*/{}/*#END_MENU_TOKEN#*/) {
Text("Register")
.padding()
.font(.system(size: 40))
}
.background(Color(red: 20/225.0 ,green: 22/225.0 , blue: 25/225.0))
.foregroundColor(Color.white)
.cornerRadius(10)
.padding()
}
}.ignoresSafeArea()
};
}
ContentView:
import SwiftUI
struct ContentView: View {
var body: some View {
LoginView()
}
}
extension UIDevice {
var hasNotch: Bool {
let bottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
return bottom > 0
}
}
Try below code-:
Use a ZStack to give a backgroundColor to your view, and give that a modifier of .ignoresSafeArea().
Use VStack inside ZStack to layout other view components. I have done few modifications on my side.
struct LoginView: View {
#State private var email: String = ""
#State private var password: String = ""
let verticalPaddingForForm = 40
var body: some View {
ZStack() {
Color(red: 20/225.0 ,green: 22/225.0 , blue: 25/225.0).ignoresSafeArea()
VStack(spacing:15){
Image(systemName: “logo")
.resizable()
.scaledToFit()
.frame( height: 200)
.foregroundColor(Color.white)
.padding([.top],15)
VStack(spacing: CGFloat(verticalPaddingForForm)) {
VStack {
TextField("Email", text: $email)
.padding(.horizontal, 30).padding(.top, 20)
Divider()
.padding(.horizontal, 30)
SecureField("Password", text: $password)
.padding(.horizontal, 30).padding(.top, 20)
Divider()
.padding(.horizontal, 30)
}
.background(Color(.white))
.padding([.top])
Text("Forgotten Password")
.foregroundColor(.blue)
.font(.system(size: 15))
Button(action: {}) {
Text("Login")
.padding()
.font(.system(size: 20))
}
.background(Color.black)
.foregroundColor(Color.white)
.cornerRadius(10)
.padding([.bottom])
}
.background(Color(.white))
Spacer()
Button(action: {}) {
Text("Register")
.padding()
.font(.system(size: 40))
}
.foregroundColor(Color.white)
.cornerRadius(10)
}
}
};
}
struct Test1: View {
var body: some View {
LoginView()
}
}
extension UIDevice {
var hasNotch: Bool {
let bottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
return bottom > 0
}
}
You can use ZStack (alignment: .top) to set the alignment from the top. And then you can use a Spacer() at the end of the second VStack to expand the view.
The following code works for me. It's your code with little changes. Also, I suggest you create a subview to better organize your code, instead of writing all views within the same view.
import SwiftUI
struct LoginView: View {
#State private var email: String = ""
#State private var password: String = ""
let verticalPaddingForForm = 40
var body: some View {
ZStack (alignment: .top){
Color(red: 20/225.0 ,green: 22/225.0 , blue: 25/225.0)
VStack(spacing: CGFloat(verticalPaddingForForm)) {
Image(systemName: "gear")
.resizable()
.scaledToFit()
.frame(width: 100)
Divider()
VStack {
TextField("Email", text: $email)
.padding(.horizontal, 30).padding(.top, 20)
Divider()
.padding(.horizontal, 30)
SecureField("Password", text: $password)
.padding(.horizontal, 30).padding(.top, 20)
Divider()
.padding(.horizontal, 30)
}
.background(Color(.white))
Text("Forgotten Password")
.foregroundColor(.blue)
.font(.system(size: 15))
Button(action: /*#START_MENU_TOKEN#*/{}/*#END_MENU_TOKEN#*/) {
Text("Login")
.padding()
.font(.system(size: 20))
}
.background(Color.black)
.foregroundColor(Color.white)
.cornerRadius(10)
.padding(.top, 0)
.padding(.bottom, 20)
Spacer()
}
.padding(.horizontal, CGFloat(verticalPaddingForForm))
.background(Color(.white))
VStack{
Spacer()
Button(action: /*#START_MENU_TOKEN#*/{}/*#END_MENU_TOKEN#*/) {
Text("Register")
.padding()
.font(.system(size: 40))
}
.background(Color(red: 20/225.0 ,green: 22/225.0 , blue: 25/225.0))
.foregroundColor(Color.white)
.cornerRadius(10)
.padding()
}
}
}
}
struct LoginView_Previews: PreviewProvider {
static var previews: some View {
LoginView()
}
}
Just put Spacer() between Image("logo") and Divider() to push your logo to the top of the screen

LazyHStack cuts off content when scrolling

I have a LazyHStack nested in a ScrollView for showing some data from an API, but everytime I scroll it, the content is being cut off like this:
Here is the full struct:
struct MovieDetailView: View {
#EnvironmentObject private var navStack: NavigationStack
#ObservedObject var viewModel: MovieDetailVM
init(viewModel: MovieDetailVM) {
self.viewModel = viewModel
//UIScrollView.appearance().bounces = false
}
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .top) {
ScrollView(showsIndicators: false) {
VStack {
GeometryReader { (proxy: GeometryProxy) in
if proxy.frame(in: .global).minY <= 0 {
Image(uiImage: (UIImage(data: viewModel.backdropData) ?? UIImage(named: JWConfig.IMG_PLACEHOLDER_MOVIE_BACKDROP))!)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: proxy.size.width, height: 330)
} else {
Image(uiImage: (UIImage(data: viewModel.backdropData) ?? UIImage(named: JWConfig.IMG_PLACEHOLDER_MOVIE_BACKDROP))!)
.resizable()
.aspectRatio(contentMode: .fill)
.offset(y: -proxy.frame(in: .global).minY)
.frame(width: proxy.size.width, height: 330 + proxy.frame(in: .global).minY)
}
}
VStack(alignment: .leading) {
FDDivider(height: 20)
HStack {
Image(uiImage: (UIImage(data: viewModel.posterData) ?? UIImage(named: JWConfig.IMG_PLACEHOLDER_MOVIE_POSTER))!)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 120, height: 180)
.cornerRadius(20)
.clipped()
VStack(alignment: .leading) {
Text(viewModel.title)
.font(Font.custom(JWConfig.FONT_ARIAL, size: 25).weight(.semibold))
.foregroundColor(.SAPPHIRE)
.padding([.top, .bottom], 12)
.lineLimit(3)
HStack {
ForEach(viewModel.genres.prefix(2), id: \.ID) { genre in
JWBorderPill(text: genre.name, textSize: 12, textColor: .SAPPHIRE, borderColor: .DANUBE)
}
}
}.padding([.leading], 10)
Spacer()
}.padding([.leading, .trailing], 20)
FDDivider(height: 20)
HStack(spacing: 50) {
VStack {
Text("Release Date")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 15))
.foregroundColor(.gray)
.padding([.bottom], 1)
Text(viewModel.releaseDate)
.font(Font.custom(JWConfig.FONT_ARIAL, size: 18).weight(.semibold))
}
VStack() {
Text("Duration")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 15))
.foregroundColor(.gray)
.padding([.bottom], 1)
Text("\(viewModel.runtime)")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 18).weight(.semibold))
}
VStack() {
Text("Rating")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 15))
.foregroundColor(.gray)
.padding([.bottom], 1)
Text("\(String(format: "%.1f", viewModel.voteAverage)) / 10")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 18).weight(.semibold))
}
}.frame(width: geometry.size.width)
VStack(alignment: .leading) {
Text("Overview")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 23).weight(.semibold))
.foregroundColor(.SAPPHIRE)
.padding([.top, .bottom], 8)
Text(viewModel.overview)
.font(Font.custom(JWConfig.FONT_ARIAL, size: 17))
.foregroundColor(.gray)
}.padding([.leading, .trailing], 24)
VStack(alignment: .leading) {
Text("Production Companies")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 23).weight(.semibold))
.foregroundColor(.SAPPHIRE)
.padding([.top], 8)
ScrollView(.horizontal, showsIndicators: false) {
LazyHStack {
ForEach(viewModel.productionCompanies, id: \.ID) { company in
ProductionCompanyCell(viewModel: ProductionCompanyCellVM(company))
}
}
}
}.frame(height: 250)
.padding([.leading], 24)
FDDivider(height: 400)
}.frame(width: geometry.size.width)
.background(Color.white)
.cornerRadiusWithEachCorner(50, corners: [.topLeft, .topRight])
.offset(y: 180)
}
}
HStack {
JWBackButton()
Spacer()
}.padding(EdgeInsets(top: 50, leading: 25, bottom: 0, trailing: 0))
}
}.edgesIgnoringSafeArea(.all)
}
}
Is there something wrong with my code? Please let me know if you need the full body code, and I'm using Xcode 12.4 at the moment

How to: Layout in Swift UI using ZStack, VStack, HStack

I am trying to achieve this layout https://gyazo.com/9714f8f1bff98edb3365338563b28fe8 in Swift UI using V and H Stacks. So far I have achieved this https://gyazo.com/fec9ae229e59a41add6542c9a8ad31af. I haven't found the right approach just yet on what to do here for more manipulation. What properties would help me achieve the desired layout?
Update! Here is what I have figured out so far... Almost there.
UPDATED CODE AND CANVAS HERE: https://gyazo.com/d12b9a831f50c25f8f854dc2143c93dc
import SwiftUI
struct CustomBlock: View {
var leading: String
var trailing: String
var body: some View {
VStack {
HStack (alignment: .firstTextBaseline, spacing: 18){
Button(action: {}){
Text(leading)
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(25)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
.multilineTextAlignment(.center)
.fixedSize()
.frame(width: 150, height: 50, alignment: .center)
}
Button(action: {}){
Text(trailing)
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(25)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
.multilineTextAlignment(.center)
.fixedSize()
.frame(width: 150, height: 50, alignment: .center)
}
}
}.padding()
}
}
struct ContentView: View {
var body: some View {
ZStack {
Color.init(hue: 0.2722, saturation: 0.89, brightness: 0.29, opacity: 1.0) .edgesIgnoringSafeArea(.all)
VStack {
HStack {
StrokeText(text: "Dividend Chaser", width: 0.5, color: .black)
.foregroundColor(.white)
.font(.system(size: 45, weight: .bold))
}
ZStack {
RoundedRectangle(cornerRadius: 25, style: .continuous)
.fill( Color.init(red: 0.33, green: 0.56, blue: 0.27))
.frame(width: 350, height: 240)
}
CustomBlock(leading: "Today's List", trailing: "Tomorrow's List").lineLimit(2)
CustomBlock(leading: "This Month", trailing: "Next Month").lineLimit(2)
CustomBlock(leading: "3% Yeild Or Higher", trailing: "5% Yeild Or Higher").lineLimit(2)
CustomBlock(leading: "App Help", trailing: "More Apps").lineLimit(2)
}
}
}
}
Here is a demo of approach. Tested with Xcode 12 / iOS 14.
struct DemoButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.foregroundColor(.white).font(Font.body.bold())
.frame(maxWidth: .infinity).padding(.vertical, 10)
.background(RoundedRectangle(cornerRadius: 8).fill(Color.green))
.multilineTextAlignment(.center)
.frame(maxWidth: .infinity)
}
}
struct TestButtonsGridLayout: View {
var body: some View {
VStack(spacing: 1) {
HStack(spacing: 1) {
Button("Today's\nList") {}
Button("Tomorrow's\nList") {}
}
HStack(spacing: 1) {
Button("This\nMonth") {}
.overlay(RoundedRectangle(cornerRadius: 8)
.stroke(lineWidth: 4).foregroundColor(.white).padding(2))
Button("Next\nMonth") {}
}
// .. other same here
}.buttonStyle(DemoButtonStyle())
}
}
Note: a) button style can be applied per-button b) show overlay selection can be also moved in style and activated by some state variable.

How to: Implement Programatic Constraints

I am working on learning programmatic UI via Swift UI... Everything is fun so far I recommend anyone "afraid" of Swift UI should jump right in. Is anyone able to correctly constrain the code below? It only fits correctly in the Swift UI generated preview which was an iPhone 8 device. Any suggestions would be appreciated I have tried .aspectRatio to start but no good progress has been made yet.
struct ContentView: View {
var body: some View {
VStack {
HStack {
VStack(alignment: .leading) {
//Header
StrokeText(text: "App Name", width: 0.5, color: .black)
.foregroundColor(.white)
.font(.system(size: 45, weight: .bold))
.position(x: 188, y: 35)
.frame(maxWidth: .infinity, maxHeight: .infinity,
alignment: .center)
.background(Color.init(hue: 0.2722, saturation: 0.89, brightness: 0.29, opacity: 1.0)).edgesIgnoringSafeArea(.all)
//Data View
ZStack(alignment: .leading) {
Color.init(red: 0.33, green: 0.56, blue: 0.27)
.position(x: 188, y: -114)
.aspectRatio(contentMode: .fit)
//Todays List
VStack(alignment: .leading) {
Button(action: {}){
Text(" Today's List ")
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
.position(x: 85, y: 80)
}
}
//Tomorrows List
VStack(alignment: .leading) {
Button(action: {}){
Text("Tomorrow's List ")
.bold()
.font(Font.custom("Helvetica Neue", size: 21.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
.position(x: 285, y: 80)
}
}
//This Month
VStack(alignment: .leading) {
Button(action: {}){
Text(" This Month ")
.bold()
.font(Font.custom("Helvetica Neue", size: 22.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
.position(x: 85, y: 148)
}
}
//Next Month
VStack(alignment: .leading) {
Button(action: {}){
Text(" Next Month ")
.bold()
.font(Font.custom("Helvetica Neue", size: 22.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
.position(x: 289, y: 148)
}
}
//3% Yeild Or Higher
VStack(alignment: .leading) {
Button(action: {}){
Text(" 3% Yield or More")
.bold()
.font(Font.custom("Helvetica Neue", size: 17.6))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
.position(x: 85, y: 215)
}
}
//5% Yield Or Higher
VStack(alignment: .leading) {
Button(action: {}){
Text(" 5% Yield or More ")
.bold()
.font(Font.custom("Helvetica Neue", size: 17.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(12)
.position(x: 282, y: 215)
}
}
//App Help
VStack(alignment: .leading) {
Button(action: {}){
Text(" App Help ")
.bold()
.font(Font.custom("Helvetica Neue", size: 22.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.yellow)
.cornerRadius(12)
.position(x: 83, y: 283)
}
}
//More Apps
VStack(alignment: .leading) {
Button(action: {moreApps()}){
Text(" More Apps ")
.bold()
.font(Font.custom("Helvetica Neue", size: 22.0))
.padding(18)
.foregroundColor(Color.white)
.background(Color.red)
.cornerRadius(12)
.position(x: 285, y: 283)
}
}
}
}
}
}
}
}
struct StrokeText: View {
let text: String
let width: CGFloat
let color: Color
var body: some View {
ZStack{
ZStack{
Text(text).offset(x: width, y: width)
Text(text).offset(x: -width, y: -width)
Text(text).offset(x: -width, y: width)
Text(text).offset(x: width, y: -width)
}
.foregroundColor(color)
Text(text)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

Resources