Buttons in NavigationViewItems do not work with incomplete swipe - ios

I created a NavigationView which I put a NavigationLink on to another View. The first page with a hidden title. After going to page 2 through Link, everything works at first. I have a title there and 2 navigationBarItems buttons. But if you pull from left to right back to the first screen, but then return (that is, do not go, but only pull a little), then all the buttons stop working. What is the problem?
struct View1: View {
var body: some View {
NavigationView {
ZStack {
Color.red
NavigationLink("View 2", destination: View2())
}.navigationbarhidden(true)
}
}
}
struct View2: View {
#State private var texti: String = ""
#State var themeColor = Color.green
var body: some View {
VStack {
TextEditor(text: $texti).padding().onReceive(texti.publisher.collect()) {
self.texti = String($0.prefix(2000))}
}.navigationBarTitle("Title").navigationBarItems(trailing: HStack { Button(action:{}) {
Text("Fund").foregroundColor(Color(#colorLiteral(red: 0.3647058824, green: 0.6901960784, blue: 0.4588235294, alpha: 1)))
}; Button(action: {}) {
Text("Gust").foregroundColor(Color(#colorLiteral(red: 0.3647058824, green: 0.6901960784, blue: 0.4588235294, alpha: 1)))
}})
}

Related

swift ColorPicker is triggered twice even when one color is selected only once

I need to create an array of colors created/selected by the user by using ColorPicker, bind it to a #State var tempColor variable, and append tempColor to the array of selected colors, but the problem is the behavior is unstable. Specifically, sometimes the same color is added twice to the array even when a color is selected/pressed once.
I added some logic to check for duplicate colors before adding the selected color to the array but still a color is added twice to the array. This behavior occurs like 80% of the time when ColorPicker is pressed and a color is selected.
Any idea to solve the problem please?
my code:
struct ContentView: View {
#State var createdColors = [Color]()
#State var tempColor: Color = .white
var body: some View {
VStack {
ColorPicker("selected color", selection: $tempColor)
.padding(10)
ScrollView(.horizontal) {
HStack {
ForEach(createdColors, id: \.self) { col in
Circle()
.fill(col)
.frame(width: 60, height: 60)
.padding(10)
}
}
}
}
.onChange(of: tempColor) { _ in
if createdColors.contains(tempColor) {
print("we have the color already \(createdColors.count)")
} else {
createdColors.append(tempColor)
print("adding new color \(createdColors.count)")
}
}
}
}
Give the system a little break.
struct ContentView: View {
#State var createdColors = [Color]()
#State var tempColor: Color = .white
var body: some View {
VStack {
ColorPicker("selected color", selection: $tempColor)
.padding(10)
Text("Currently ^[\(createdColors.count) item](inflect: true)")
ScrollView(.horizontal) {
HStack {
ForEach(createdColors, id: \.self) { col in
Circle()
.fill(col)
.frame(width: 60, height: 60)
.padding(10)
}
}
}
}
.onChange(of: tempColor) { newColor in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
if createdColors.contains(newColor) {
print("We have the \(newColor.description) already. Total: \(createdColors.count)")
} else {
createdColors.append(tempColor)
print("Adding new color to \(createdColors.count)")
}
}
}
}
}
There are better ways to resolve the issue. This is just a quick fix.

Creating a custom back button with NavigationView on SwiftUI

I'm trying to create a custom back button on SwiftUI, but I can't
figure out how to do it.
The idea is to hide the "Back" button at the top left that provides NavigationView, and make a custom button with the same functionality.
struct AnadirDatosViewA: View {
#Environment(\.presentationMode) var presentation
var body: some View{
NavigationView(){
Color(red: 48 / 255, green: 49 / 255, blue: 54 / 255)
.edgesIgnoringSafeArea(.all)
.overlay(
VStack{
AnadirDatosExpB()
HStack{
NavigationLink(destination:NuevoExperimentoView()){
Text("Back") //HERE
NavigationLink(destination:AnadirDatosExpA()){
Text("Next")
}
}
}
}
)
}.navigationBarBackButtonHidden(true)
}
}
Right now I'm "cheating" by using the view I want go go back as destination, but it doesn't work the same...
What can I do?
You can use the presentationMode var from the environment inside a Button:
See the commented example below for a possible implementation.
struct ContentView: View{
var body: some View{
// I am navigating with a Navigationlink, so there is
// no need for it in the AnadirDatosViewA
NavigationView {
NavigationLink("show AnadirDatosViewA") {
AnadirDatosViewA()
}
}
}
}
struct AnadirDatosViewA: View {
#Environment(\.presentationMode) var presentation
var body: some View{
// if you navigated to this by a Navigationlink remove the NavigationView
Color(red: 48 / 255, green: 49 / 255, blue: 54 / 255)
.edgesIgnoringSafeArea(.all)
.overlay(
HStack{
// This Button will dismiss the View
Button("Back"){
// with help of th presentationMode from the environment
presentation.wrappedValue.dismiss()
}
// This NavigationLink can forward you to another view
NavigationLink("Next") {
TextView(text: "last")
}
}
// This will hide the back Button in this View
).navigationBarBackButtonHidden(true)
}
}
// HelperView
struct TextView: View{
var text: String
var body: some View{
Text(text)
}
}
It seems like presentationMode is going to be deprecated in the future, so instead you could also do
#Environment(\.dismiss) var dismiss
paired with
Button(action: {
dismiss()
}, label: {
Image(systemName: "chevron.left")
Text(bookClub.bookTitle)
.fontWeight(.bold)
})

SwiftUI - Navigation Link opening the same view multiple times

I have a list in ViewA which has 3 rows. ViewA is a grand-child of the main view(not sure if this info matters, but just providing since I don't know where the actual bug is. Here is how the stack is ContentView -> opens Main Menu View(MMV) -> select an item from MMV and it opens -> Settings View -> select an item from Settings and it opens ViewA).
When I click on a row in ViewA, another view should opens up let's say ViewB. However I am seeing ViewB instantiating 3 times i.e. I see ViewB appearing 3 times on the screen and then it stops at the last instance.
I am not sure why this is happening and what the actual bug is. Here is my code:
ViewA(MenuViewOptions):
struct MenuViewOptions: View {
#State var destination: MenuViewType?
var isActive: Binding<Bool> { Binding(get: { destination != nil }, set: { _ in destination = nil } ) }
var body: some View {
VStack {
List(SettingsOptions().menuViewSettingsOptions) { item in
NavigationLink(isActive: isActive, destination: {destination?.view} ) {
MenuViewOptionRowView(menuViewItem: item, destination: $destination)
}
}
}.navigationBarTitle("Settings")
}
}
MenuViewType code:
enum MenuViewType: Int, CaseIterable, Hashable {
case circularGrid = 0, regularList = 1, capsuleGrid = 2
#ViewBuilder var view: some View {
switch self {
case .circularGrid: MainMenuCircularGridViewNew()
case .regularList: MainMenuListView()
case .capsuleGrid: MainMenuCapsuleGridView()
}
}
}
SettingsOptions().menuViewSettingsOptions code:
struct SettingsOptions {
// View inside menu view settings
let menuViewSettingsOptions: [MenuViewSettingsItem] = [
MenuViewSettingsItem(id: 0, name: "Circular Grid", imageName: "circle.grid.2x2", isSelected: false),
MenuViewSettingsItem(id: 1, name: "List", imageName: "list.dash", isSelected: false),
MenuViewSettingsItem(id: 2, name: "Capsule Grid", imageName: "rectangle.grid.2x2", isSelected: false),
]
}
MenuViewOptionRowView code
struct MenuViewOptionRowView: View {
let menuViewItem: MenuViewSettingsItem
#ObservedObject var userSettingsStore = UserSettingsStore()
#Binding var destination: MenuViewType?
var body: some View {
HStack {
Image(systemName: menuViewItem.imageName)
.circularImageStyle(width: 15, height: 15, padding: 5, backgroundColor: Color(red: 34 / 255, green: 34 / 255, blue: 34 / 255), foregroundColor: Color(red: 23 / 255, green: 121 / 255, blue: 232 / 255))
Text(menuViewItem.name)
Spacer()
if menuViewItem.id == userSettingsStore.menuViewSelection {
Image(systemName: "checkmark").foregroundColor(Color(red: 23 / 255, green: 121 / 255, blue: 232 / 255))
}
}.onTapGesture {
userSettingsStore.menuViewSelection = self.menuViewItem.id
destination = MenuViewType(rawValue: self.menuViewItem.id)
}
}
}
Basically I am setting the destination in MenuViewOptionRowView and once it's set, isActive in MenuViewOptions becomes true and NavigationLink gets fired. I am seeing the row navigates to the correct view, but just that the view instantiates 3 times which I am not sure if it is because I have 3 rows in the list.
If you have any idea of what could be the issue, please do let me know. New to SwiftUI.
Thanks!
You set destination once, but with this you activate all links in List, because they are all bound to one isActive.
With such code design I would propose the following solution: one destination - one link, destination is already set on tap, so... (code in question is not testable so just as-is)
List(SettingsOptions().menuViewSettingsOptions) { item in
MenuViewOptionRowView(menuViewItem: item, destination: $destination)
}
.background(
NavigationLink(isActive: isActive, destination: {destination?.view} ) {
EmptyView()
}
)

How to get SwiftUI List and NavigationView with a background gradient?

When I scroll a List, I want to shrink the navigation bar from large to small. This works by default, but if I try to add a gradient behind the table, it doesn't work any more. Code is attached (try uncommenting the Gradient to see). How do I get this to work?
import SwiftUI
struct BuyView: View {
let numbers = ["1","2","4","1","2","4","1","2","4","1","2","4","1","2","4","1","2","4"]
init() {
UITableView.appearance().backgroundColor = .clear
UITableViewCell.appearance().backgroundColor = .clear
}
var body: some View {
NavigationView {
ZStack {
// LinearGradient(gradient: Gradient(colors: [.gray, .white]), startPoint: .top, endPoint: .bottom)
// .edgesIgnoringSafeArea(.all)
List(numbers, id: \.self) { number in
Text(number)
}.navigationBarTitle("Numbers")
}
}
}
}
struct BuyView_Previews: PreviewProvider {
static var previews: some View {
BuyView()
}
}

SwiftUI 2 questions but very simple, about searchBar and the backgroundImage for List

SwiftUI very simple 2 questions
1, how to make the searchBar stick to top so that when use scroll down they can still see they searchBar
2, I'm using a List and work with a TabView and I want the List or the VStack maybe(or something that is holding the List) to have a background Image(a png already in my Assets.xcassets). I tried ZStack or .background(Image("...")) but none of them worked.
Here is the image, I want the background to be as the teal color png image.
Here is the code of one of the view for TabView:
struct Discover: View {
#State private var keywords: String = ""
var names = ["Yu Song", "ZhangYuan", "Kotoyama"]
var body: some View {
ZStack {
List {
HStack {
SearchBar(text: $keywords)
Image(systemName: "person")
Image(systemName: "bell")
}
ForEach(self.names.filter {
self.keywords.isEmpty ? true : $0.localizedCaseInsensitiveContains(self.keywords)
}, id: \.self) { name in
Text(name)
}
}.background(Image("bg_global"))
}.edgesIgnoringSafeArea(.all)
}
}
here is the preview for your convinence:
Notice that I already added .background(Image("bg_global")) in List and VSrack but the image never showed.
Thanks a lot.
To make background visible it's needed to make List and its content transparent. It can be done for example in init,
init() {
UITableView.appearance().backgroundColor = .clear
UITableViewCell.appearance().backgroundColor = .clear
}
Use a VStack instead of a ZStack to make the SearchBar stick to the top. And make sure the SearchBar is not part of the List View.
struct ContentView: View {
init() {
UITableView.appearance().backgroundColor = .clear
UITableViewCell.appearance().backgroundColor = .clear
}
#State private var keywords: String = ""
var names = ["Yu Song", "ZhangYuan", "Kotoyama"]
var body: some View {
VStack{
// Your Search Bar View
HStack{
Spacer()
Text("Search")
Spacer()
}.padding().background(Color.red)
List {
ForEach(self.names.filter {
self.keywords.isEmpty ? true : $0.localizedCaseInsensitiveContains(self.keywords)
}, id: \.self) { name in
Text(name)
}
}
}.offset(x: 0, y: 45).background(Color.yellow).edgesIgnoringSafeArea(.all)
}
}
Since you also want to show the background in the safe areas you need to push down the view with offset.

Resources