Confusion with passing data to another view. SwiftUI - ios

I'm building this project, and I have two views: MenuView and CreateBoardView.
What I want to achieve is to be able to create a new board on the menu screen, and so that the data I'd enter (board name and description) would be shown in the new created box. But I'm really confused about how to make it.
Here's the code for my MenuView:
import Foundation
import SwiftUI
struct MenuView: View {
#EnvironmentObject var AboutBoard: BoardModel
var body: some View {
ZStack {
VStack {
HStack(spacing: 80) {
VStack(alignment: .leading, spacing: 10) {
Text("Hey,")
.font(Font.custom("Montserrat", size: 25))
Text("username")
.font(Font.custom("Montserrat-Bold", size: 30))
}
Image("Profile")
.resizable()
.scaledToFit()
.frame(width: 100, height: 100, alignment: .trailing)
}
.padding(.top, 30)
HStack(alignment: .top, spacing: 30) {
VStack(alignment: .leading) {
Text("New board")
.font(Font.custom("Montserrat-Bold", size: 25))
.foregroundColor(.white)
Text("Create with your friends")
.font(Font.custom("Montserrat", size: 18))
.foregroundColor(.white)
.padding(.bottom, 10)
NavigationLink(destination: CreateBoardView()) {
Text("Create board")
}.padding(15)
.frame(width: 180, height: 50, alignment:.center)
.background(LinearGradient(gradient: Gradient(colors: [(Color.init(red: 0.58, green: 0.12, blue: 0.68)), (Color.init(red: 0.58, green: 0.12, blue: 0.68))]), startPoint: .topLeading, endPoint: .bottomTrailing), in: RoundedRectangle(cornerRadius: 20))
.foregroundColor(.white)
.scaledToFill()
.font(Font.custom("Montserrat-Bold", size: 20))
.shadow(color: Color.init(red: 0.28, green: 0.00, blue: 0.34, opacity: 0.2), radius: 5, x: 0, y: 7)
.navigationBarBackButtonHidden(true)
.navigationBarTitleDisplayMode(.inline)
}
Image("Forum")
.resizable()
.scaledToFit()
.frame(width: 50, height: 50)
}
.frame(width: 350, height: 180, alignment: .center)
.background(LinearGradient(gradient: Gradient(colors: [(Color.init(red: 0.88, green: 0.33, blue: 1.00)), (Color.init(red: 0.69, green: 0.05, blue: 1.00))]), startPoint: .topLeading, endPoint: .bottomTrailing), in: RoundedRectangle(cornerRadius: 30))
HStack(spacing: 150) {
Text("Your boards")
.font(Font.custom("Montserrat-Bold", size: 20))
Text("See all")
.font(Font.custom("Montserrat", size: 15))
}.padding(.top, 20)
HStack(spacing: 30) {
ForEach(0..<10) {_ in
Text(AboutBoard.BoardName)
.font(Font.custom("Montserrat", size: 20))
Text(AboutBoard.BoardDescription)
.font(Font.custom("Montserrat", size: 20))
}
.frame(width: 250, height: 210)
.background(
Image("Board-Holder")
.resizable()
.scaledToFit()
.frame(width: 250, height: 210)
)
}
Spacer()
}
}
.environmentObject(BoardModel())
}
}
struct MenuPagePreview: PreviewProvider {
static var previews: some View {
MenuView()
}
}
And my CreateBoardView:
import Foundation
import SwiftUI
struct CreateBoardView: View {
#StateObject var BoardInfo = BoardModel()
#State private var SetDeadline = false
#State private var ShowMenu = false
var body: some View {
ZStack {
VStack {
Text("Create a new board")
.font(Font.custom("Montserrat-Medium", size: 30))
.padding(.bottom, 50)
.padding(.top, 50)
Text("Enter your board's name")
.font(Font.custom("Montserrat", size: 20))
.padding(.bottom, 30)
TextField("Board name", text: $BoardInfo.BoardName)
.padding(15)
.frame(width: 350, height: 60, alignment:.center)
.background(RoundedRectangle(cornerRadius: 20).fill(.white))
.scaledToFill()
.font(Font.custom("Montserrat", size: 20))
.shadow(color: Color.init(red: 0.28, green: 0.00, blue: 0.34, opacity: 0.2), radius: 15, x: 0, y: 7)
.padding(.bottom, 25)
.disableAutocorrection(true)
Text("Add board description")
.font(Font.custom("Montserrat", size: 20))
.padding(.bottom, 30)
TextField("Board description", text: $BoardInfo.BoardDescription)
.padding(15)
.frame(width: 350, height: 60, alignment:.center)
.background(RoundedRectangle(cornerRadius: 20).fill(.white))
.scaledToFill()
.font(Font.custom("Montserrat", size: 20))
.shadow(color: Color.init(red: 0.28, green: 0.00, blue: 0.34, opacity: 0.2), radius: 15, x: 0, y: 7)
.padding(.bottom, 25)
.disableAutocorrection(true)
NavigationLink(destination: MenuView()) {
Text("Create board")
}
.padding(15)
.frame(width: 350, height: 60, alignment:.center)
.background(LinearGradient(gradient: Gradient(colors: [(Color.init(red: 0.72, green: 0.26, blue: 0.67)), (Color.init(red: 0.47, green: 0.16, blue: 0.74))]), startPoint: .topLeading, endPoint: .bottomTrailing), in: RoundedRectangle(cornerRadius: 20))
.foregroundColor(.white)
.scaledToFill()
.font(Font.custom("Montserrat-Bold", size: 20))
.shadow(color: Color.init(red: 0.28, green: 0.00, blue: 0.34, opacity: 0.2), radius: 15, x: 0, y: 7)
.padding(.bottom, 25)
.sheet(isPresented: $ShowMenu){
MenuView()
}
}
}
}
}
struct CreateBoardPreview: PreviewProvider {
static var previews: some View {
CreateBoardView()
}
}
I also have this BoardModel but I don't know if I'm even doing it right.
import Foundation
import SwiftUI
class BoardModel: ObservableObject {
static let shared = BoardModel()
#Published var BoardName: String = ""
#Published var BoardDescription: String = ""
}
So how to make it such way so that the CreateBoardView would take the input and then have it stored and shown in the menu?
Thanks.

Related

How to place Image(plus) to top right of custom frame in swiftui?

I am trying to put a plus sign in a tight frame at a very specific spot (at the right of the title text) but i cannot seem to do so
Do you know how I can do so?
var body: some View {
VStack {
HStack {
Image(systemName: "plus")
VStack(alignment: .leading, spacing: 15) {
Text("This Month's Goal")
.bold()
.frame(width: 300, height: 10, alignment: .center)
Text("100 out of 2000")
.frame(width: 300, height: 10, alignment: .center)
//replace percent with percent and code percent to move with data
ProgressBarView(width: 300, height: 30, percent: 50, color1: Color(#colorLiteral(red: 0.01413772535, green: 0.2225477993, blue: 0.9861308932, alpha: 1)), color2: Color(#colorLiteral(red: 0.5605781674, green: 0.9172690511, blue: 0.8047055602, alpha: 1)))
}
Spacer()
}
.padding()
}
.background(Color.white)
.frame(width: 350, height: 120, alignment: .center)
.cornerRadius(25.0)
}
This is what it looks like right now, Somewhere in the circled spot in the same frame would be ideal.
struct TestView: View {
var body: some View {
VStack {
HStack {
Image(systemName: "plus")
VStack(alignment: .leading, spacing: 15) {
ZStack(alignment: .trailing) {
VStack {
Text("This Month's Goal")
.bold()
.frame(width: 300, height: 10, alignment: .center)
Text("100 out of 2000")
.frame(width: 300, height: 10, alignment: .center)
}
Button(
action: { },
label: { Image(systemName: "plus.circle") }
)
}
//replace percent with percent and code percent to move with data
ProgressBarView(width: 300, height: 30, percent: 50, color1: Color(#colorLiteral(red: 0.01413772535, green: 0.2225477993, blue: 0.9861308932, alpha: 1)), color2: Color(#colorLiteral(red: 0.5605781674, green: 0.9172690511, blue: 0.8047055602, alpha: 1)))
}
Spacer()
}
.padding()
}
.background(Color.white)
.frame(width: 350, height: 120, alignment: .center)
.cornerRadius(25.0)
}
}
Result:
Incidentally, your progress bar might look better if you calculate the width of the completion bar (the blue-green overlay) as height + (width - height) * percent / 100 instead of as width * percent / 100.

UserDefaults Text / SwiftUI

When I click the "Update" button, I want the text view to save the text used in the User Defaults.
I could not. Do you know how? Can you edit the codes?
After updating, I want the checkbox to appear, but first I need to set user defaults.
Struct ContentView: View{
#State private var profilName = ""
#State private var profilSurname = ""
var body: some View{
ZStack{
VStack{
TextField("Name", text: $profilName)
.frame(height: 60)
.padding([.leading, .trailing], 20)
.foregroundColor(.white)
.font(Font.system(size: 30, design: .default))
.multilineTextAlignment(.center)
.accentColor(Color.white)
.overlay(RoundedRectangle(cornerRadius:30)
.stroke(Color(#colorLiteral(red: 0.5411764706, green:
0.4549019608, blue: 0.2823529412, alpha: 1)), lineWidth: 1)).padding(.horizontal, 50)
TextField("Surname", text: $profilSurname)
.frame(height: 60)
.padding([.leading, .trailing], 20)
.foregroundColor(.white)
.font(Font.system(size: 30, design: .default))
.multilineTextAlignment(.center)
.accentColor(Color.white)
.overlay(RoundedRectangle(cornerRadius:30)
.stroke(Color(#colorLiteral(red: 0.5411764706, green: 0.4549019608, blue: 0.2823529412, alpha: 1)), lineWidth: 1)).padding(.horizontal, 50)
Button(action: {
}, label: {
Text("Update")
.frame(width:300 , height: 40)
.padding(10)
.font(Font.system(size: 30, weight: .medium, design: .serif))
.foregroundColor(.white)
.background(RoundedRectangle(cornerRadius: 45))
.foregroundColor(.init(red: 45 / 255, green: 0 / 255, blue: 112 / 255))
})
}
}
}
}
You can save textfield content by simply calling user defaults in button action
Button(action: {
UserDefaults.standard.set(profilSurname, forKey: "Key")
}
To retrieve text from user defaults when app starts load user defaults data in init function like below
struct ContentView: View{
#State private var profilName = ""
#State private var profilSurname = ""
init() {
self._profilSurname = State(initialValue: UserDefaults.standard.object(forKey: "Key") as? String ?? "")
}
var body: some View{
struct ContentView: View{
#State private var profilName = ""
#State private var profilSurname: String = UserDefaults.standard.string(forKey: "Key") ?? ""
var body: some View{
ZStack{
VStack{
TextField("Name", text: $profilName)
.frame(height: 60)
.padding([.leading, .trailing], 20)
.foregroundColor(.black)
.font(Font.system(size: 30, design: .default))
.multilineTextAlignment(.center)
.accentColor(Color.white)
.overlay(RoundedRectangle(cornerRadius:30)
.stroke(Color(#colorLiteral(red: 0.5411764706, green:
0.4549019608, blue: 0.2823529412, alpha: 1)), lineWidth: 1)).padding(.horizontal, 50)
TextField("Surname", text: $profilSurname)
.frame(height: 60)
.padding([.leading, .trailing], 20)
.font(Font.system(size: 30, design: .default))
.multilineTextAlignment(.center)
.accentColor(Color.white)
.overlay(RoundedRectangle(cornerRadius:30)
.stroke(Color(#colorLiteral(red: 0.5411764706, green: 0.4549019608, blue: 0.2823529412, alpha: 1)), lineWidth: 1)).padding(.horizontal, 50)
Button(action: {
UserDefaults.standard.set(profilSurname, forKey: "Key")
}, label: {
Text("Update")
.frame(width:300 , height: 40)
.padding(10)
.font(Font.system(size: 30, weight: .medium, design: .serif))
.foregroundColor(.white)
.background(RoundedRectangle(cornerRadius: 45))
.foregroundColor(.init(red: 45 / 255, green: 0 / 255, blue: 112 / 255))
})
}
}
}
}
This will be the updated code.
Button(action: {
// This is the action section. You can add your code here
UserDefaults.standard.set($profilSurname.wrappedValue, forKey: "surnname")
}, label: {
Text("Update")
.frame(width:300 , height: 40)
.padding(10)
.font(Font.system(size: 30, weight: .medium, design: .serif))
.foregroundColor(.white)
.background(RoundedRectangle(cornerRadius: 45))
.foregroundColor(.init(red: 45 / 255, green: 0 / 255, blue: 112 / 255))
})
Getting stored values form Userdefaults
let surnName = UserDefaults.standard.object(forKey: "surnname") as? String ?? ""

NavigationBar Color / Swift

I created the NavigationBar, but when I perform .inline, I cannot make the background color completely black.
Do you have any information on this?
I could not find how to do it.
I would be glad if you could fix this.
likewise tabBar also have this color problem
I tried different ways but got the same result in all of them.
init() {
//Tabbar Renk bölümü
UITabBar.appearance().barTintColor = UIColor.black
UINavigationBar.appearance().barTintColor = .black
}
HStack(spacing: 10) {
NavigationLink(destination: PicturePage()) {
Text("Picture")
.font(.title)
.foregroundColor(Color(#colorLiteral(red: 0.7239437103, green: 0.2440972626, blue: 0.4727140069, alpha: 1)))
.frame(maxWidth: geometry.size.width)
.frame(height: geometry.size.height / 5)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color(#colorLiteral(red: 0.8527825475, green: 0.821311295, blue: 0.8959596753, alpha: 1)), lineWidth: 3)
)
}.navigationBarTitle(Text("Geri"),displayMode: .inline)
.navigationBarHidden(true)
}
struct PicturePage: View {
//3-1//
var body: some View {
GeometryReader { geometry in
Color.black.edgesIgnoringSafeArea(.all)
VStack {
VStack {
Text("Picture")
.font(.system(size: 60))
.frame(height: geometry.size.height / 10)
.foregroundColor(.init(red: 45 / 255, green: 0 / 255, blue: 112 / 255))
Spacer().frame(height: geometry.size.height / 15)
}
VStack {
Text("Merhaba").frame(width: geometry.size.width, height: geometry.size.height / 10)
.foregroundColor(Color.white)
}
VStack {
Image("AstroGirl").resizable()
.aspectRatio(contentMode: .fit)
.frame(width: geometry.size.width, height: geometry.size.height / 3)
Spacer().frame(height: geometry.size.height / 15)
}
// This `HStack` is changed
HStack(spacing: 30) {
ForEach(0 ..< 3) { _ in
CircleView()
.frame(width: geometry.size.width / 5, height: geometry.size.height / 10)
.shadow(color: Color.yellow, radius: 10, x: 0, y: 0)
}
}
Spacer().frame(height: geometry.size.height / 10)
VStack {
Button(action: {}, label: {
Text("Gönder")
.frame(width: geometry.size.width / 3, height: 50)
.padding(10)
.font(Font.system(size: 30, weight: .medium, design: .serif))
.foregroundColor(.white)
.background(RoundedRectangle(cornerRadius: 30))
.foregroundColor(.init(red: 45 / 255, green: 0 / 255, blue: 112 / 255))
})
}
}
}
}
}

TextEditor positioning in SwiftUI

I added a text editor but couldn't center its position,
The text editor has shifted to the right as shown in the picture.
Sorry, I just noticed that the whole page has shifted to the right.
I don't know what I'm doing wrong. You can fix this.
I want it to stand in the middle.
struct TextSend: View {
#State private var inputText = ""
var body: some View {
GeometryReader { geometry in
VStack {
HStack {
Text("Picture")
.font(.system(size: 60))
.frame(width: geometry.size.width, height: geometry.size.height / 10)
.foregroundColor(.init(red: 45 / 255, green: 0 / 255, blue: 112 / 255))
Spacer().frame(height: geometry.size.height / 5)
}
VStack {
Text("Hi").frame(width: geometry.size.width, height: geometry.size.height / 10)
}
HStack {
ForEach(0 ..< 3) { _ in
CircleView()
.frame(width: geometry.size.width / 5, height: geometry.size.height / 10)
.shadow(radius: 10)
}
}
VStack {
TextEditor(text: $inputText) .frame(width: geometry.size.width, height:geometry.size.height / 3) .overlay(RoundedRectangle(cornerRadius: 30).stroke(Color.init( red: 45/255, green: 0/255, blue: 112/255), lineWidth: 1)).lineSpacing(10)
.autocapitalization(.words)
.disableAutocorrection(true)
.padding()
}
Spacer().frame(height: geometry.size.height / 15)
VStack {
Button(action: {}, label: {
Text("Gönder")
.frame(width: geometry.size.width / 3, height: 50)
.padding(10)
.font(Font.system(size: 30, weight: .medium, design: .serif))
.foregroundColor(.white)
.background(RoundedRectangle(cornerRadius: 30))
.foregroundColor(.init(red: 45 / 255, green: 0 / 255, blue: 112 / 255))
})
}
}
}
}
}
Remove frame(width: geometry.size.width from everywhere used, as such hardcoding breaks layout. Try to use geometry always only for calculable values.
Here is fixed parts (tested with Xcode 12.1 / iOS 14.1)
HStack {
Text("Picture")
.font(.system(size: 60))
.frame(height: geometry.size.height / 10) // << !!
.foregroundColor(.init(red: 45 / 255, green: 0 / 255, blue: 112 / 255))
Spacer().frame(height: geometry.size.height / 5)
}
VStack {
Text("Hi").frame(height: geometry.size.height / 10) // << !!
}
// ... other code
VStack {
TextEditor(text: $inputText)
.frame(height:geometry.size.height / 3) // << !!
.overlay(RoundedRectangle(cornerRadius: 30).stroke(Color.init( red: 45/255, green: 0/255, blue: 112/255), lineWidth: 1)).lineSpacing(10)
.autocapitalization(.words)
.disableAutocorrection(true)
.padding()
}
You need to add frame to your first child inside the GeometryReader which is VStack in your case
VStack{
}.frame(width:geometry.size.width , height: geometry.size.height)
ps : you can make it : geometry.size.width - 10 for example , for padding purpose

SwiftUI how do I perfectly align on of my object in my HStack in the center of my screen?

I am trying to figure out how to align my "Create" Button in the exact middle of my screen with my "share" button to the right of my centered "Create" Button, without using arbitrary numbers.
HStack (spacing: 40) {
Text("Create")
.fontWeight(.bold)
.frame(width: 185, height: 40, alignment: .center)
.cornerRadius(50)
.overlay(
Capsule(style: .circular)
.stroke(Color(red: 0.879, green: 0.369, blue: 0, opacity: 1), style: StrokeStyle(lineWidth: 2)))
Image(systemName:"square.and.arrow.up")
.resizable()
.frame(width: 25, height: 30)
.font(Font.title.weight(.light))
} .foregroundColor(Color(red: 0.879, green: 0.369, blue: 0, opacity: 1))
Here is how I would do it (no hardcoded numbers)
HStack {
Spacer()
Text("Create")
.fontWeight(.bold)
.frame(width: 185, height: 40, alignment: .center)
.cornerRadius(50)
.overlay(
Capsule(style: .circular)
.stroke(Color(red: 0.879, green: 0.369, blue: 0, opacity: 1), style: StrokeStyle(lineWidth: 2)))
Spacer()
.overlay(
HStack {
Image(systemName:"square.and.arrow.up")
.resizable()
.frame(width: 25, height: 30)
.font(Font.title.weight(.light))
Spacer()
}
.padding(.leading) // << here can be any distance to center button
)
}
.foregroundColor(Color(red: 0.879, green: 0.369, blue: 0, opacity: 1))
There's probably a better way, but this will do it. It just adds the action button as an overlay to the main Create button. But by using a PreferenceKey, the action button knows the size (and origin) of the Create button and can offset itself accordingly. Using rectangles here to represent the buttons so it's easier to read.
struct BoundsPreferenceKey: PreferenceKey {
typealias Value = CGRect
static var defaultValue: CGRect = .zero
static func reduce(value: inout CGRect, nextValue: () -> CGRect) {
value = value.union(nextValue())
}
}
struct CenteredView: View {
let spacing: CGFloat = 40
var body: some View {
HStack {
Rectangle().fill(Color.blue)
.frame(width: 185, height: 40)
.preference(key: BoundsPreferenceKey.self, value: CGRect(origin: .zero, size: CGSize(width: 185, height: 40)))
.overlayPreferenceValue(BoundsPreferenceKey.self) { rect in
Rectangle().fill(Color.green)
.frame(width: 25, height: 30)
.offset(x: rect.size.width/2 + self.spacing, y: 0)
}
}
}
}
You could use GeometryReader to avoid specifying the height and width, but you need to specify it for the frame anyway.
Alternatively, look at a custom alignment guide.
It could be like this:
HStack{
Spacer()
Spacer().overlay(Button("Create"){}.padding(10).border(Color.blue, width: 3.0))
Spacer()
}

Resources