43

How to Change color of over-scroll edge and over-scroll glow or how to change the white color (default color) of android release 5.0 lollipop?

Ahmed Hegazy
  • 12,395
  • 5
  • 41
  • 64
Ad Dahoun
  • 453
  • 1
  • 5
  • 8
  • 1
    possible duplicate of [android lollipop scrollview edge effect color](http://stackoverflow.com/questions/27104521/android-lollipop-scrollview-edge-effect-color) – alanv Dec 07 '14 at 20:30

4 Answers4

89

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 (only available for API 21 and above).

<style name="MyAppTheme" parent="...">
   <item name="android:colorEdgeEffect">@color/my_color</item>
</style>
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Ahmed Hegazy
  • 12,395
  • 5
  • 41
  • 64
  • 7
    Note that `android:colorPrimary` also sets the color of your ActionBar or Toolbar. Whereas `android:colorEdgeEffect` is more specific and only applies to ListViews, RecyclerViews, etc. – Mr-IDE Jun 27 '17 at 06:06
24

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/71b5c65689786b1d52d701d81d8c7445495807c3/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 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();
    }
  }
}
Eugen Pechanec
  • 37,669
  • 7
  • 103
  • 124
  • 1
    Nice! I was looking for a way of changing the glow color programmatically and every answer was related to setting the style on xml. Yours worked for me without a problem and now I can change the color dinamycally depending on the context like I do for the statusbarcolor and the toolbar. Thanks! – MrBrightside Dec 12 '14 at 17:01
  • thank you. it works nice. but what about `RecyclerView` ? –  Nov 29 '15 at 06:57
  • 1
    @sajad Here's the class I use to handle the majority of scrolling containers http://pastebin.com/TAujMUu9 The only missing one is `HorizontalScrollView` I think. – Eugen Pechanec Dec 01 '15 at 13:10
  • @Analizer Correct, the pastebin code crashes on Android 4. Luckily I found out yesterday so here's the update: http://pastebin.com/JSefcHiB – Eugen Pechanec Feb 11 '16 at 12:42
  • ViewPager is missing, I need this exact same thing but for ViewPagers! – Felipe Ribeiro R. Magalhaes Jun 06 '16 at 01:27
  • @FelipeRibeiroR.Magalhaes You have Android source code and my source code at your disposal, I'm sure you can adapt it for ViewPager. – Eugen Pechanec Jun 06 '16 at 08:09
  • @EugenPechanec thing is I'm not very good with reflections and I searched a little and couldn't find the source for the updated ViewPager, only an old version (that propably doesn't have the overscroll effect, as it was pre-lollipop): http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/support/v4/view/ViewPager.java – Felipe Ribeiro R. Magalhaes Jun 06 '16 at 18:15
  • @FelipeRibeiroR.Magalhaes On that page you can pick different version from a spinner on top. Check the link in the answer I updated it for ViewPager. Haven't tested but should work. – Eugen Pechanec Jun 06 '16 at 21:16
  • @EugenPechanec I tested it, but unfortunately it did not work. You implemented it for the support v4 ViewPager? I really appreciate your help! – Felipe Ribeiro R. Magalhaes Jun 06 '16 at 21:57
  • @FelipeRibeiroR.Magalhaes If you need it for v13 ViewPager all you have to do is change `v4` to `v13` in the `import` line at the top of the file. – Eugen Pechanec Jun 06 '16 at 21:58
  • @EugenPechanec I mustn't have expressed myself correctly... I'm already using v4, and I was wondering if you made it for this version, which is now clear you did. But it does not work... – Felipe Ribeiro R. Magalhaes Jun 06 '16 at 23:23
  • @FelipeRibeiroR.Magalhaes Fixed. (And there's no v13 ViewPager of course.) – Eugen Pechanec Jun 07 '16 at 09:52
  • @EugenPechanec thank you very much, it is working now! – Felipe Ribeiro R. Magalhaes Jun 07 '16 at 15:43
  • @EugenPechanec, what about webviews, just realized those can be scrollable too and also have the edge effect! – Felipe Ribeiro R. Magalhaes Jun 22 '16 at 16:38
  • @FelipeRibeiroR.Magalhaes Correct. Since Android 4.4 WebView implementation is provided by an independent APK and I don't want to dig into that. For older devices I just don't care. Feel free to explore if this interests you. – Eugen Pechanec Jun 22 '16 at 16:53
  • @EugenPechanec makes sense, I'll look into it! Thanks. – Felipe Ribeiro R. Magalhaes Jun 22 '16 at 17:41
  • This Link is broken, btw. (https://github.com/consp1racy/android-commons/blob/master/android/src/main/java/net/xpece/android/widget/XpEdgeEffect.java) – Martin Marconcini Jul 05 '17 at 20:22
19

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.

Phocacius
  • 1,127
  • 1
  • 13
  • 23
  • 1
    For java... `getRecyclerView().setEdgeEffectFactory(new RecyclerView.EdgeEffectFactory() { @NonNull @Override protected EdgeEffect createEdgeEffect(@NonNull RecyclerView view, int direction) { EdgeEffect edge = new EdgeEffect(view.getContext()); edge.setColor(ContextCompat.getColor(view.getContext(), R.color.blue)); return edge; } });` – Javatar Jun 07 '19 at 07:42
1

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);
John
  • 1,447
  • 15
  • 16