Swift: Changing the length of a ForEach loop and updating the view during use - swift

I've seen some similar questions but I'm still struggling to sort this one out. I am making a word game that involves typing a word between 4-6 letters long. The game board is generated in its own view file using a ForEach loop that currently iterates 6 times. On the 3rd round, I want to change the game board to be 7 spaces long instead of 6, and during the final round I want to make the game board 8 spaces long. Initially I tried setting the upper limit to equal the value of a variable or return value of a function and it works "in theory" but depending on what I try, either the game crashes on round 3 or the board just stays 6 spaces long.
I've included the GuessView code as it exists below
struct GuessView: View {
#Binding var guess: Guess
var body: some View {
HStack(spacing: 3) {
ForEach(0...5, id: \.self) { index in
Text(guess.guessLetters[index])
.foregroundColor(.primary)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 50, alignment: .center)
.background(Color.systemBackground)
.font(.system(size: 35, weight: .heavy))
//.border(Color(.secondaryLabel))
.overlay(
Rectangle()
.frame(height: 3)
.foregroundColor(.pink),
alignment: .bottom
)
}
}
}
}
The majority of the logic exits in a Swift file that called WordDataModel. It's an Oberservable Object and essentially contains a class with all of the relevant functions and variables that I pull from. So for instance, when I was trying to make the upper limit of the ForEach loop a variable that changed I had that variable stored/changing in the WordDataModel function and had GuessView looking like this
WordDataModel:
var boardLength: Int = 5
GuessView:
ForEach(0...dm.boardLength, id: \.self) { index in
Text(guess.guessLetters[index])
.foregroundColor(.primary)
But when I update the value in WordDataModel or try to bring the variable over using #Binding or #State it doesn't seem to work.
Hopefully I've provided enough data, any suggestions are much appreciated thank you!

Use #Published for a property, it creates a publisher for type.
#Published var boardLength: Int

Related

How do I access a custom color that is part of a struct?

I'm trying to assign a color to the following button that I gave to a member of a struct previously, yet I keep getting compiler errors. Here's what my code is:
var sampleGameView: gameViewState = gameViewState(
Outs: 2,
Balls: 1,
Strikes: 1,
Runner1: true,
Runner2: true,
Runner3: false,
HomeTeam: "MIA",
AwayTeam: "ATL",
HomeTeamColor: Color("SampleGameViewATL"),
AwayTeamColor: Color("SampleGameViewMIA"),
InningTop: false,
InningNumber: 4,
HomeTeamScore: 0,
AwayTeamScore: 1,
CurrentBatterFirst: "Starling",
CurrentBatterLast: "Marte",
CurrentPitcherFirst: "Max",
CurrentPitcherLast: "Fried"
)
As you can see, sampleGameView has two Color properties. However, when I try to assign them to a Button like so, I get errors:
Button(action: {}) {
VStack {
Text(sampleGameView.CurrentPitcherFirst)
Text(sampleGameView.CurrentPitcherLast)
.fontWeight(.bold)
.textCase(.uppercase)
}
.padding()
}
.foregroundColor(.white)
.frame(width: 170, height: 75)
.background(Color("sampleGameView.HomeTeamColor")) // error is on this line
.cornerRadius(10)
I've tried accessing the color without quotes at all, and also with string interpolation, neither of which works :/
Can someone tell me what the correct syntax is for a situation like this? Thank you!
Remove double quotes and Color object constructor.
.background(sampleGameView.HomeTeamColor)
Note: Struct and Class name start with capital character and properties start with small character.

How to create two column list in swiftUI using List view?

I am new to SwiftUI. I need to create a list that is displaying in two columns. Its more likely a collectionView with two items per row. The condition is I need to create it using "List" because I need to add a "drag and drop to reorder" functionality on this list.
So far I have implemented it using HStack and VStack but in this case there is no option to drag and reorder the list.
Here is the code I have done so far:
ZStack{
Button(action: {
}) {
HStack{
Image(systemName: "person.crop.circle.fill")
Text(font)
.font(.system(size: 13 ))
.foregroundColor(.black)
.frame(minWidth: UIScreen.main.bounds.size.width/4, maxWidth: UIScreen.main.bounds.size.width/4)
.padding(.horizontal)
}
.padding(10)
}
.foregroundColor(Color.black)
.background(Color.white)
.cornerRadius(8)
.background(
RoundedRectangle(cornerRadius: 5)
.fill(Color.white)
.shadow(color: .gray, radius: 2, x: 0, y: 2)
)
}
My question is: how can I create collection view type of two column list in SwiftUI Using List??
IF my implementation using HStack and Stack sounds good then: Is there any way to implement drag and drop to reorder list functionality on it??
Using LazyVGrid is not possible for me because my requirement is ios13.
Any help will be appreciated.
Thanks!!
Update:
I solved it using UICollectionView wrapped in UIViewRepresentable in swiftui.

SwiftUI Form Picker with text and Image

I am trying to create a form picker that shows the currently selected image resource at the top level and when the user selects it to show the detail, I want it to show all of the image resources available.
Here is the relevant section of code:
Picker("Background image:", selection: $task.background) {
ForEach(0 ..< backgroundImages.count) {
Image("Background\($0)").resizable().frame(width: 100, height: 35, alignment: .center)
Text("Background\($0)")
}
}
The problem with this is that in the detail screen I get:
The image is blank and the image and text appear on 2 different rows.
I have tried wrapping the Image and Text lines in an HStack, but that gives a compile time error on some other line. Any suggestions would be helpful.
The following should compile & work well (tested with replaced system images, Xcode 11.2)
Picker("Background image:", selection: $task.background) {
ForEach(0 ..< backgroundImages.count) { i in
HStack {
Image("Background\(i)").resizable().frame(width: 100, height: 35, alignment: .center)
Text("Background\(i)")
}
}
}

SwiftUI beta 7: Trigger `List` to scroll when item added?

Using Xcode 11 beta 7 and Catalina beta 19A536g (6?)
In my SwiftUI app I have a simple view with a list. Below the list I have a button to add items to the list.
After having added some items, the newly added items are not visible, since they are outside the content size of the list.
var body: some View {
NavigationView {
VStack {
List(self.accounts) { account in
Text("\(account.name)")
}
Button("Add new account") {
self.addNewAccount()
}
}.navigationBarTitle("Select account")
}
}
I guess I would like some binding the content offset of the list, passed to my method addNewAccount and trigger a scrolling of the list.
Can I somehow programmatically trigger the list to scroll down to the new content?
the easiest way to achieve it is to flip the list and its content using .scaleEffect(x: 1, y: -1, anchor: .center) in order to have an upside down structured list but with the correct looking content therefore, insertion of item at index 0 in the list will be performed at the bottom with a nice looking animation
List {
ForEach(self.content) { itemContent in
Item(itemContent).scaleEffect(x: 1, y: -1, anchor: .center)
}
}.scaleEffect(x: 1, y: -1, anchor: .center)

WatchOS ScrollView Doesn't Wrap Text Properly

Right now I am able to see the text I want from my 'articles' if I set a frame with a desired width and height.
If the height is long enough it will show all of the article 'body' but with tons of space. I would like to have it where the frame can adjust it's size based on the size of the text I have so that the scrollview can scroll properly based on the desired text frames for each article body.
import SwiftUI
let articles = [
Article (id: 0, title: "Trump as President", body: "Some very short string for the article at the moment."),
Article (id: 1, title: "Obama as President", body: "He may not have been the worst but was he every really the best? Could he have done more or less from what we know?"),
Article (id: 2, title: "Tanner Fry as President", body: "Who knows how well that would work as if Tanner Fry was the president. However we do know a little bit about him from his experience as a programmer. I mean who can just pick up different langauges just off the bat and start creating code for apps to run on their watch and/or phone? Not too many people know how to do that but you know who does? Tanner Fry does, that's right.")
]
var height = 0
struct ContentView: View {
var body: some View {
// Watch res = 448 - 368
ScrollView(.vertical) {
VStack(spacing: 10){
Text("Your News").font(.title)
ForEach(0..<articles.count) {index in
Text(articles[index].title)
Text(articles[index].body).frame(width: 170, height: 170)
// Text(articles[index].body).lineLimit(50).padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
// Height needs to be variable based on the amount of text in the
// articles description. OR find a wrapper
// We're talking about the frame for the body of text
}
}
}
}
}
I am able to scroll all of my content if my height for the frame of the article.body is long enough. Otherwise it truncates the text. Is there any way to make the height more variable to the text length so that the watchOS works properly when scrolling via the ScrollView? Am I missing something?
Thank you for your time, much appreciated.
Define .lineLimit(x) to what you want to be the maximum of line the Text is able to expand. Then add .fixedSize(horizontal: false, vertical: true) to secure that the size is not shrinking back due the SwiftUI layout engine. See below.
struct ContentView: View {
var body: some View {
// Watch res = 448 - 368
ScrollView(.vertical) {
VStack(spacing: 10){
Text("Your News").font(.title)
ForEach(0..<articles.count) {index in
Text(articles[index].title)
Text(articles[index].body)
.lineLimit(nil)
.multilineTextAlignment(.leading)
.fixedSize(horizontal: false, vertical: true)
// Text(articles[index].body).lineLimit(50).padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
// Height needs to be variable based on the amount of text in the
// articles description. OR find a wrapper
// We're talking about the frame for the body of text
}
}
}
}
}