NavigationLink in SwiftUI won't accept arguments - swiftui

My NavigationLink does not appear to be working as advertised, in that it is not accepting arguments to display text or a view. My code is as follows:
struct MainContentView: View {
var body: some View {
// MARK: PROPERTIES
let mainData: [MainData] =
Bundle.main.decode("mainData.json")
// MARK: BODY
NavigationView {
List {
Image("hsSampleBack")
.resizable()
.scaledToFill()
.frame(height: 300)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
ForEach(mainData) { mainDataPoint in
NavigationLink(destination: Selection() {
Text("Text Here")
})
}//:LOOP
} //: LIST
.navigationBarTitle("Data Points", displayMode: .large)
} //: NAVIGATION
}
}
I am getting the following 2 error messages over my NavigationLink line:
Argument passed to call that takes no arguments
Missing argument for parameter #1 in call
If these seems contradictory to you, join the club. On the one hand it claims that no arguments are permitted, and then it's flagging a missing argument. It seems to want to call for a "Label" Text argument, which would be fine, except that I ultimately want to pass a View, which I have done successfully elsewhere.
Any thoughts on this?

Here is corrected syntax
ForEach(mainData) { mainDataPoint in
NavigationLink(destination: Selection()) {
Text("Text Here")
}
}//:LOOP

Related

Trouble With Constraints for a Navigation Link

Here is my code:
import SwiftUI
struct ContentView: View {
var link: some View {
NavigationLink(destination: OtherView()) {
Text("NLTitle")
}
.foregroundColor(.blue)
}
var body: some View {
NavigationView {
List {
ZStack {
HStack {
Text("1")
Spacer()
}.padding([.leading, .trailing], 20)
HStack {
Spacer()
Text("2")
.multilineTextAlignment(.center)
.frame(
alignment: .center
)
Spacer()
}
.padding([.leading, .trailing], 20)
HStack {
Spacer()
link
}.padding([.leading, .trailing], 20)
}
}
}
}
}
I have a NavigationLink (named 'link') in a list cell. I would like for the Text within 'link' to be to the rightmost side of the view. To try to accomplish this, I inserted 'link' in an HStack and put a Spacer() before it to try and push it to the rightmost part of the view. When I run the app though, the Text ends up in between Text("1") and Text("2") and I can't figure out why. I want Text("1") to be in the leftmost part of the view, Text("2") to be in the center of the view, and 'link' to be in the rightmost part of the view. I have provided visuals (the colors aren't important, I just wanted to make the different Texts clear):
Desired layout:
What I get instead:
I found that if I take everything out of the List view I get my desired layout. Also, if I keep everything in the List view and replace the NavigationLink with a Button I get my desired layout. The goal is to get the desired layout without having to change either of these aspects.
For the sake of clarity, I didn't include the code for OtherView() as I don't think it's necessary for this question.
The "quick" fix is to add fixedSize() to the NavigationLink
var link: some View {
NavigationLink(destination: Text("OtherView()")) {
Text("NLTitle")
}
.foregroundColor(.blue)
.fixedSize()
}
That will allow the link to shrink.

XCode SwiftUI - Why is my keypad toolbar doing this?

Very novice to the app development game. I am trying to put this toolbar above the .decimalPad and I cannot get this large gap to go away.
VStack {
Rectangle()
.foregroundColor(Color(UIColor.systemBackground))
.frame(height: 35)
.overlay {
HStack {
Spacer()
Button(action: {
isTextFieldFocused = false
}) { Text("Done")}
}
.offset(y: -3)
.padding(.trailing)
}
.opacity(isTextFieldFocused ? 1 : 0)
.ignoresSafeArea(.keyboard) //This makes sure the bottom tab bar stays below the keyboard.
}
I initially thought it was something in another view causing the spacing, but I managed to parse through the views in the canvas and it does it regardless.
Here is what I'd like it to look like, for reference.
What I want
To add a Button onto your keyboard, you use a .toolbar with the locations to .keyboard like this:
TextField("Enter Text", text: $text)
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Button(action: {
isTextFieldFocused = false
}) { Text("Done")}
// If you want it leading, then use a Spacer() after
Spacer()
}
}
You were overthinking it by adding the Rectangle. This is why we look for minimal reproducible examples. We can dial in the fix for your specific code.

Rounded corners and border for a SwiftUI List Section

I want to create the following design in SwiftUI. I am currently using a list and creating a section that contains cells like so.
List {
Section {
ForEach(titles) { title in
Cell(title: title)
}
}
}
When I apply a modifier like a border to the section it applies it to all the views contained in the Section. I want to have that border around the entire Section with a corner radius of 10. The closest I have got to creating the desired design is by not using a List but instead using a VStack and applying the following modifiers
VStack {
ForEach(titles) { title in
Cell(title: title)
}
}
.overlay(RoundedRectangle(cornerRadius: 10)
.stroke(.gray, lineWidth: 2))
I discovered however that this is not a smart approach as the List uses reusable cells and in the case of VStack they do not. Is it possible to create the wanted design with a List in SwiftUI? I do not want to opt for the default list style provided by Apple
Just Copy paste this code and customise it as per your needs, enjoy
import SwiftUI
struct CustomizeListView: View {
var titles = ["First Section" : ["Manage your workout", "View recorded workouts", "Weight tracker", "Mediation"], "Second Section" : ["Your workout", "Recorded workouts", "Tracker", "Mediations"]]
var body: some View {
List {
ForEach(titles.keys.sorted(by: <), id: \.self){ key in
Section(key) {
VStack(alignment: .leading, spacing: 0){
ForEach(titles[key]!, id: \.self) { title in
HStack{
Text(title)
Spacer()
Image(systemName: "arrow.right")
}//: HSTACK
.padding(20)
Divider()
}//: LOOP
}//: VSTACK
.overlay(
RoundedRectangle(cornerRadius: 10, style: .circular).stroke(Color(uiColor: .tertiaryLabel), lineWidth: 1)
)
.foregroundColor(Color(uiColor: .tertiaryLabel))
}//: SECTION
}//: LOOP
}//: LIST
.listStyle(InsetListStyle())
}
}
struct CustomizeListView_Previews: PreviewProvider {
static var previews: some View {
CustomizeListView()
}
}
I assume you just need to change list style, like
List {
Section {
ForEach(titles) { title in
Cell(title: title)
}
}
}
.listStyle(.insetGrouped) // << here !!

SwiftUI Picker onReceive() called every time the body is rendered

i am using a Picker to show a segmented control and wish to know when the picker value changes so i can perform a non-UI action. Using the proposed onReceive() modifier (as suggested here) does not work as it is called every time the body is rendered.
Here's the code i have:
struct PickerView: View {
#State private var weather = 0
#State private var showMessage = false
var body: some View {
VStack(spacing: 24) {
Picker(selection: $weather, label: Text("Weather")) {
Image(systemName: "sun.max.fill").tag(0)
Image(systemName: "cloud.sun.rain.fill").tag(1)
}
.pickerStyle(SegmentedPickerStyle())
.frame(width: 120, height: 48)
.onReceive([weather].publisher.first()) { connectionType in
print("connection type is: \(connectionType)")
}
Button(action: { self.showMessage.toggle() }) {
Text("Press Me")
}
if showMessage {
Text("Hello World")
}
}
}
}
The onReceive() block will get called any time the body is rendered, including the first time and any time the button (which toggles showing a message) is pressed.
Any ideas why this is happening and how i can only react to when the picker value is changed?
Here is possible solution instead of .onReceive
Picker(selection: Binding( // << proxy binding
get: { self.weather },
set: { self.weather = $0
print("connection type is: \($0)") // side-effect
})
, label: Text("Weather")) {
Image(systemName: "sun.max.fill").tag(0)
Image(systemName: "cloud.sun.rain.fill").tag(1)
}

Swiftui hide disclosure arrow

I have this View
NavigationView {
GeometryReader { geometry in
List {
ForEach(self.viewModel.items) { item in
HStack(spacing: 0, content: {
ZStack {
RowItemView(data: item.FirstItem)
NavigationLink(destination: CustomView(data: item.FirstItem))
{
EmptyView()
}
}
.frame(width: geometry.size.width / 2, alignment: .center)
if (item.SecondItem != nil) {
ZStack {
RowItemView(data: item.SecondItem!)
NavigationLink(destination: CustomView(data: item.SecondItem!))
{
EmptyView()
}
}
})
}.listRowInsets(EdgeInsets())
}
}
I want to hide the disclouse arrow of the NavigationView.
I try to add .buttonStyle(PlainButtonStyle()) or add a negative trailing to the navigationLink, but it doesn't change.
I have already read this question and this one but they do not work in my case, probably because I'm creating a grid and not a plain list.
In this scenario the possible approach is to use zero frame, as following
NavigationLink(destination: CustomView(data: item.FirstItem)) {
EmptyView()
}.frame(width: 0)
Thanks to #Asperi I figured out what is the problem.
With a zero EdgeInsets in listRowInsets the arrow still show.
So I create this trick (Works in Xcode 13.3.1)
List {
ForEach(self.viewModel.items) { item in
//code for creating the row
}.listRowInsets(EdgeInsets.init(top: 8, leading: 0, bottom: 8, trailing: 0))
Put a value for both top and bottom.
I do not know if it is the correct way to get rid of that annoying arrow, but for my app it works :-)