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.
Related
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)
I start with one map myInitialMap. i would like to create another map myNewMap that is initialised with myInitialMap.
val myInitialMap = mapOf<String, Int>("one" to 1, "two" to 2)
val myNewMap = mapOf(myInitialMap)
I get error:
Type mismatch.
Required: Pair<TypeVariable(K), TypeVariable(V)>
Found: Map<String, Int>
How can I initialise myNewMap with myInitialMap?
You can use myInitialMap.toList().toMutableStateMap().
The ...Of() functions in Kotlin all follow the convention of taking individual entries as varargs, which is why mapOf(myInitialMap) doesn't, and shouldn't, work. Since these functions use the arguments to determine the generic types, the list/set versions could not possibly support also having overloads that accept an Iterable parameter with all the entries to include, because you might actually want a list of Iterables (2D collection). For consistency, mapOf must behave the same.
Function naming/behavior conventions:
...Of(): A function taking a vararg parameter of all the individual values to put in the collection. The argument type can be used for the compiler to infer the generic type(s) of the collection.
.to...Map/Set/List(): An extension function that creates a shallow copy or new type of collection from the entries of the collection it is called on.
.as...(): An extension function that wraps the original object in another one. For example, asIterable() or asSequence() will return those types, but they will read from the original object. They are not copies.
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
I've created multiple graphs in separate files.
The first one is GraphA and it's includes GraphB. the startDestination of GraphB is FragmentB that has an argument named AnID
Now I want to pass the AnID from GraphA to GraphB (FragmentB)
Despite of the editor know about the argument but generated codes don't regard the argument:
val directionB = FragmentADirections.actionFragmentAToGraphB(/* HAS NOT ARGUMENT */)
findNavController().navigate(directionB)
How can I pass the argument to a nested graph?
I found this but it's not an official solution:
val direction = FragmentADirections.actionFragmentAToGraphB()
findNavController().navigate(direction.actionId, FragmentBArgs(anId).toBundle())
Update:
someone introduced another way by defining nested-graph arguments in action
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.