在 androidx.recyclerview.widget.RecyclerView 上找不到参数类型为布尔值的属性 'app:fastScrollEnabled' 的 setter
Cannot find the setter for attribute 'app:fastScrollEnabled' with parameter type boolean on androidx.recyclerview.widget.RecyclerView
我已经尝试设置 ObservableField 或 String 值,但仍然无效。如果我只是设置一个静态的 true 或 false 值而不是 viewModel 引用,它就可以工作。
布局文件:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="app.viewmodel.ViewModel"/>
</data>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:fastScrollEnabled="@{viewModel.isUserAdmin}"
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
app:fastScrollVerticalTrackDrawable="@drawable/line_drawable"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
</layout>
ViewModel:
class AppointmentsViewModel()
{
val isUserAdmin: Boolean = sharedPreferencesRepo.isUserAdmin
}
RecyclerView
目前没有 public 代码设置快速滚动属性的方法。在撰写本文时,启用快速滚动的唯一方法是在布局中设置相关属性 XML。 RecyclerView
然后从其构造函数调用一个私有方法来设置它。
数据绑定库在生成其适配器代码时找不到 public 属性的 fastScrollEnabled
方法,这就是您收到该错误的原因。只是现在还不可能。
有 a request in the Issue Tracker to add the relevant functionality to RecyclerView
, and even a comment there that points out the data binding limitation,但目前似乎不是高优先级。
如果您不介意一些额外的工作,我们实际上可以手动完成此操作,因为 RecyclerView
的 FastScroller
实现只是 ItemDecoration
和 OnItemTouchListener
.我们可以从库源复制 class 并在外部设置它,允许我们以编程方式启用和禁用快速滚动,从而通过数据绑定来处理它。
直接复制 the current FastScroller
class 应该只需要进行一些明显的小修改(例如,更改 package
、一些注释等),下面的示例假定您已经完成以原名复制,FastScroller
.
有一个重要的补充是允许从 RecyclerView
中无错误地分离 FastScroller
。 (事实上 ,它似乎还没有出现。)在 FastScroller
的 destroyCallbacks()
方法中,添加对 mShowHideAnimator.cancel()
:
的调用
private void destroyCallbacks() {
mRecyclerView.removeItemDecoration(this);
mRecyclerView.removeOnItemTouchListener(this);
mRecyclerView.removeOnScrollListener(mOnScrollListener);
cancelHide();
// ADD THIS
mShowHideAnimator.cancel();
}
幸运的是,FastScroller
在实例化后基本上不需要进一步关注,并且由于这无论如何都是在替换 RecyclerView
-内部功能,因此将每个 FastScroller
实例附加到它的 RecyclerView
作为标签,因此我们不必在其他任何地方跟踪这些实例。我们只需要在以后检索它们一次即可分离,这种安排非常适合数据绑定设置。
我们需要定义一个唯一的资源 ID 作为我们的标签键。可以放在res/values/
文件夹下的任意资源文件中; /res/values/ids.xml
会很合适,如果你喜欢整洁。
<resources>
<id name="recycler_view_fast_scroller_tag_key" />
</resources>
我们的 FastScroller
初始化代码1 本质上是对 RecyclerView
及其构造函数中初始化的重新排序,合并到 static
实用程序中方法:
static void initFastScroller(RecyclerView recyclerView) {
Resources resources = recyclerView.getContext().getResources();
Resources.Theme theme = recyclerView.getContext().getTheme();
StateListDrawable verticalThumbDrawable = (StateListDrawable)
ResourcesCompat.getDrawable(resources, R.drawable.thumb_drawable, theme);
Drawable verticalTrackDrawable =
ResourcesCompat.getDrawable(resources, R.drawable.line_drawable, theme);
StateListDrawable horizontalThumbDrawable = (StateListDrawable)
ResourcesCompat.getDrawable(resources, R.drawable.thumb_drawable, theme);
Drawable horizontalTrackDrawable =
ResourcesCompat.getDrawable(resources, R.drawable.line_drawable, theme);
if (verticalThumbDrawable == null || verticalTrackDrawable == null
|| horizontalThumbDrawable == null || horizontalTrackDrawable == null) {
throw new IllegalArgumentException(
"Trying to set fast scroller without all required drawables.");
}
FastScroller fastScroller =
new FastScroller(recyclerView, verticalThumbDrawable, verticalTrackDrawable,
horizontalThumbDrawable, horizontalTrackDrawable,
resources.getDimensionPixelSize(R.dimen.fastscroll_default_thickness),
resources.getDimensionPixelSize(R.dimen.fastscroll_minimum_range),
resources.getDimensionPixelOffset(R.dimen.fastscroll_margin));
recyclerView.setTag(R.id.recycler_view_fast_scroller_tag_key, fastScroller);
}
为简单起见,此示例将所有特定资源选择移至 initFastScroller()
方法中,但当然可以根据需要修改和重新排列;例如,进入自定义 RecyclerView
subclass。此外,您可以在此处指定您喜欢的任何维度参数,尽管该示例使用 RecyclerView
包中的默认资源值。2
drawables现在是动态处理的,所以需要从布局中移除它们对应的属性设置XML:3
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:fastScrollEnabled="@{viewModel.isUserAdmin}"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
最后,为了将所有这些结合在一起,setFastScrollEnabled()
方法展示了我们如何以编程方式启用和禁用快速滚动,我们将其注释为 BindingAdapter
以将该功能公开给数据通过 fastScrollEnabled
属性绑定:
@BindingAdapter("fastScrollEnabled")
public static void setFastScrollEnabled(RecyclerView recyclerView, boolean setEnabled) {
Object fastScroller = recyclerView.getTag(R.id.recycler_view_fast_scroller_tag_key);
boolean isEnabled = fastScroller instanceof FastScroller;
if (setEnabled != isEnabled) {
if (setEnabled) {
initFastScroller(recyclerView);
} else {
// Detach the FastScroller from the RecyclerView
((FastScroller) fastScroller).attachToRecyclerView(null);
// Nullify our only reference to it
recyclerView.setTag(R.id.recycler_view_fast_scroller_tag_key, null);
}
}
}
此方法首先在 R.id.recycler_view_fast_scroller_tag_key
的 RecyclerView
上检查我们的 FastScroller
标签。如果它在那里,则当前启用快速滚动,否则禁用。如果该状态与我们被调用设置的状态不同,则继续初始化和 setTag()
FastScroller
(它处理在实例化时将自身附加到 RecyclerView
内部),或者分离它并使标签无效。
1 Java 中提供这些方法仅仅是因为这是从原始来源借用的代码语言。如果您更愿意在 Kotlin 中使用它,Android Studio 可以作为第一步自动转换它,但您可能希望进一步 syntax/structural/etc。调整。
2 给定的三个 R.dimen
在我的测试中都没有问题地解决和构建,有点出乎意料。如果您确实想使用这些默认值但遇到问题,您也可以复制相应的 <dimen>
s from the library source。
3 这应该可以在 fastScrollEnabled
属性上有或没有 app
命名空间前缀,因为它显然是 ignored/stripped 由数据绑定框架。它留在XML这里只是为了显示必要的最小变化。
当然,这一切也独立于数据绑定工作,并且它可以改编成更合适的实用方法,或 Kotlin 扩展,例如:
var RecyclerView.isFastScrollEnabled: Boolean
get() = getTag(R.id.recycler_view_fast_scroller_tag_key) is FastScroller
set(value) {
if (value != isFastScrollEnabled) {
if (value) {
// Convert initFastScroller() from above as you like
initFastScroller(this)
} else {
// Detach the FastScroller from the RecyclerView
(getTag(R.id.recycler_view_fast_scroller_tag_key) as FastScroller)
.attachToRecyclerView(null)
// Nullify our only reference to it
setTag(R.id.recycler_view_fast_scroller_tag_key, null)
}
}
}
我已经尝试设置 ObservableField 或 String 值,但仍然无效。如果我只是设置一个静态的 true 或 false 值而不是 viewModel 引用,它就可以工作。
布局文件:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="app.viewmodel.ViewModel"/>
</data>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:fastScrollEnabled="@{viewModel.isUserAdmin}"
app:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
app:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
app:fastScrollVerticalTrackDrawable="@drawable/line_drawable"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
</layout>
ViewModel:
class AppointmentsViewModel()
{
val isUserAdmin: Boolean = sharedPreferencesRepo.isUserAdmin
}
RecyclerView
目前没有 public 代码设置快速滚动属性的方法。在撰写本文时,启用快速滚动的唯一方法是在布局中设置相关属性 XML。 RecyclerView
然后从其构造函数调用一个私有方法来设置它。
数据绑定库在生成其适配器代码时找不到 public 属性的 fastScrollEnabled
方法,这就是您收到该错误的原因。只是现在还不可能。
有 a request in the Issue Tracker to add the relevant functionality to RecyclerView
, and even a comment there that points out the data binding limitation,但目前似乎不是高优先级。
如果您不介意一些额外的工作,我们实际上可以手动完成此操作,因为 RecyclerView
的 FastScroller
实现只是 ItemDecoration
和 OnItemTouchListener
.我们可以从库源复制 class 并在外部设置它,允许我们以编程方式启用和禁用快速滚动,从而通过数据绑定来处理它。
直接复制 the current FastScroller
class 应该只需要进行一些明显的小修改(例如,更改 package
、一些注释等),下面的示例假定您已经完成以原名复制,FastScroller
.
有一个重要的补充是允许从 RecyclerView
中无错误地分离 FastScroller
。 (事实上 ,它似乎还没有出现。)在 FastScroller
的 destroyCallbacks()
方法中,添加对 mShowHideAnimator.cancel()
:
private void destroyCallbacks() {
mRecyclerView.removeItemDecoration(this);
mRecyclerView.removeOnItemTouchListener(this);
mRecyclerView.removeOnScrollListener(mOnScrollListener);
cancelHide();
// ADD THIS
mShowHideAnimator.cancel();
}
幸运的是,FastScroller
在实例化后基本上不需要进一步关注,并且由于这无论如何都是在替换 RecyclerView
-内部功能,因此将每个 FastScroller
实例附加到它的 RecyclerView
作为标签,因此我们不必在其他任何地方跟踪这些实例。我们只需要在以后检索它们一次即可分离,这种安排非常适合数据绑定设置。
我们需要定义一个唯一的资源 ID 作为我们的标签键。可以放在res/values/
文件夹下的任意资源文件中; /res/values/ids.xml
会很合适,如果你喜欢整洁。
<resources>
<id name="recycler_view_fast_scroller_tag_key" />
</resources>
我们的 FastScroller
初始化代码1 本质上是对 RecyclerView
及其构造函数中初始化的重新排序,合并到 static
实用程序中方法:
static void initFastScroller(RecyclerView recyclerView) {
Resources resources = recyclerView.getContext().getResources();
Resources.Theme theme = recyclerView.getContext().getTheme();
StateListDrawable verticalThumbDrawable = (StateListDrawable)
ResourcesCompat.getDrawable(resources, R.drawable.thumb_drawable, theme);
Drawable verticalTrackDrawable =
ResourcesCompat.getDrawable(resources, R.drawable.line_drawable, theme);
StateListDrawable horizontalThumbDrawable = (StateListDrawable)
ResourcesCompat.getDrawable(resources, R.drawable.thumb_drawable, theme);
Drawable horizontalTrackDrawable =
ResourcesCompat.getDrawable(resources, R.drawable.line_drawable, theme);
if (verticalThumbDrawable == null || verticalTrackDrawable == null
|| horizontalThumbDrawable == null || horizontalTrackDrawable == null) {
throw new IllegalArgumentException(
"Trying to set fast scroller without all required drawables.");
}
FastScroller fastScroller =
new FastScroller(recyclerView, verticalThumbDrawable, verticalTrackDrawable,
horizontalThumbDrawable, horizontalTrackDrawable,
resources.getDimensionPixelSize(R.dimen.fastscroll_default_thickness),
resources.getDimensionPixelSize(R.dimen.fastscroll_minimum_range),
resources.getDimensionPixelOffset(R.dimen.fastscroll_margin));
recyclerView.setTag(R.id.recycler_view_fast_scroller_tag_key, fastScroller);
}
为简单起见,此示例将所有特定资源选择移至 initFastScroller()
方法中,但当然可以根据需要修改和重新排列;例如,进入自定义 RecyclerView
subclass。此外,您可以在此处指定您喜欢的任何维度参数,尽管该示例使用 RecyclerView
包中的默认资源值。2
drawables现在是动态处理的,所以需要从布局中移除它们对应的属性设置XML:3
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:fastScrollEnabled="@{viewModel.isUserAdmin}"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
最后,为了将所有这些结合在一起,setFastScrollEnabled()
方法展示了我们如何以编程方式启用和禁用快速滚动,我们将其注释为 BindingAdapter
以将该功能公开给数据通过 fastScrollEnabled
属性绑定:
@BindingAdapter("fastScrollEnabled")
public static void setFastScrollEnabled(RecyclerView recyclerView, boolean setEnabled) {
Object fastScroller = recyclerView.getTag(R.id.recycler_view_fast_scroller_tag_key);
boolean isEnabled = fastScroller instanceof FastScroller;
if (setEnabled != isEnabled) {
if (setEnabled) {
initFastScroller(recyclerView);
} else {
// Detach the FastScroller from the RecyclerView
((FastScroller) fastScroller).attachToRecyclerView(null);
// Nullify our only reference to it
recyclerView.setTag(R.id.recycler_view_fast_scroller_tag_key, null);
}
}
}
此方法首先在 R.id.recycler_view_fast_scroller_tag_key
的 RecyclerView
上检查我们的 FastScroller
标签。如果它在那里,则当前启用快速滚动,否则禁用。如果该状态与我们被调用设置的状态不同,则继续初始化和 setTag()
FastScroller
(它处理在实例化时将自身附加到 RecyclerView
内部),或者分离它并使标签无效。
1 Java 中提供这些方法仅仅是因为这是从原始来源借用的代码语言。如果您更愿意在 Kotlin 中使用它,Android Studio 可以作为第一步自动转换它,但您可能希望进一步 syntax/structural/etc。调整。
2 给定的三个 R.dimen
在我的测试中都没有问题地解决和构建,有点出乎意料。如果您确实想使用这些默认值但遇到问题,您也可以复制相应的 <dimen>
s from the library source。
3 这应该可以在 fastScrollEnabled
属性上有或没有 app
命名空间前缀,因为它显然是 ignored/stripped 由数据绑定框架。它留在XML这里只是为了显示必要的最小变化。
当然,这一切也独立于数据绑定工作,并且它可以改编成更合适的实用方法,或 Kotlin 扩展,例如:
var RecyclerView.isFastScrollEnabled: Boolean
get() = getTag(R.id.recycler_view_fast_scroller_tag_key) is FastScroller
set(value) {
if (value != isFastScrollEnabled) {
if (value) {
// Convert initFastScroller() from above as you like
initFastScroller(this)
} else {
// Detach the FastScroller from the RecyclerView
(getTag(R.id.recycler_view_fast_scroller_tag_key) as FastScroller)
.attachToRecyclerView(null)
// Nullify our only reference to it
setTag(R.id.recycler_view_fast_scroller_tag_key, null)
}
}
}