为什么在我使用 viewmodel 时 onClick 方法不调用 ratingBar?
Why onClick method don't call for ratingBar when i'm using viewmodel?
我有一个 recyclerView,它的每个元素都有一个 ratingBar。我尝试获取用户对每个元素的评分。
我正在使用 MVVM 架构。
现在这是我的代码:
<RatingBar
android:id="@+id/rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:numStars="5"
android:stepSize="1"
android:onClick="@{(view) -> listener.rateMovie(view, model)}"
app:layout_constraintTop_toBottomOf="@id/movie_poster"
app:layout_constraintEnd_toEndOf="@id/movie_poster"
app:layout_constraintStart_toStartOf="@id/movie_poster"
/>
override fun rateMovie(
ratingBar: View,
pickedMovieItemViewModel: PickedMovieItemViewModel
) {
ratingBar as RatingBar
val stars: Int = ratingBar.numStars
pickedMovieItemViewModel.rating.set(stars)
}
这是我初始化侦听器的地方:
@BindingAdapter("rated_movies", "listener")
@JvmStatic
fun setItems(
recyclerView: RecyclerView,
items: List<PickedMovieItemViewModel>?,
rateListener: RateListener?
) {
var adapter = recyclerView.adapter
if (adapter == null) {
adapter = RateMoviesAdapter()
recyclerView.adapter = adapter
val layoutManager: RecyclerView.LayoutManager =
LinearLayoutManager(recyclerView.context, LinearLayoutManager.HORIZONTAL, false)
recyclerView.layoutManager = layoutManager
}
if (items != null) {
adapter as RateMoviesAdapter
adapter.updateItems(items)
}
if (items != null && rateListener != null) {
adapter as RateMoviesAdapter
adapter.updateListener(rateListener)
}
}
这是 recycler-view 的适配器
class RateMoviesAdapter : RecyclerView.Adapter<RateMoviesAdapter.RateMoviesViewHolder>() {
private lateinit var movies: List<PickedMovieItemViewModel>
private lateinit var listener: RateListener
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): RateMoviesViewHolder {
val binding: ItemMovieRatedBinding = DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.item_movie_rated,
parent,
false
)
return RateMoviesViewHolder(binding)
}
override fun onBindViewHolder(holder: RateMoviesViewHolder, position: Int) {
val item = movies[position]
holder.bind(item, listener)
}
override fun getItemCount(): Int {
return movies.size
}
fun update(
movies: List<PickedMovieItemViewModel>,
rateListener: RateListener
) {
this.movies = movies
this.listener = rateListener
notifyDataSetChanged()
}
class RateMoviesViewHolder(private val binding: ItemMovieRatedBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: PickedMovieItemViewModel, rateListener: RateListener) {
binding.model = item
binding.listener = rateListener
}
}
}
这是回收站视图所在的布局
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="viewModel"
type="com.example.moviepicker.presentation.viewmodel.RateMoviesViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".presentation.activity.RateMoviesActivity">
<TextView
android:id="@+id/rate_textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin"
android:gravity="center"
android:text="@string/please_give_us_a_review_for_movies_you_have_picked"
android:textColor="@color/red_dark"
android:textSize="@dimen/title_size"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_pickedMovies"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/top_margin"
app:listener="@{viewModel::rateMovie}"
app:rated_movies="@{viewModel.pickedMovies}"
android:foregroundGravity="center"
app:layout_constraintTop_toBottomOf="@id/rate_textView" />
<Button
android:id="@+id/login_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/top_margin"
android:layout_marginTop="@dimen/button_top_margin"
android:layout_marginEnd="@dimen/top_margin"
android:layout_marginBottom="@dimen/top_margin"
android:background="@drawable/ic_red_button"
android:onClick="@{() -> viewModel.goMainPage()}"
android:shadowColor="@color/black"
android:shadowDx="1.5"
android:shadowDy="1.3"
android:shadowRadius="10"
android:text="@string/next"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="@dimen/text_size"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/rv_pickedMovies" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
从未调用过 rateMovie 方法。
我哪里错了?
您正在回收商的适配器中定义不同的侦听器,您需要从您的 fragment/videmodel 传递侦听器,该侦听器已在此处实现和覆盖。
YourFragment : Fragment(), RateListener {
val yourAdapter = RateMoviesAdapter(this)
}
其中“this”表示已实现的侦听器(接口),并在适配器中应用该侦听器。
然后应该工作
OnClick 事件不会在 RatingBar 视图上触发,因此我使用 setOnRatingBarChangeListener()
方法从 RatingBar 获取回调。并从 ItemViewRateBinding
中删除 android:onClick="@{(view) -> listener.rateMovie(view,model)}"
。喜欢:
fun bind(item: PickedMovieItemViewModel, rateListener: RateListener) {
binding.model = item
//binding.listener = rateListener
// Click listener is not working on Rating Bar.
binding.rating.setOnRatingBarChangeListener { ratingBar, rating, fromUser ->
rateListener.rateMovie(ratingBar,item)
}
}
item_view_rate.xml
<layout>
<data>
<variable
name="model"
type="com.adhoc.testapplication.PickedMovieItemViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<RatingBar
android:id="@+id/rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:numStars="5"
android:stepSize="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
<!--
android:onClick="@{(view) -> listener.rateMovie(view,model)}"
-->
我有一个 recyclerView,它的每个元素都有一个 ratingBar。我尝试获取用户对每个元素的评分。
我正在使用 MVVM 架构。
现在这是我的代码:
<RatingBar
android:id="@+id/rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:numStars="5"
android:stepSize="1"
android:onClick="@{(view) -> listener.rateMovie(view, model)}"
app:layout_constraintTop_toBottomOf="@id/movie_poster"
app:layout_constraintEnd_toEndOf="@id/movie_poster"
app:layout_constraintStart_toStartOf="@id/movie_poster"
/>
override fun rateMovie(
ratingBar: View,
pickedMovieItemViewModel: PickedMovieItemViewModel
) {
ratingBar as RatingBar
val stars: Int = ratingBar.numStars
pickedMovieItemViewModel.rating.set(stars)
}
这是我初始化侦听器的地方:
@BindingAdapter("rated_movies", "listener")
@JvmStatic
fun setItems(
recyclerView: RecyclerView,
items: List<PickedMovieItemViewModel>?,
rateListener: RateListener?
) {
var adapter = recyclerView.adapter
if (adapter == null) {
adapter = RateMoviesAdapter()
recyclerView.adapter = adapter
val layoutManager: RecyclerView.LayoutManager =
LinearLayoutManager(recyclerView.context, LinearLayoutManager.HORIZONTAL, false)
recyclerView.layoutManager = layoutManager
}
if (items != null) {
adapter as RateMoviesAdapter
adapter.updateItems(items)
}
if (items != null && rateListener != null) {
adapter as RateMoviesAdapter
adapter.updateListener(rateListener)
}
}
这是 recycler-view 的适配器
class RateMoviesAdapter : RecyclerView.Adapter<RateMoviesAdapter.RateMoviesViewHolder>() {
private lateinit var movies: List<PickedMovieItemViewModel>
private lateinit var listener: RateListener
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): RateMoviesViewHolder {
val binding: ItemMovieRatedBinding = DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.item_movie_rated,
parent,
false
)
return RateMoviesViewHolder(binding)
}
override fun onBindViewHolder(holder: RateMoviesViewHolder, position: Int) {
val item = movies[position]
holder.bind(item, listener)
}
override fun getItemCount(): Int {
return movies.size
}
fun update(
movies: List<PickedMovieItemViewModel>,
rateListener: RateListener
) {
this.movies = movies
this.listener = rateListener
notifyDataSetChanged()
}
class RateMoviesViewHolder(private val binding: ItemMovieRatedBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: PickedMovieItemViewModel, rateListener: RateListener) {
binding.model = item
binding.listener = rateListener
}
}
}
这是回收站视图所在的布局
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="viewModel"
type="com.example.moviepicker.presentation.viewmodel.RateMoviesViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".presentation.activity.RateMoviesActivity">
<TextView
android:id="@+id/rate_textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin"
android:gravity="center"
android:text="@string/please_give_us_a_review_for_movies_you_have_picked"
android:textColor="@color/red_dark"
android:textSize="@dimen/title_size"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_pickedMovies"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/top_margin"
app:listener="@{viewModel::rateMovie}"
app:rated_movies="@{viewModel.pickedMovies}"
android:foregroundGravity="center"
app:layout_constraintTop_toBottomOf="@id/rate_textView" />
<Button
android:id="@+id/login_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/top_margin"
android:layout_marginTop="@dimen/button_top_margin"
android:layout_marginEnd="@dimen/top_margin"
android:layout_marginBottom="@dimen/top_margin"
android:background="@drawable/ic_red_button"
android:onClick="@{() -> viewModel.goMainPage()}"
android:shadowColor="@color/black"
android:shadowDx="1.5"
android:shadowDy="1.3"
android:shadowRadius="10"
android:text="@string/next"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="@dimen/text_size"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/rv_pickedMovies" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
从未调用过 rateMovie 方法。
我哪里错了?
您正在回收商的适配器中定义不同的侦听器,您需要从您的 fragment/videmodel 传递侦听器,该侦听器已在此处实现和覆盖。
YourFragment : Fragment(), RateListener {
val yourAdapter = RateMoviesAdapter(this)
}
其中“this”表示已实现的侦听器(接口),并在适配器中应用该侦听器。 然后应该工作
OnClick 事件不会在 RatingBar 视图上触发,因此我使用 setOnRatingBarChangeListener()
方法从 RatingBar 获取回调。并从 ItemViewRateBinding
中删除 android:onClick="@{(view) -> listener.rateMovie(view,model)}"
。喜欢:
fun bind(item: PickedMovieItemViewModel, rateListener: RateListener) {
binding.model = item
//binding.listener = rateListener
// Click listener is not working on Rating Bar.
binding.rating.setOnRatingBarChangeListener { ratingBar, rating, fromUser ->
rateListener.rateMovie(ratingBar,item)
}
}
item_view_rate.xml
<layout>
<data>
<variable
name="model"
type="com.adhoc.testapplication.PickedMovieItemViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<RatingBar
android:id="@+id/rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:numStars="5"
android:stepSize="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
<!--
android:onClick="@{(view) -> listener.rateMovie(view,model)}"
-->