NavigationLink inside LazyVGrid cycles all entries on back, SwiftUI
It is Form/List feature to auto-detect links in rows, but you have several in row, so the effect. The solution would be to separate cell view and hide link from auto-detection.
Tested with Xcode 12.0 / iOS 14
struct ContentView: View {
@State var images:[String] = ["plus", "minus"]
var body: some View {
NavigationView {
Form {
Section {
LazyVGrid(columns: [GridItem(.adaptive(minimum:100))]){
ForEach(images){
ImageCellView(image: $0)
}
}
}
}
}
}
}
struct ImageCellView: View {
var image: String
@State private var isActive = false
var body: some View {
Image(uiImage: UIImage(systemName: image)!)
.resizable()
.scaledToFit()
.onTapGesture {
self.isActive = true
}
.background(
NavigationLink (
destination: ImageDetail(image: image), isActive: $isActive,
label: {
EmptyView()
}
))
}
}
SwiftUI NavigationLink in LazyVGrid picking random index
You activate all links at once (because all of them depends on one state). Instead we need to use different NavigationLink
constructor for such cases.
Here is fixed variant. Tested with Xcode 12.1 / iOS 14.1
struct TestView: View {
let columns = [
GridItem(.flexible())
]
@State var selectedItem: Int?
var body: some View {
ScrollView {
LazyVGrid(columns: columns, spacing: 20) {
ForEach(1...10, id: \.self) { index in
Text("\(index)")
.background(NavigationLink(destination: TestDetail(index: index), tag: index, selection: $selectedItem) {
EmptyView()
}).onTapGesture {
selectedItem = index
}
}
}
}
}
}
Assigning NavigationLink to Images within Array in Swift UI
For occasions like this I would prefer an enum that holds all related information. You also could do this with a struct the reasoning behind this stays the same.
enum ImageEnum: String, CaseIterable{ //Please find a better name ;)
case image1, image2
var imageName: String{ // get the assetname of the image
switch self{
case .image1:
return "test"
case .image2:
return "test2"
}
}
@ViewBuilder
var detailView: some View{ // create the view here, if you need to add
switch self{ // paramaters use a function or associated
case .image1: // values for your enum cases
TestView1()
case .image2:
TestView2()
}
}
}
struct TestView1: View{
var body: some View{
Text("test1")
}
}
struct TestView2: View{
var body: some View{
Text("test2")
}
}
And your Grid
View:
struct Grid: View {
var columnGrid: [GridItem] = [GridItem(.flexible(), spacing: 25), GridItem(.flexible(), spacing: 25)]
var body: some View {
NavigationView{ // Add the NavigationView
LazyVGrid(columns: columnGrid, spacing: 50) {
ForEach(ImageEnum.allCases, id:\.self) { imageEnum in // Itterate over all enum cases
NavigationLink(destination: imageEnum.detailView){ // get detailview here
Image(imageEnum.imageName) // get image assset name here
.resizable()
.scaledToFill()
.clipped()
.cornerRadius(25)
}
}
}
}
}
}
Result:
The Back button messes up the view
Your issue is that you have duplicate NavigationViews
. There are two ways to solve this:
When you call the next view in your
NavigationLink
, set.navigationBarBackButtonHidden(true)
. This will disappear the extra back button.A simpler way; just delete the
NavigationView
in your second view (the linked one). That will prevent duplicate back buttons.
SwiftUI: NavigationLink unintentionally tappable and activated inside Form
The solution is to hide link into background of some view, like below
Form {
Section {
VStack {
Text("Hello")
.background(
NavigationLink(destination: Text("Detail View"), isActive: $showNext)
{ EmptyView() }.disabled(!showNext)
)
}
}
}
SwiftUI NavigationLink Hide Arrow
The way it worked for me:
List {
ForEach(elements) { element in
ZStack {
CustomView(element: element)
NavigationLink(destination: DestinationView()) {
EmptyView()
}.buttonStyle(PlainButtonStyle())
}
}
}
SwiftUI - Setting maxHeight does nothing for Text() inside LazyVGrid()
You just need to set the idealHeight
to 80
as well.
Text(buttons[index])
.font(.system(size: 30))
.foregroundColor(Color.white)
.frame(maxWidth: 80, idealHeight: 80, maxHeight: 80) // <- Here
.background(RoundedRectangle(cornerRadius: 8).fill(getButtonColour(char: buttons[index]).opacity(Double(index) / Double(buttons.count) + 0.1)))
Result (colors may look different because I don't have all the functions):
Additionally, in the screenshot you can see not all the characters are shown. You should change the range in the ForEach
to 0 ..< buttons.count
to fix this.
Related Topics
How to Debug Swift Playgroundbook
Outline Uilabel Text in Uilabel Subclass
How to Draw a Simple Rounded Rect in Swift (Rounded Corners)
Change Buttonstyle Modifier Based on Light or Dark Mode in Swiftui
Show More Button Next to End of Text Swift
Viewcontroller.Type Does Not Have a Member Names 'Answerone' - Swift
How to Pass a Swift Object to JavaScript (Wkwebview/Swift)
Setting Default Tab in Uitabbar in Swift
Dyld: Symbol Not Found: _Tmpdcss12Anygenerator
Why Swift Use a Struct as Dictionary Key Instead of a String Here
Animated View Floats into Place Weirdly Swiftui
Expand Uitextview and Uitableview When Uitextview's Text Extends Beyond 1 Line
Problems with Cropping a Uiimage in Swift
iOS Uiimagepickercontroller: Any Way of Getting the Date of the Chosen Picture
Please Add the Host Targets for the Embedded Targets to the Podfile
How to Change How a Remote Notification Is Presented Before Presentation