我想创建一个RecyclerView
,在其项目之上绘制一个选择器。它应该呈现在项目之上,这意味着我不能简单地将StateListDrawable
设置为项目背景。
我对压制状态特别感兴趣,即如果(并且仅当)按下某个项目,应该绘制一些东西。
RecyclerView.ItemDecoration
能够绘制RecyclerView
的项目。这是我到目前为止所尝试的:
public final class ItemPressedDecoration extends RecyclerView.ItemDecoration {
private final Rect rect = new Rect();
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
final int count = parent.getChildCount();
for (int index = 0; index < count; index++) {
final View child = parent.getChildAt(index);
if (child.isPressed()) {
drawOverlay(c, child);
}
}
}
private void drawOverlay(Canvas c, View child) {
c.save();
rect.set(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
c.clipRect(rect);
c.drawColor(0x80ff0000);
c.restore();
}
}
问题是RecyclerView
似乎没有重绘项目装饰,如果其中一个孩子的可绘制状态发生变化。那么如何让它做到呢?
我尝试添加RecyclerView.OnItemTouchListener
并从recyclerView.invalidate()
方法调用onInterceptTouchEvent()
,但这不起作用。
答案 0 :(得分:7)
如果您可以使用FrameLayout
作为root用户,并且您的选择器是半透明的,则下面的布局可能会有用。
android:foreground
,而不是android:background
布局/ view_listitem.xml
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="@drawable/your_selector">
<!-- your list items -->
</FrameLayout>
答案 1 :(得分:2)
我找到了一个似乎有用的解决方案。我必须继承RecyclerView
以使视图无效并强制再次绘制项目装饰。
public class ChildDrawableStateRecyclerView extends RecyclerView {
/* constructors omitted */
@Override
public void childDrawableStateChanged(View child) {
super.childDrawableStateChanged(child);
// force ItemDecorations to be drawn
invalidate();
}
}
我不知道这是否是正确的方法。如果您有任何答案,请提供更好的答案。
我还必须检查是否可以通过这种方式实现涟漪效应。
答案 2 :(得分:2)
我最终使用了一种完全不同的方法。我没有实现RecyclerView.ItemDecoration
,而是编写了一个可以在前台绘制选择器的RelativeLayout
子类。我将此布局用作所有需要选择器的列表项的容器。
这种方法似乎也适用于波纹绘制。
public class SelectorRelativeLayout extends RelativeLayout {
public static final int[] ATTRS_LIST_SELECTOR = { android.R.attr.listSelector };
private final Drawable selector;
public SelectorRelativeLayout(Context context) {
this(context, null);
}
public SelectorRelativeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SelectorRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, ATTRS_LIST_SELECTOR, 0, 0);
selector = a.getDrawable(0);
a.recycle();
if (selector != null) {
setWillNotDraw(false);
selector.setCallback(this);
}
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
final Drawable d = selector;
if (d != null && d.isStateful()) {
d.setState(getDrawableState());
}
}
@Override
public void jumpDrawablesToCurrentState() {
super.jumpDrawablesToCurrentState();
final Drawable d = selector;
if (d != null) {
d.jumpToCurrentState();
}
}
@Override
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void drawableHotspotChanged(float x, float y) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return;
}
super.drawableHotspotChanged(x, y);
final Drawable d = selector;
if (d != null) {
d.setHotspot(x, y);
}
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
final Drawable d = selector;
if (d != null) {
d.setBounds(0, 0, getWidth(), getHeight());
d.draw(canvas);
}
}
@Override
protected boolean verifyDrawable(Drawable who) {
return who == selector || super.verifyDrawable(who);
}
}