How to change the color of overscroll edge and overscroll glow

人盡茶涼 提交于 2019-11-29 02:52:15

The overscroll glow color inherits the primary color value set by android:colorPrimary in your entire app. But If you need to specify different value simply use android:colorEdgeEffect.

<style name="MyAppTheme" parent="***">
   <item name="android:colorEdgeEffect">@color/my_color</item>
</style>

On LOLLIPOP the edge glow inherits from colorPrimary. After the view is created the edge glow color can only be changed through reflection. This can be useful when you load colors dynamically using Palette.

EDIT: TL;DR: Download the whole class from here: https://github.com/consp1racy/android-commons/blob/master/commons/src/main/java/net/xpece/android/widget/XpEdgeEffect.java

PROGUARD SETUP: If you're going to use this on widgets from support library you need to keep the field names. Quickest way to do it is the following (although still wasteful):

-keepclassmembers class * extends android.view.View {
    <fields>;    
}

-keepclassmembers class android.support.v4.widget.EdgeEffectCompat {
    <fields>;    
}

Create a utility class with the following code:

private static final Class<?> CLASS_SCROLL_VIEW = ScrollView.class;
private static final Field SCROLL_VIEW_FIELD_EDGE_GLOW_TOP;
private static final Field SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM;

private static final Class<?> CLASS_LIST_VIEW = AbsListView.class;
private static final Field LIST_VIEW_FIELD_EDGE_GLOW_TOP;
private static final Field LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM;

static {
  Field edgeGlowTop = null, edgeGlowBottom = null;

  for (Field f : CLASS_SCROLL_VIEW.getDeclaredFields()) {
    switch (f.getName()) {
      case "mEdgeGlowTop":
        f.setAccessible(true);
        edgeGlowTop = f;
        break;
      case "mEdgeGlowBottom":
        f.setAccessible(true);
        edgeGlowBottom = f;
        break;
    }
  }

  SCROLL_VIEW_FIELD_EDGE_GLOW_TOP = edgeGlowTop;
  SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM = edgeGlowBottom;

  for (Field f : CLASS_LIST_VIEW.getDeclaredFields()) {
    switch (f.getName()) {
      case "mEdgeGlowTop":
        f.setAccessible(true);
        edgeGlowTop = f;
        break;
      case "mEdgeGlowBottom":
        f.setAccessible(true);
        edgeGlowBottom = f;
        break;
    }
  }

  LIST_VIEW_FIELD_EDGE_GLOW_TOP = edgeGlowTop;
  LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM = edgeGlowBottom;
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static void setEdgeGlowColor(AbsListView listView, int color) {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    try {
      EdgeEffect ee;
      ee = (EdgeEffect) LIST_VIEW_FIELD_EDGE_GLOW_TOP.get(listView);
      ee.setColor(color);
      ee = (EdgeEffect) LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM.get(listView);
      ee.setColor(color);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static void setEdgeGlowColor(ScrollView scrollView, int color) {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    try {
      EdgeEffect ee;
      ee = (EdgeEffect) SCROLL_VIEW_FIELD_EDGE_GLOW_TOP.get(scrollView);
      ee.setColor(color);
      ee = (EdgeEffect) SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM.get(scrollView);
      ee.setColor(color);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
}

If you're using the latest RecyclerView implementation it is pretty straightforward to change the overflow colour programmatically. Use the following code (Kotlin implementation):

recyclerView.edgeEffectFactory = object : RecyclerView.EdgeEffectFactory() {
    override fun createEdgeEffect(view: RecyclerView, direction: Int): EdgeEffect {
        return EdgeEffect(view.context).apply { setColor(color) }
    }
}

Note that this works only for API level 21 (Lollipop) and above. If you know the value at compile time, use the colorEdgeEffect as pointed out by Ahmed.

In pre-lollipop the glow effect is actually a Drawable embedded in the OS's resources, you can apply a ColorFilter on that:

public static void changeOverScrollGlowColor(Resources res, int colorID ) {
    try {
        final int glowDrawableId = res.getIdentifier("overscroll_glow", "drawable", "android");
        final Drawable overscrollGlow = res.getDrawable(glowDrawableId);
        overscrollGlow.setColorFilter(res.getColor(colorID), android.graphics.PorterDuff.Mode.SRC_ATOP);

        final int edgeDrawableId = res.getIdentifier("overscroll_edge", "drawable", "android");
        final Drawable overscrollEdge = res.getDrawable(edgeDrawableId);
        overscrollEdge.setColorFilter(res.getColor(colorID), android.graphics.PorterDuff.Mode.SRC_ATOP);
    } catch (Exception ignored) {
    }
}

Calling it once in onCreate is enough.

changeOverScrollGlowColor(getResources(), R.color.colorPrimary);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!