My search bar won't show anything in list - ios

I have a view model for country codes, names, flags...
How can I search through that list once I fetch it?
My search code is like this:
ForEach(countryVM.diallingCode.filter{$0.name.lowercased()
.contains(self.textlowercased())}, id:\.self) { option in
VStack{
Divider()
.frame(maxWidth:.infinity)
HStack{
Image(option.flag)
.resizable()
.frame(width:30, height:30)
Text(option.name)
.font(.custom("Ubuntu-Light", size:12))
Spacer()
}.frame(maxWidth:.infinity)
}
}
There is array in diallingCode, it shows me the countries, but I can't search through them.
The same code worked when I used static values.

To make it easier on yourself, move
countryVM.diallingCode.filter{$0.name.lowercased().contains(self.textlowercased())}`
to a method on your view model, e.g.
func filteredDialingCodes(for text: String) {
let codes = diallingCode.filter{$0.name.lowercased().contains(text.lowercased())}
print(codes) // see what's happening
return codes
}
Then call like:
ForEach(filteredDialingCodes(for: text), id:\.self) { option in
Not only is it clearer what you're trying to do, it also will allow you to see what values are returned when filtering.

Related

SwiftUI retuning List or NavigationView in body: difference of return List and List in body

I have question about returning NavigationView and List inside of SwiftUI body
There are code snippets like this:
var body: some View {
let trailingItem = HStack {
Button(action: { print("Button 1") }) {
Image(systemName: "bell")
}
Button(action: { print("Button 2") }) {
Image(systemName: "square.and.arrow.up")
}
}
return NavigationView {
Image("SwiftUI")
.navigationBarItems(trailing: trailingItem)
.navigationBarTitle("Title")
}
}
and this
var body: some View {
let numbers = [1, 2, 3, 4, 5]
return List(numbers, id: \.self) {
Text("\(String(describing: $0))")
}
}
In these two code snippets, I can find return keyword for NavigationView and List
To figure out what does that grammar do, I tried deleting return keyword but nothing happened
I want to know:
What does that return keyword do?
What is difference between using return for NavigationView and List
Thanks in advance for any help you are able to provide.
Some of the features in SwiftUI's syntax are made possible by something called a View Builder which is a type of Result Builder
When using a View Builder, functions and computed properties have an implicit return (ie the last statement is returned even without the return keyword). There are also other specific rules about what kinds of implicit code can be included in a View Builder, but let declarations like your examples contain are fine. See https://swiftwithmajid.com/2019/12/18/the-power-of-viewbuilder-in-swiftui/ and https://swiftontap.com/viewbuilder for more information.
SwiftUI Views are an interesting special case because the var body property of the View is interpreted to be a ViewBuilder even though we don't have to explicitly annotate it with #ViewBuilder. However, if you were to try the same thing in a regular function, you would need to use that #ViewBuilder to get a similar result if the function had more than one statement (one-line functions in Swift have implicit returns as well).
#ViewBuilder func myView() -> some View {
Text("test")
Text("Another item")
}
So, in your code examples (since you were in var body), there is no difference between using return and omitting it.

List View longer than its content (SwiftUI)

My question is regarding the List in SwiftUI. I provide a picture and the code in order to present the problem easier.
List(){
Section(header: Text("Notifications").textCase(nil).font(.title2)) {
Radio_Buttons_Group()
}
Section(header: Text("Apperance").textCase(nil).font(.title2)) {
Radio_Buttons_Group()
}
}
.listStyle(GroupedListStyle())
What I'm trying to figure out is how to get that blue line(it comes from Xcode preview, it represents the List View) to end after the last element.
Thank You

Why does swiftUI give me errors for correct code?

SwiftUI has been giving me errors and refusing to build when I know that the code is correct. For instance the following code was working all of 15 minutes ago. I tried to wrap the List in JumpToBookView in a VStack and add a Button underneath the list, and it started spitting out errors on my Image in BookRow. This code was compiling and showing in the preview before I added the Button and VStack, after I removed them, it still won't let me preview the view. I have tried cleaning the build folder, deleting derived data, and quitting the application, all at the same time, and still nothing. No preview, and the project won't compile. For background, the project is mainly UIKit, but I'm trying to incorporate SwiftUI into it, even though that shouldn't matter because this view is not called anywhere. I am currently running the latest version of Xcode, and have attached my code and a screenshot of the errors. For search, I will also paste the errors here. Missing argument label 'imageName:' in call, Value of type 'Image' has no member 'resizable', and Cannot infer contextual base in reference to member 'fit'
import SwiftUI
struct JumpToBookView: View {
var body: some View {
List {
BookRow(selected: true)
BookRow(selected: true)
BookRow(selected: true)
BookRow(selected: true)
BookRow(selected: true)
BookRow(selected: true)
}
}
func testJump()
{
print("test")
}
}
struct BookRow: View {
var selected: Bool
var body: some View {
ZStack {
Rectangle()
.fill(Color(RaiseColor.red))
HStack{
Text("1.2 What is an Ecosystem?")
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color(.white))
Spacer()
Image(selected ? "pauseButton" : "playButton")
.resizable()
.aspectRatio(1, contentMode: .fit)
.frame(maxWidth: 25)
.foregroundColor(Color(.white))
}
.padding(.all)
}
}
}
struct JumpToBookView_Previews: PreviewProvider {
static var previews: some View {
JumpToBookView()
}
}
EDIT: I just want to add that it was also working with RaiseColor.red before, so there shouldn't be any issues with that custom color.
The issue ended up being that my codebase had previously defined a class named Image, so SwiftUI was having issues figuring out which Image I was trying to reference. Without making other changes to the codebase, this issue was resolved by specifying SwiftUI as the parent of Image, which can be done by the following SwiftUI.Image(selected ? "pauseButton" : "playButton")". This fixes all of the issues I was having, but the best thing to do would be to refactor your codebase in order to not have conflicting names with SwiftUI classes and structs.
When I replace this
Rectangle()
.fill(Color(RaiseColor.red))
with this
Rectangle()
.fill(Color.red)
all compiled well... so look for error in that custom color.
My issue was that i named an intentdefinition enum to Color. I renamed it and it's working fine again.

how to use EnvironmentObject in a Swiftui View function?

Resolved
Finally, I found the problem. My questioned View was placed in a .sheet. If I show this View separately, the environment variables will work, but if they are placed in .sheet, the Store must be explicitly injected in.
.sheet(isPresented: $showEditSheet){
EditFavoriteRootView().environmentObject(Store())
}
Now It's worked!
old quesition
Because ForEach couldn't support too complicated logic, I defined a function in the View to implement the content.
In most cases, this is fine. However, I cannot use the EnviromentObject in the function。
build success , the button in View body works fine, but when I click button in function got the runtime error:
Fatal error: No ObservableObject of type Store found.
A View.environmentObject(_:) for Store may be missing as an ancestor of this view.: file /BuildRoot/Library/Caches/com.apple.xbs/Sources/Monoceros/Monoceros-
Code sample:
struct FromCategory: View {
#EnvironmentObject var store:Store
var body: some View {
ForEach(AppState.HealthCategoryList.keys.sorted(by: <),id:\.self){
self.ShowList(categoryId: $0)
}
Button(action:{
self.store.dispatch(.updateFavorite(idName:"test"))
}){Text("Test")}
}
func ShowList(categoryId:String)->some View{
let metalist = AppState.HealthCategoryList[categoryId]?.metaData?.sortedArray(using: [NSSortDescriptor(key: "idName", ascending: true)]) as! [HealthMetaData]
return VStack{
VStack(spacing:10) {
ForEach(0..<metalist.count){i in
HStack{
Text(metalist[i].title!)
Spacer()
Button(action:{
self.store.dispatch(.updateFavorite(idName: metalist[i].idName!))
//self.store.appState.updateFavorite(idName: metalist[i].idName!)
}){
if AppState.UserFavoriteList[metalist[i].idName!] != nil {
Image(systemName: "star.fill")
}
else {
Image(systemName: "star")
}
}
}
}
}
}
}
}
Fatal error: No ObservableObject of type Store found. in this line
self.store.dispatch(.updateFavorite(idName: metalist[i].idName!))
store can be use well in normal some View, but not in function.
How to solve this. Or is there any other way?
Thanks
This is happening because you want to update an EnvironmentObject and you're not in the View which was loaded by the SceneDelegate.swift
In case you're using the EnvObject in a correct way, you just need to pass te EnvObject to the next view like this:
DestinationView().environmentObject(self.yourEnvObject)
More information explained in my post:
https://stackoverflow.com/a/58997326/12378791

How to disable SwiftUI's default behavior?

SwiftUI makes it very easy to build declarative UIs. However, sometimes they assume defaults that are not necessarily what we want.
Example:
When adding two buttons inside a list row, SwiftUI automatically makes the whole row touchable, and both button's actions are called on row tap. This is the default behavior, as demonstrated in their WWDC videos.
But I do not want this behavior. I want both buttons to work properly, and the row to not be tappable.
Question:
How can we tell our Guacamole expert (to use the WWDC reference) to stop assuming how I want my list (or any other behavior) to work?
Any help would be appreciated.
If the List's default behavior is not required, you could use a VStack:
struct ContentView: View {
var body: some View {
VStack {
Button(action: {
print("foo")
}) {
Image(systemName: "photo")
}
Button(action: {
print("bar")
}) {
Image(systemName: "photo")
}
}
}
}
However if List is really required, then it could be customized by writing a custom ListStyle.
(Also take a look at this question: How to change ListStyle in List.)
It seems that SomethingStyle protocol is the way Apple wants developers to use to modify native SwiftUI elements/behavior. Another example would be ButtonStyle or TextFieldStyle, etc.
I am under the impression that Apple wants to enforce their style guidelines. Also to add onto #backslash-f answer you could also just use a for each instead of a list, this will give you a similar effect and allow much more customization.
struct doubleList: View {
var body: some View {
VStack{
ForEach(1 ..< 10) {index in
Button(action: {
print("foo")
}) {
Image(systemName: "photo")
}
}
}
}
}
Another option to try would be to wrap an UITableView into an UIViewRepresentable and try to enable buttons that way
It seems there might be another way around this by using tap gestures
Image(systemName: "photo")
.gesture(TapGesture().onEnded() {
print("action2")
})

Resources