jetpack组件
In my previous article, we created reusable UIComponents using Jetpack Compose:
在上一篇文章中,我们使用Jetpack Compose创建了可重用的UIComponent:
It had limited capability, as UIComponents could only be laid out on the screen. This article will cover user interactions, like click events, that were not handled.
它的功能有限,因为UIComponents只能放在屏幕上。 本文将介绍未处理的用户交互,例如单击事件。
什么是互动? (What Is Interaction?)
It is an event on the UIComponents (e.g. a click event on the MovieUI
component).
这是UIComponents上的一个事件(例如, MovieUI
组件上的click事件)。
The interaction on the UIComponent will be handled by the ComposeActivity
class that includes UIComponents. For example, a click event on the MovieView
in the HomeScreen
is handled by HomeScreen Activity
.
UIComponent上的交互将由包含UIComponent的ComposeActivity
类处理。 例如, MovieView
上的click事件 在HomeScreen
中,由HomeScreen Activity
处理。
我们正在建设什么? (What Are We Building?)
We have HomeScreen
and MovieDetailScreen
. Both of them contain movies (MovieView
). A click on MovieView
should result in navigation to the MovieDetailScreen
of the clicked movie.
我们有HomeScreen
和MovieDetailScreen
。 它们都包含电影( MovieView
) 。 单击MovieView
应该可以导航到MovieDetailScreen
点击的电影
This calls for following the changes in the Architecture(in red):
这要求遵循体系结构中的更改(红色):
- Our ViewModel (presentation) layer remains the same. 我们的ViewModel(表示)层保持不变。
UIComponent
propagates the events to theComposeActivity
through an interface (UIDelegate
— explained below).UIComponent
通过接口将事件传播到ComposeActivity
(UIDelegate
,在下面进行解释)。ComposeActivity
handles the events by implementing the interface above.ComposeActivity
通过实现上述接口ComposeActivity
处理事件。
让我们来构建它 (Let’s Build it)
First, we need to change the UIComponent. We convert it to a generic interface of type
UIDelegate
. ThecomposableView()
function now takes in the genericUIDelegate
.首先,我们需要更改UIComponent。 我们将其转换为
UIDelegate
类型的通用接口。 现在,composableView()
函数接受通用UIDelegate
。
interface UIDelegate
interface UIComponent<T: UIDelegate> {
@Composable
fun composableView(delegate: T): ComposableView
}
What is UIDelegate
? It’s an interface responsible for sending the UI events/interactions from UIComponent
to View
(activity). This is explained with an example below.
什么是UIDelegate
? 它是一个接口,负责将UI事件/交互从UIComponent
发送到View
(活动)。 下面通过一个示例对此进行说明。
MovieView should now be able to send the click events. As pointed out above, the interactions are handled through the UIDelegate
. For this, the MovieUIDelegate
interface is created with the capability of receiving the clicks on the movie.
电影浏览 现在应该能够发送点击事件。 如上所述,交互是通过UIDelegate
处理的。 为此,创建了MovieUIDelegate
接口,它具有接收电影点击的功能。
This UIDelegate
is passed as an argument to the Composable
function.
该UIDelegate
作为参数传递给Composable
函数。
interface MovieUIDelegate: UIDelegate {
fun movieClick(movie: Movie)
}
/**
* MovieUIDelegate is the extra argument added for handling the interaction.
*/
@Composable
fun MovieView(movie: Movie, delegate: MovieUIDelegate) {
val state = ImageState()
Clickable(onClick = {
// Notifies the UIDelegate that click event has occured on the movie.
delegate.movieClick(movie)
}) {
....
// Everything remains the same
....
}
}
2. Consequently, MovieListUIComponent
is responsible for passing the MovieUIDelegate
to the MovieView
. This is a middle man between the MovieView
and ComposeActivity
.
2 。 因此, MovieListUIComponent
负责将MovieUIDelegate
传递给MovieView
。 这是MovieView
和ComposeActivity
之间的ComposeActivity
。
class MovieListUIComponent(
private val subHeader: String,
private val movieList: List<Movie>
) : UIComponent<MovieUIDelegate> {
/**
* MovieUIDelegate is an argument passed,
* which is then passed on to the MovieView for handling the interaction
*/
override fun composableView(delegate: MovieUIDelegate): ComposableView = {
HMovieListView(header = subHeader, movieList = movieList, delegate = delegate)
}
}
3.View
(Jetpack Compose activity) should implement MovieUIDelegate
to handle the events. A click on the movie opens the MovieDetailScreen
of that movie.
3. View
(Jetpack Compose活动)应实现MovieUIDelegate
来处理事件。 单击电影即可打开MovieDetailScreen
那部电影。
class MovieDetailActivity : AppCompatActivity(), MovieUIDelegate {
fun onCreate() {
...
...
setContent {
// Passes the movieUIDelegate
MovieDetailPageView(vm.pageData, delegate = this)
}
}
// Implements the MovieUIDelegate function
override fun onMovieClick(movie: Movie) {
/**
* Launches the new MovieDetailActivity for the clicked movie
*/
startActivity(getIntent(this, movieId = movie.id))
}
}
The UIDelegate
implemented by the ComposeActivity
is passed to the component while rendering it out on the screen.
由ComposeActivity
实现的UIDelegate
在传递到屏幕上时传递给该组件。
@Composable
fun MovieDetailPageView(data: LiveData<MovieDetailPageUiModel>, delegate: MovieUIDelegate) {
val pageUiModel = observe(data = data)
VStack {
pageUiModel?.components()?.forEach {
/** Additionally UIDelegate is passed to the UIComponent so that
* the activity can handle the interaction
**/
it.composableView(delegate = delegate).render()
}
}
}
You can get the complete code here:
您可以在此处获取完整的代码:
In the case of ComposeActivity
handling multiple components, which usually is the case, it needs to implement all the UIDelegates
of all the UIComponents that it incorporates in its view.
在通常情况下处理ComposeActivity
的情况下,它需要实现其视图中合并的所有UIComponent的所有UIDelegates
。
结论 (Conclusion)
That’s it! We have created a UIComponent that sends events to the outside world. For now, these events are sent to the ComposeActivity
. In the following article, we’ll see how the UIComponent interacts with the presentation layer. Also, we’ll see the inter-communication between UIComponents.
而已! 我们创建了一个UIComponent来将事件发送到外界。 目前,这些事件已发送到ComposeActivity
。 在下面的文章中,我们将看到UIComponent如何与表示层交互。 另外,我们将看到UIComponent之间的相互通信。
jetpack组件