Composite clock model app
This is an example application to show how to create an application that follows the non-user interface practices described in the Compose (UI) series.
In short, these practices allow you to manage configuration changes manually and avoid AAC ViewModels in applications that are fully compiled. To understand why, please read the articles (Part I, Part II, Part III).
This application uses simulated data to save time on API requests and avoid using identifiers.
Project specifications
- Compiling a user interface for everything (beta01)
- MVVM Architecture
- No use of AppCompatActivity, Fragment, or AAC ViewModel
- Changes to the parameters are processed manually: Changes in language or alignment are not reinstated.
- Registration for DI and View screens and navigation charts
- Coroutines and flows
- The status of the application is saved, with utilities that simplify the use of the flow
- ViewModels are visualized on screens, on screens (nested graph) and on the whole application.
- Navigation component (with wizards for managing the circle of relatives and creating routes)
- Layout that adapts to landscape or multiple windows (with a simple animation).
- Clock that can be customized to your theme
- Switch to force a different locale without recreating the activity.
- Navigation in the bottom bar that maintains proper selection on the sub-screens.
- Some simple animations (when resizing different windows in the control panel, when changing the time, when selecting a clock type or in the preview window of the image)
- Matching reel for displaying images
Application Description
This application has a navigation bar at the bottom with three destinations. The first is the settings screen, where you can change the language and theme of the clock (change the color of certain parts of the clock).
The second screen shows a list of cities with a picture and a clock showing the local time. Clicking on a city brings the user to a detailed information screen where they can see the time zone and a description of the city.
Finally, the user can add a city to the list on the third destination line at the bottom. It’s a two-screen stream, and you can go back and forth without losing data. On the first screen of this feed, you can enter the name of the city and select the time zone and clock style. In the second screen, the user can then enter a description and the URL of the image they wish to view. Adding a city brings the user to the list of cities with a new addition.
dial | Size change |
---|---|
Non-AAC ViewModels (or ViewControllers)
To create our own ViewModels, we need the following items:
- A way to query the same instance as long as its lifecycle is active, or in other words, until the user has left the screen or view.
- A way to clean up at the end of the lifecycle, to cancel ongoing tasks such as. B. the Coruscant.
- A way to store the status of the user.
To retrieve the same ViewController instance when it is active, this example uses the Koin scope: getOrCreateScope. To know which instance to retrieve, the navigation path with the filled parameters is used as the identifier.
To clear ViewControllers and other scoped instances that need to be cleared, these instances implement the Clearable interface and are declared with the Clearable::class binding in Koin.
To replace the scope when the user leaves the target, we used the RunOnce utility (which uses memorySaveable) and then LifecycleEventObserver set to NavBackStackEntry from the target.
There are some tools to support this process, which are explained in more detail in the navigation tools.
Finally, to save the state in ViewModels bound to a navigation target, we can get SavedStatHandle from NavBackStackEntry. For other cases, compose offers memorySaveable. To unify the memory state, this application has a StateSaver interface with two implementations, one for each case. This way, classes that need to preserve their state don’t have to worry about specific implementations, and state preservation is platform independent.
Local force
The application allows you to change the switching language (Spanish and English only). Changing the language is done without repeating the steps, which speeds up operation and prevents the screen from flashing.
In newer versions of Android, to force a locale change, it is supposed to use attachBaseContext, which depends on activity recreation to work.
An alternative is to use the deprecated resource resources.updateConfiguration. This works without recreating the activity, but is obsolete due to problems in WebView with night mode requiring a resource configuration change.
There is a new way to change the language in the composition, which is to use CompositionLocalProvider and specify an updated context and LayoutDirection. However, since beta01, the bottom navigation bar in the frame does not update when the locale is changed. It is only updated if, for example. B. changes the orientation of the screen.
I discovered this problem, which you can call a star if it concerns you. For an example of the traditional approach, see SetLanguage, and for an example of the composite alternative – which doesn’t work well yet – see LanguageOverride.
Navigation aids
This example shows utilities that help navigate with screen globes and nested diagrams. These wizards should use the templates provided to create the navigation paths.
If you know how to navigate with the Navigation Component and how to use the Koin scopes, the following sections describe the small changes you should make if you decide to use these tools. In fact, you have to use different functions to declare targets, declare classes to define each target (which extend the corresponding parent scopes), and declare Koin scopes in a specific way. In return, you get a range that is automatically maintained for your navigation targets (screens and nested images); and a thoughtful way of declaring targets and arguments that helps with path construction.
Screen report in NavHost
This can be done with the following syntax: scopedComposable(YourDestination) { NavEntry, scope -> where YourDestination is an instance of the class that extends NavDestination.
The scope parameter is a part scope that can be used to retrieve instances bound to the screen boundaries, e.g. B. a ViewModel or other ViewController.
Announcement of embedded chart in NavHost
This can be done with the following syntax: scopedNavigation(YourSubgraph) { NestedNavGraph -> where YourSubgraph is an instance of the class that extends NestedNavGraph.
This function allows you to specify endpoints in a nested graph:
doubleScopedComposable(
NavController, nestedNavGraph, YourDestination
) { NavEntry, parentScope, scope ->)
Here, YourDestination is also an instance of the class that extends NavDestination, and nestedNavGraph is the parameter provided by scopedNavigation. You will get two windows, one for this screen and one for the embedded image. So if you need to set the range of a ViewController (or whatever) for the entire screen stream, you can do that with this range.
Rating definition
To specify a screen destination, create an object that extends ScreenDestination or ScreenDestinationWithArgs and specify the navigation route, argument list (such as NavArguments), and parameter class.
The params class must extend NavParams and enumerate the parameters in the same order as they were declared in the target arguments. If the argument is optional, use it to create the list: YourNavArgument.paramsAsRoute(parameterVariable).
Set nested target surface
To declare a nested destination graph, create an object that extends SubgraphDestination or SubgraphDestinationWithArgs and specify the navigation route, a list of arguments (such as NavArguments), an initial destination, and a parameter class for the subgraph and initial destination.
Navigate to destination without parameters
You can use NavController.navigate(YourDestination.buildRoute(NoParams)), or the less explicit YourDestination.declaredPath.
Navigate to a destination with parameters
You can pass YourDestination.buildRoute(DestinationNavParams(firstParam, secondParam)) to the navigation function.
Navigate to a destination with optional NavParams
If you have additional parameters, you must declare them as OptionalParam in NavParam. Then use OptionalParam.Provided(id) or OptionalParam.Default.
Declare part field for screen
Pass ScreenDestination as a range qualifier. Then, implement Clearable in all scope instances that need a callback when the scope is cancelled, and declare them with the Clearable::class binding. Example:
scope {
scoped { YourViewModel() } bind Clearable::class
}
Define appearance limits for nested graphics
Instead of a scope, you can use NavGraphScope, which automatically manages the lifecycle. You can then declare your objects internally, as described in the previous section.
Related Tags:
jetpack compose example,jetpack compose image,jetpack compose recyclerview,jetpack compose navigation,jetpack compose release date,jetpack compose github,Privacy settings,How Search works,jetpack compose livedata,jetpack compose codelab