Android可滚动控件(GridView、ListView、ScrollView等)当用户滚动到头的时候会有个边缘反馈效果,在4.0上默认为Holo蓝色效果。 如果您的App自定义了主题颜色,比如Google Play Music的橘黄色。 那么在滚动内容控件还是用默认的Holo蓝色边缘效果看起来可能不太协调。这个时候就需要自定义边缘效果了。
边缘效果在Android系统中是通过 EdgeEffect 类来实现的,在该类的的构造函数中使用两个系统图片来绘制边缘效果:
final Resources res = context.getResources();
mEdge = res.getDrawable(R.drawable.overscroll_edge);
mGlow = res.getDrawable(R.drawable.overscroll_glow);
4.0默认的这两个图片如下(点击链接查看图片):
- overscroll_edge: overscroll_edge.png
- overscroll_glow: overscroll_glow.png
所以要实现自定义边缘效果,只需要hack系统在获取这两个图片的时候使用您App提供的图片即可。
Android系统的App是通过ContextWrapper类来获取Resources类,然后通过Resources类来获取各种资源。所以通过自定义这两个类并把自定义的类应用到这些滚动控件中即可。
首先自定义Resources类,在该类中如果判断需要获取上面这两个边缘效果图片,就返回自定义的图片(ResourcesEdgeEffect.java):
public class ResourcesEdgeEffect extends Resources { private int overscroll_edge = getPlatformDrawableId("overscroll_edge"); private int overscroll_glow = getPlatformDrawableId("overscroll_glow"); public ResourcesEdgeEffect(AssetManager assets, DisplayMetrics metrics, Configuration config) { super(assets, metrics, config); } private int getPlatformDrawableId(String name) { try { int i = ((Integer) Class.forName("com.android.internal.R$drawable").getField(name).get(null)).intValue(); return i; } catch (ClassNotFoundException e) { Log.e("[ContextWrapperEdgeEffect].getPlatformDrawableId()", "Cannot find internal resource class"); return 0; } catch (NoSuchFieldException e1) { Log.e("[ContextWrapperEdgeEffect].getPlatformDrawableId()", "Internal resource id does not exist: " + name); return 0; } catch (IllegalArgumentException e2) { Log.e("[ContextWrapperEdgeEffect].getPlatformDrawableId()", "Cannot access internal resource id: " + name); return 0; } catch (IllegalAccessException e3) { Log.e("[ContextWrapperEdgeEffect].getPlatformDrawableId()", "Cannot access internal resource id: " + name); } return 0; } public Drawable getDrawable(int resId) throws Resources.NotFoundException { if (resId == this.overscroll_edge) return ContextWrapperEdgeEffect.this.getBaseContext().getResources().getDrawable(R.drawable.overscroll_edge); if (resId == this.overscroll_glow) return ContextWrapperEdgeEffect.this.getBaseContext().getResources().getDrawable(R.drawable.overscroll_glow); return super.getDrawable(resId); } }
然后自定义一个ContextWrapper类(ContextWrapperEdgeEffect.java):
public class ContextWrapperEdgeEffect extends ContextWrapper { private static ResourcesEdgeEffect RES_EDGE_EFFECT; public ContextWrapperEdgeEffect(Context context) { super(context); Resources resources = context.getResources(); if (RES_EDGE_EFFECT == null) RES_EDGE_EFFECT = new ResourcesEdgeEffect(resources.getAssets(), resources.getDisplayMetrics(), resources.getConfiguration()); } //返回自定义的Resources public Resources getResources() { return RES_EDGE_EFFECT; } }
最后再自定义App中使用到的滚动控件,把Context对象替换为前面自定义的ContextWrapperEdgeEffect类即可(如下是GridView的示例):
public class GridView extends android.widget.GridView { public GridView(Context context, AttributeSet attrs) { super(new ContextWrapperEdgeEffect(context), attrs); } public GridView(Context context, AttributeSet attrs, int defStyle) { super(new ContextWrapperEdgeEffect(context), attrs, defStyle); } }
然后让您的UE同学按照Holo蓝色边缘效果的两张图来提供自定义的两张图即可。
如果您感觉上面这些步骤比较繁琐的话,也可以下载 EdgeEffectOverride 这个项目,该项目已经实现了ListView、GridView、ScrollVeiw、ExpandableListView和ViewPager类, 下载该项目只需要替换两个图片即可。
下图是一个自定义红色效果的截图: