使用appcompat时设置RecyclerView边缘发光前棒棒糖

Bil*_*yan 3 android colors android-appcompat android-recyclerview

我正在寻找一种方法来在使用appcompat材料主题时在RecyclerView pre-lollip中设置过度滚动指示器的颜色.

在内部,它使用EdgeEffect设置为内部可设置属性,除非你已经在棒棒糖(讽刺),否则无法设置.

使用反射不起作用,只能在棒棒糖上设置EdgeEffect的颜色.

在我的API21应用程序上它从主要材料颜色绘制,在Kitkat它是白色的,之前它是全息蓝色,我想要统一我的设计.

关于它是如何完成的任何想法?

Tim*_*eed 7

使用以下设置边缘效果发光颜色.适用于支持EdgeEffect(API 14+)的所有平台版本,否则将无声地失败.

void themeRecyclerView(Context context, RecyclerView recyclerView) {
    int yourColor = Color.parseColor("#your_color");
    try {
        final Class<?> clazz = RecyclerView.class;
        for (final String name : new String[]{"ensureTopGlow", "ensureBottomGlow", "ensureLeftGlow", "ensureRightGlow"}) {
            Method method = clazz.getDeclaredMethod(name);
            method.setAccessible(true);
            method.invoke(recyclerView);
        }
        for (final String name : new String[]{"mTopGlow", "mBottomGlow", "mRightGlow", "mLeftGlow"}) {
            final Field field = clazz.getDeclaredField(name);
            field.setAccessible(true);
            final Object edge = field.get(recyclerView);
            final Field fEdgeEffect = edge.getClass().getDeclaredField("mEdgeEffect");
            fEdgeEffect.setAccessible(true);
            setEdgeEffectColor((EdgeEffect) fEdgeEffect.get(edge), yourColor);
        }
    } catch (final Exception | NoClassDefFoundError ignored) {
    }
}

void setEdgeEffectColor(EdgeEffect edgeEffect, int color) {
    try {
        if (Build.VERSION.SDK_INT >= 21) {
            edgeEffect.setColor(color);
            return;
        }

        for(String name : new String[]{"mEdge", "mGlow"}){
            final Field field = EdgeEffect.class.getDeclaredField(name);
            field.setAccessible(true);
            final Drawable drawable = (Drawable) field.get(edgeEffect);
            drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
            drawable.setCallback(null);
        }
    } catch (final Exception | NoClassDefFoundError ignored) {
    }
}
Run Code Online (Sandbox Code Playgroud)

感谢@Lukas Novak提供了大部分代码.

正如Lukas所说,这些方法必须从onScrollListener你的内部调用RecyclerView:

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
      @Override
      public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
           super.onScrollStateChanged(recyclerView, newState);
           EdgeChanger.setEdgeGlowColor(recycler, getResources().getColor(R.color.your_color));
      }
});
Run Code Online (Sandbox Code Playgroud)


Luk*_*vak 5

谢谢@TomášLinhart指出来.以下解决方案仅用于在API> 21中更改边缘颜色.它可以与AppCompat一起使用,但只有在棒棒糖及以上才能看到改变颜色的效果.


我找到了一种使用反射设置颜色的方法.例如,这里是更改顶部和底部边缘颜色的代码:

public static void setEdgeGlowColor(final RecyclerView recyclerView, final int color) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        try {
            final Class<?> clazz = RecyclerView.class;
            for (final String name : new String[] {"ensureTopGlow", "ensureBottomGlow"}) {
                Method method = clazz.getDeclaredMethod(name);
                method.setAccessible(true);
                method.invoke(recyclerView);
            }
            for (final String name : new String[] {"mTopGlow", "mBottomGlow"}) {
                final Field field = clazz.getDeclaredField(name);
                field.setAccessible(true);
                final Object edge = field.get(recyclerView); // android.support.v4.widget.EdgeEffectCompat
                final Field fEdgeEffect = edge.getClass().getDeclaredField("mEdgeEffect");
                fEdgeEffect.setAccessible(true);
                ((EdgeEffect) fEdgeEffect.get(edge)).setColor(color);
            }
        } catch (final Exception ignored) {}
    }
}
Run Code Online (Sandbox Code Playgroud)

不像像ListView的滚动型或其他组件的解决方案,在这里,你必须调用包私有方法ensureTopGlow,ensureBottomGlow等等,并调用setEdgeEffectColor(RecyclerView recycler, int color)上面onScrollStateChanged的方法RecyclerView.OnScrollListener.

例如:

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
      @Override
      public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
           super.onScrollStateChanged(recyclerView, newState);
           EdgeChanger.setEdgeGlowColor(recycler, getResources().getColor(R.color.your_color));
      }
});
Run Code Online (Sandbox Code Playgroud)

默认情况下,Android通过ensure*Glow滚动开始调用方法.在这些方法中,初始化的new EdgeEffect具有默认颜色,但仅在尚未初始化时.要防止出现这种情况,您必须调用ensure*Glow方法,然后更改边缘的颜色,以便后续初始化EdgeEffect将被忽略(如setEdgeGlowColor上面的方法)

  • 您的解决方案没有回答这个问题,因为它是关于如何在使用appcompat时在棒棒糖前进行,而您的解决方案仅适用于Lollipop. (3认同)