I'm trying to build an app with flutter. I'm getting an error which I cant figure out:
This is the code for the Navigation Bar where it is then called to several pages
This is where the error is occuring:
I tried adding the required this.name, .. arguments but it shows different errors.
Error image
The reason you have a problem is that you require that these constructor parameters are set when creating the widget, except that when you do you don't actually do so and fail to send any. Either way, first thing you'll need to do is get rid of the #required directive, as it's not needed, especially if you don't want to include them. There are three way's you can fix this:
Set defaults for your constructor parameters:
const NavBar([Key? key, this.name = "", this.credit = "", this.rank = ""])
Make your constructor parameters nullable:
const NavBar([Key? key, this.name, this.credit, this.rank])
String? name;
String? credit;
String? rank;
Make them late and instantiate them elsewhere in your class, before they get called. I probably wouldn't recommend that approach for you though.
Additionally, as Just a Person suggests, I'd convert them from positional to named arguments, as it gives you greater flexibility.
There are various ways you can set up a constructor in Dart, so which approach would be best for you I couldn't tel as it depends on your requirements.
You need to pass required arguments in nav bar widget
drawer : NavBar('name','credit','rank')
Replace your drawer code with above code.
In your NavBar you are not declaring a named argument but a positional argument. So removed the #required in front of all parameters or enclose them in {} but in this case I think you should named arguments as it will be more clear.
Like this: NavBar(Key? key, {required this.name, this.credit, this.rank})
Also pass all the four arguments, but not by name because they are not positional.
drawer: NavBar(name: name, credit: credit, rank: rank)
Related
When working with optional arguments in Compose: What's the value between the braces?
"item=" is the key. What is the purpose of the string within the braces?
composable("Details?item={item}",
arguments = listOf(navArgument("item") {
this.type = NavType.StringType
defaultValue = "Item not available!"
})) {
You have it backwards - the name of the query parameter (the item= part) could be anything. It could be lorem_ipsum or foobar or any word - that word isn't used by Navigation at all for figuring out how to parse that argument. The only thing that matters is the structure of your route pattern - that query parameter syntax is how you mark a parameter as an optional argument. Just like a web URL, you could navigate to Details as well as Details?item=cat - both would match your route. A required parameter would be part of the path (i.e., Details/{item}).
As explained in the Navigate with arguments guide:
Navigation compose also supports passing arguments between composable destinations. In order to do this, you need to add argument placeholders to your route, similar to how you add arguments to a deep link when using the base navigation library
That {item} is the placeholder that indicates that whatever string is in the place of the {item} should be parsed and put as an argument with the name item. This is how you can call navBackStackEntry.arguments?.getString("item") and get that parsed value out of the arguments of the destination.
I have this sample data class:
data class Car ( var id: String )
Now I can create a fun as this:
fun doWhatever(id: String){}
My problem is that if my customer then tells me that Id is an int, I have to change it in both places.
So what I want is to set Car.id type as refence in fun doWhatever, something like this:
fun doWhatever(id: propertyTypeOfCarId){}
So I if the customer changes type, I only have to change it in the class.
I read all kind of posts, but I wasnt able to find the answer. Any idea how to achieve it?
If this isn't something you expect to be doing regularly, consider just using the refactoring tools the IDE provides. You code to handle a specific set of data, and if the structure of that data changes, you have to adapt the code to fit it. Baking in a bunch of "what if" functionality can add complexity, compared to just saying a String is a String and changing it if it ever needs changing, using the tools provided to make that as quick and easy as possible.
But sometimes you need to do this kind of thing, and Kotlin has some nice language features it can be worth using, like type aliases:
typealias CarId = String
data class Car(var id: CarId)
fun doWhatever(id: CarId){}
Two benefits here: the actual type is only defined in one place, so you can change that String to an Int without needing to change anything else - except stuff that relied on the ID being a String specifically of course
The other benefit is you're actually adding some semantic information by using that very specific type. That function isn't supposed to just take any old String - it's specifically meant to handle CarIds. It tells you what it's for, and that can make your code a lot easier to understand
(The function will accept Strings, because CarId is just an alias - an alternative name for a String - so it's not a way to enforce structure on your code, just a way to make it nicer to read and write. You can't define a new type that is a String in Kotlin unfortunately)
If the number of id types you support is limited, you can simply use method overloading:
fun doWhatever(id: String){}
fun doWhatever(id: Int){}
// etc.
Alternatively, you can use a reified generic parameter in your method to support any number of types:
inline fun <reified T> doWhatever(id: T) {
when (T::class) {
Int::class -> {}
String::class -> {}
}
}
I have created my NavGraph using the Kotlin DSL and everything is fine. But I'm struggling to pass a simple argument between destinations.
I'm folowing this Android Docs without success: https://developer.android.com/guide/navigation/navigation-kotlin-dsl#constants
Part of graph that adds the argument as the docs says:
fragment<RestaurantsTabsFragment>(
"${CampusSelectorDestinations.restaurantsTabsFragment}/" +
CampusSelectorArguments.campusId
) {
argument(CampusSelectorArguments.campusId) {
type = NavType.StringType
defaultValue = "test"
}
}
Code with the navigation action trying to pass a argument:
campusesAdapter.onCampusClick = { campusId ->
findNavController().navigate("${CampusSelectorDestinations.restaurantsTabsFragment}/" + campusId
}
Error I get:
IllegalArgumentException: Navigation destination that matches request NavDeepLinkRequest{ uri=android-app://androidx.navigation/restaurantsTabsFragment/jCkuLbzRHtW0CUzDFWYw } cannot be found in the navigation graph NavGraph
Can anyone help me? I can provide more information if needed
The pattern to pass the argumet route is wrong at the docs:
For luck, I've found this explanation inside a Navigation Lib class and that solved my problem (after 2 days struggling):
...
In addition to a direct Uri match, the following features are supported:
Uris without a scheme are assumed as http and https. For example, www.example.com will match http://www.example.com and https://www.example.com. Placeholders in the form of {placeholder_name} matches 1 or more characters. The String value of the placeholder will be available in the arguments Bundle with a key of the same name. For example, http://www.example.com/users/{id} will match http://www.example.com/users/4. The .* wildcard can be used to match 0 or more characters.
These Uris can be declared in your navigation XML files by adding one or more elements as a child to your destination.
...
Hope someone from Google see this and fixes the docs. (or explain if I'm wrong)
Just put your arguments into curved breaks and separate them by slash as it shown in the example below.
Define your destination with all required argument:
fragment<TransactionFragment>("${MainNavRoute.transaction}/{arg1}/{arg2}") {
argument("arg1") {
type = NavType.StringType
}
argument("arg2") {
type = NavType.LongType
}
Navigation to the destination:
findNavController().navigate("${MainNavRoute.transaction}/string_value/2")
Also, I have reported an issue to the tracker too. https://issuetracker.google.com/issues/221895357
In Kotlin i am learning about covariant(a subtype can be used in place of a super type).
They wrote there something like a rule. but it seems wrong for me. It is written:
You can’t, however, use out if the class has function parameters or var
properties of that generic type.
But i think that the word or should be replaced with the word and, because in situation when a class has a function that "gets" the type as a parameter, if the property of the generic type is a val and not var, and damage can't be done, because any assignment isn't possible to val property.
Am i right or what is written in the book is correct and i'm missing something?
Edit:
I just realized (according to some post i saw in this forum) that the only situation that a parameter can be a problem although property is declared as val, is in case we have a container of type T, let's say List then it may be a problem if we try to add to the List, but if we don't have a container i can't see situation when getting a parameter type can make trouble while property is val. Am i right?
The out keyword is for covariance, not contravariance.
Here's a basic example of the trouble caused in an imaginary class where covariance is allowed for the var property type:
class Container<out T>(var item: T)
val intContainer = Container<Int>(1)
val numberContainer: Container<Number> = intContainer // cast is allowed for covariant type
numberContainer.item = 5f // allowed if item is a var
val intValue = intContainer.item // Float value is cast to an Int!
This isn't possible with a val so the above class could be covariant at the declaration site if item were a val.
This is my data class created using a Kotlin data class creator Plugin.
data class ResponseHealthInisghts(
val `data`: List<Data>,
val message: String,
val statusCode: Int
)
This code gets work even if I remove the backticks, I wonder if it's for Java interoperability. But this variable is not a keyword but also it has backticks. why?
Based on Why does this Kotlin method have enclosing backticks?
this question is is a keyword for both Java and Kotlin but data is not.
You can use backticks simply to enclose class, method or variable name
For example it's useful if there are spaces:
class `Final Frontier` {
fun `out of space`() {
val `first second`: String?
}
}
Or as you mention if using Kotlin keyword
If a Java library uses a Kotlin keyword for a method
foo.`is`(bar)
data is a Modifier Keyword
data instructs the compiler to generate canonical members for a class
The following tokens act as keywords in modifier lists of declarations and can be used as identifiers in other contexts
And not a Hard Keyword that can't be used as identifier
The following tokens are always interpreted as keywords and cannot be used as identifier
It allows you to use reserved keywords and operators as names of your variables. The list of those words: https://kotlinlang.org/docs/reference/keyword-reference.html
Based on this question's answerWhy does this Kotlin method have enclosing backticks?
and the comments from #forpas and #marstran I was able to understand my problem.
The is keyword is a hard keyword
Hard Keywords
are always interpreted as keywords and cannot be used as identifiers:
so fore interoperability we need to use backticks because Java and Kotlin both have is keyword.
Where data keyword is only available in Kotlin and also belong to the category
Soft Keywords
act as keywords in the context when they are applicable and can be used as identifiers in other contexts.
So we can use it with or without backticks.
Also as an additional note you can use bacticks to customize your identifier
var `data is simple` : List<String>
If it shows lint error use
"File | Settings | Editor | Inspections | Illegal Android Identifier" and disable this inspection.