去除HorizontalScrollView滑动边缘效果,兼容5.0及以上安卓系统

从Ancroid2.3开始,HorizontalScrollView有一个滑动到边缘的阴影阻尼效果,同样Listview,ScrollView都有,要去除这个阴影很简单,在xml里面写上android:overScrollMode=”never”就可以了,但是这个问题,就是阻尼效果也消失了,那么怎么能保留阻尼的效果并且干掉这个阴影呢,表面上看很简单,把阴影的颜色改为透明就行了,可惜的是Api并没有提供直接修改这个颜色的方法,当时产品提出了这个需求,我就研究了一下,分享出来和大家一同探讨.
之前也在他人的博客中看到一个方法,系统对于这个颜色是有内置的,只要替换掉系统提供的颜色就可以了,方法如下:
首先定义几个类

public class ResourcesEdgeEffect extends Resources {
    private int overscroll_edge = getPlatformDrawableId("overscroll_edge");
    private int overscroll_glow = getPlatformDrawableId("overscroll_glow");
    private ContextWrapperEdgeEffect mContextWrapperEdgeEffect;

    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) {
            InKeLog.e("[ContextWrapperEdgeEffect].getPlatformDrawableId()", "Cannot find internal resource class");
            return 0;
        } catch (NoSuchFieldException e1) {
            InKeLog.e("[ContextWrapperEdgeEffect].getPlatformDrawableId()", "Internal resource id does not exist: " + name);
            return 0;
        } catch (IllegalArgumentException e2) {
            InKeLog.e("[ContextWrapperEdgeEffect].getPlatformDrawableId()", "Cannot access internal resource id: " + name);
            return 0;
        } catch (IllegalAccessException e3) {
            InKeLog.e("[ContextWrapperEdgeEffect].getPlatformDrawableId()", "Cannot access internal resource id: " + name);
        }
        return 0;
    }

    public Drawable getDrawable(int resId) {
        try {
            mContextWrapperEdgeEffect = new ContextWrapperEdgeEffect(InKeApplication.getInstance());
            if (resId == this.overscroll_edge)
                return mContextWrapperEdgeEffect.getResources().getDrawable(R.drawable.overscroll_edge);
            if (resId == this.overscroll_glow)
                return mContextWrapperEdgeEffect.getResources().getDrawable(R.drawable.overscroll_glow);
            return super.getDrawable(resId);
        }catch (Resources.NotFoundException e){
            return InKeApplication.getInstance().getResources().getDrawable(R.drawable.overscroll_edge);
        }
    }

}

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;
    }

}

其中overscroll_edge,overscroll_glow是你自定义的drawable文件,改为你希望的颜色,用法很简单

public MyHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(new ContextWrapperEdgeEffect(context), attrs, defStyle);
    }

自定义一个HorizontalScrollView,姑且叫做MyHorizontalScrollView吧,在这个构造函数中把原来的super方法替换为super(new ContextWrapperEdgeEffect(context), attrs, defStyle),这样MyHorizontalScrollView自带的阴影颜色就可以改为你想要的颜色,不需要颜色的话就改为透明颜色
这个方法替换了系统的颜色属性,很有效果,但是其中也有一个问题,就是对于安卓5.0及5.0系统以上是无效的,那么问题出在哪里呢,我翻看了5.0的源码并对比了5.0之前的源码,原来源码在此做了修改,这个属性在5.0系统做了源码修改,HorizontalScrollView源码里面有两个变量mEdgeGlowLeft和mEdgeGlowRight,由他们来控制滑动到左右边缘的阴影颜色,他们都是一个EdgeEffect对象,EdgeEffect提供有setColor方法,只要修改这个颜色就可以了,可惜的是HorizontalScrollView并没有提供修改方法,mEdgeGlowLeft和mEdgeGlowRight也是私有变量无法访问,那么使用反射就可以了

public static void changeEffectColor(HorizontalScrollView view, Context context, int color) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            try {
                Field fieldLeft = null;
                Field fieldRight = null;
                fieldLeft = HorizontalScrollView.class.getDeclaredField("mEdgeGlowLeft");
                fieldRight = HorizontalScrollView.class.getDeclaredField("mEdgeGlowRight");
                fieldLeft.setAccessible(true);
                fieldRight.setAccessible(true);
                EdgeEffect edgeEffect = new EdgeEffect(context);
                edgeEffect.setColor(color);
                fieldLeft.set(view, edgeEffect);
                fieldRight.set(view, edgeEffect);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

在此方法里面进行了系统版本号的判断,只处理5.0及5.0系统以上的,配合之前介绍的方法,那么可以解决目前所有版本的适配问题,这样既改变了阴影颜色,又保留了阻尼效果,或许还有更好的方法,欢迎大家探讨交流,对此有什么问题也可以留言沟通,谢谢,元旦快乐!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值