Created
December 25, 2015 17:22
-
-
Save PDDStudio/caadc623be2b6d9af114 to your computer and use it in GitHub Desktop.
EdgeUtils for various Views
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.pddstudio.pur.utils; | |
import android.annotation.TargetApi; | |
import android.graphics.PorterDuff; | |
import android.graphics.drawable.Drawable; | |
import android.os.Build; | |
import android.support.annotation.ColorInt; | |
import android.support.annotation.IntDef; | |
import android.support.v4.widget.EdgeEffectCompat; | |
import android.support.v4.widget.NestedScrollView; | |
import android.support.v7.widget.RecyclerView; | |
import android.widget.AbsListView; | |
import android.widget.EdgeEffect; | |
import android.widget.ScrollView; | |
import com.pddstudio.pur.BuildConfig; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
import java.lang.reflect.Field; | |
@TargetApi(21) | |
public class EdgeUtils { | |
protected EdgeUtils() {} | |
private static final Class<ScrollView> 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<NestedScrollView> CLASS_NESTED_SCROLL_VIEW = NestedScrollView.class; | |
private static final Field NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_TOP; | |
private static final Field NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM; | |
private static final Class<RecyclerView> CLASS_RECYCLER_VIEW = RecyclerView.class; | |
private static final Field RECYCLER_VIEW_FIELD_EDGE_GLOW_TOP; | |
private static final Field RECYCLER_VIEW_FIELD_EDGE_GLOW_LEFT; | |
private static final Field RECYCLER_VIEW_FIELD_EDGE_GLOW_RIGHT; | |
private static final Field RECYCLER_VIEW_FIELD_EDGE_GLOW_BOTTOM; | |
private static final Class<AbsListView> 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; | |
private static final Field EDGE_GLOW_FIELD_EDGE; | |
private static final Field EDGE_GLOW_FIELD_GLOW; | |
private static final Field EDGE_EFFECT_COMPAT_FIELD_EDGE_EFFECT; | |
static { | |
Field edgeGlowTop = null, edgeGlowBottom = null, edgeGlowLeft = null, edgeGlowRight = null; | |
for (Field f : CLASS_RECYCLER_VIEW.getDeclaredFields()) { | |
switch (f.getName()) { | |
case "mTopGlow": | |
f.setAccessible(true); | |
edgeGlowTop = f; | |
break; | |
case "mBottomGlow": | |
f.setAccessible(true); | |
edgeGlowBottom = f; | |
break; | |
case "mLeftGlow": | |
f.setAccessible(true); | |
edgeGlowLeft = f; | |
break; | |
case "mRightGlow": | |
f.setAccessible(true); | |
edgeGlowRight = f; | |
break; | |
} | |
} | |
RECYCLER_VIEW_FIELD_EDGE_GLOW_TOP = edgeGlowTop; | |
RECYCLER_VIEW_FIELD_EDGE_GLOW_BOTTOM = edgeGlowBottom; | |
RECYCLER_VIEW_FIELD_EDGE_GLOW_LEFT = edgeGlowLeft; | |
RECYCLER_VIEW_FIELD_EDGE_GLOW_RIGHT = edgeGlowRight; | |
for (Field f : CLASS_NESTED_SCROLL_VIEW.getDeclaredFields()) { | |
switch (f.getName()) { | |
case "mEdgeGlowTop": | |
f.setAccessible(true); | |
edgeGlowTop = f; | |
break; | |
case "mEdgeGlowBottom": | |
f.setAccessible(true); | |
edgeGlowBottom = f; | |
break; | |
} | |
} | |
NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_TOP = edgeGlowTop; | |
NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM = edgeGlowBottom; | |
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; | |
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { | |
Field edge = null, glow = null; | |
Class cls = null; | |
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { | |
try { | |
cls = Class.forName("android.widget.EdgeGlow"); | |
} catch (ClassNotFoundException e) { | |
if (BuildConfig.DEBUG) e.printStackTrace(); | |
} | |
} else { | |
cls = EdgeEffect.class; | |
} | |
if (cls != null) { | |
for (Field f : cls.getDeclaredFields()) { | |
switch (f.getName()) { | |
case "mEdge": | |
f.setAccessible(true); | |
edge = f; | |
break; | |
case "mGlow": | |
f.setAccessible(true); | |
glow = f; | |
break; | |
} | |
} | |
} | |
EDGE_GLOW_FIELD_EDGE = edge; | |
EDGE_GLOW_FIELD_GLOW = glow; | |
} else { | |
EDGE_GLOW_FIELD_EDGE = null; | |
EDGE_GLOW_FIELD_GLOW = null; | |
} | |
Field efc = null; | |
try { | |
efc = EdgeEffectCompat.class.getDeclaredField("mEdgeEffect"); | |
} catch (NoSuchFieldException e) { | |
if (BuildConfig.DEBUG) e.printStackTrace(); | |
} | |
EDGE_EFFECT_COMPAT_FIELD_EDGE_EFFECT = efc; | |
} | |
@IntDef({ALWAYS, PRE_HONEYCOMB, PRE_KITKAT, PRE_LOLLIPOP}) | |
@Retention(RetentionPolicy.SOURCE) | |
public @interface EdgeGlowColorApi {} | |
public static final int ALWAYS = 0; | |
/** Replace yellow glow in vanilla, blue glow on Samsung. */ | |
public static final int PRE_HONEYCOMB = Build.VERSION_CODES.HONEYCOMB; | |
/** Replace Holo blue glow. */ | |
public static final int PRE_KITKAT = Build.VERSION_CODES.KITKAT; | |
/** Replace Holo grey glow. */ | |
public static final int PRE_LOLLIPOP = Build.VERSION_CODES.LOLLIPOP; | |
public static void setEdgeGlowColor(AbsListView listView, @ColorInt int color, @EdgeGlowColorApi int when) { | |
if (Build.VERSION.SDK_INT < when || when == ALWAYS) { | |
setEdgeGlowColor(listView, color); | |
} | |
} | |
public static void setEdgeGlowColor(AbsListView listView, @ColorInt int color) { | |
try { | |
Object ee; | |
ee = LIST_VIEW_FIELD_EDGE_GLOW_TOP.get(listView); | |
setEdgeGlowColor(ee, color); | |
ee = LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM.get(listView); | |
setEdgeGlowColor(ee, color); | |
} catch (Exception ex) { | |
if (BuildConfig.DEBUG) ex.printStackTrace(); | |
} | |
} | |
public static void setEdgeGlowColor(ScrollView scrollView, @ColorInt int color, @EdgeGlowColorApi int when) { | |
if (Build.VERSION.SDK_INT < when || when == ALWAYS) { | |
setEdgeGlowColor(scrollView, color); | |
} | |
} | |
public static void setEdgeGlowColor(ScrollView scrollView, @ColorInt int color) { | |
try { | |
Object ee; | |
ee = SCROLL_VIEW_FIELD_EDGE_GLOW_TOP.get(scrollView); | |
setEdgeGlowColor(ee, color); | |
ee = SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM.get(scrollView); | |
setEdgeGlowColor(ee, color); | |
} catch (Exception ex) { | |
if (BuildConfig.DEBUG) ex.printStackTrace(); | |
} | |
} | |
public static void setEdgeGlowColor(NestedScrollView scrollView, @ColorInt int color, @EdgeGlowColorApi int when) { | |
if (Build.VERSION.SDK_INT < when || when == ALWAYS) { | |
setEdgeGlowColor(scrollView, color); | |
} | |
} | |
public static void setEdgeGlowColor(NestedScrollView scrollView, @ColorInt int color) { | |
try { | |
Object ee; | |
ee = NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_TOP.get(scrollView); | |
setEdgeGlowColor(ee, color); | |
ee = NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM.get(scrollView); | |
setEdgeGlowColor(ee, color); | |
} catch (Exception ex) { | |
if (BuildConfig.DEBUG) ex.printStackTrace(); | |
} | |
} | |
public static void setEdgeGlowColor(RecyclerView scrollView, @ColorInt int color, @EdgeGlowColorApi int when) { | |
if (Build.VERSION.SDK_INT < when || when == ALWAYS) { | |
setEdgeGlowColor(scrollView, color); | |
} | |
} | |
public static void setEdgeGlowColor(RecyclerView scrollView, @ColorInt int color) { | |
try { | |
Object ee; | |
ee = RECYCLER_VIEW_FIELD_EDGE_GLOW_TOP.get(scrollView); | |
setEdgeGlowColor(ee, color); | |
ee = RECYCLER_VIEW_FIELD_EDGE_GLOW_BOTTOM.get(scrollView); | |
setEdgeGlowColor(ee, color); | |
ee = RECYCLER_VIEW_FIELD_EDGE_GLOW_LEFT.get(scrollView); | |
setEdgeGlowColor(ee, color); | |
ee = RECYCLER_VIEW_FIELD_EDGE_GLOW_RIGHT.get(scrollView); | |
setEdgeGlowColor(ee, color); | |
} catch (Exception ex) { | |
if (BuildConfig.DEBUG) ex.printStackTrace(); | |
} | |
} | |
@TargetApi(Build.VERSION_CODES.LOLLIPOP) | |
private static void setEdgeGlowColor(Object edgeEffect, @ColorInt int color) { | |
if (edgeEffect instanceof EdgeEffectCompat) { | |
// EdgeEffectCompat | |
try { | |
edgeEffect = EDGE_EFFECT_COMPAT_FIELD_EDGE_EFFECT.get(edgeEffect); | |
} catch (IllegalAccessException e) { | |
if (BuildConfig.DEBUG) e.printStackTrace(); | |
return; | |
} | |
} | |
if (edgeEffect == null) return; | |
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { | |
// EdgeGlow | |
try { | |
final Drawable mEdge = (Drawable) EDGE_GLOW_FIELD_EDGE.get(edgeEffect); | |
final Drawable mGlow = (Drawable) EDGE_GLOW_FIELD_GLOW.get(edgeEffect); | |
mEdge.setColorFilter(color, PorterDuff.Mode.SRC_IN); | |
mGlow.setColorFilter(color, PorterDuff.Mode.SRC_IN); | |
mEdge.setCallback(null); // free up any references | |
mGlow.setCallback(null); // free up any references | |
} catch (Exception ex) { | |
if (BuildConfig.DEBUG) ex.printStackTrace(); | |
} | |
} else { | |
// EdgeEffect | |
((EdgeEffect) edgeEffect).setColor(color); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For line 274, it should be less than Lollipop. I've tested it on versions below Lollipop and line 288 causes a crash on all pre-21 Android versions.