随手指拖动而变色的ScrollView

参考

        关于view的概述

效果描述

        在一个可以上下滚动的scrollview,当某一个新View出现时,随着它出现高度的增加而不断改变背影色。如下:


最下面一个view会随着手指的移动由红色逐渐变成蓝色。

原理

        在ScrollView滑动的过程中,会不断地调用onScrollChanged(),从而可以判断出某个显示的百分比,由该百分比计算出当前应该显示的背影色。简单点说,我们只需要自定义一个ScrollView,重写其中的onScrollChanged()即可。

代码

public class CustomLinearLayout extends ScrollView{
    private ArgbEvaluator mEvaluator;
    private ViewGroup mContainer;
    public CustomLinearLayout(Context context) {
        super(context);
    }

    public CustomLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomLinearLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onFinishInflate() {//在这里获取ScrollView下的子View
        super.onFinishInflate();
        mContainer = (ViewGroup)getChildAt(0);
        mEvaluator = new ArgbEvaluator();
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        for(int x= 0;x<mContainer.getChildCount();x++) {
            View child = mContainer.getChildAt(x);
            if (child.getTop() <= t + getHeight() && child.getBottom() >= t + getHeight()) {
                float fraction = (t + getHeight() - child.getTop()) / (float) child.getHeight();
                child.setBackgroundColor((Integer) mEvaluator.evaluate(fraction, Color.RED, Color.BLUE));
            }else{
                child.setBackgroundColor(Color.BLUE);
            }
        }
    }
    private void log(String content){
        Log.e("TAG",content);
    }
}

        在onScrollChanged()中,会不断地判断当前的View的背影是否应该进行变化。
        设置背景色时,是通过ArgbEvaluator()进行计算的,这是系统提供的一个工具类,在属性动画中常用到。

与LayoutParams结合

        与LayoutParams结合后,可以将上面的动画直接在子View中配置,就像相对布局的子view可以配置centerInParent属性一样。由于需要配置给子view,所以需要定义一个ViewGroup,用作ScrollView的子View;并且在该ViewGroup中自定义LayoutParams,保证它的子View关联的LayoutParams中有自定义的属性。

        首先自定义LayoutParams的属性:

<resources>
    <declare-styleable name="MyLinearLayout_LayoutParams">
        <attr name="layout_animator">
            <flag name="translate" value="0x2" />
            <flag name="alpha" value="0x1"/>
        </attr>
    </declare-styleable>
</resources>

        上面自定义属性时使用flag标签,因为这些属性在使用时可以通过"|"进行连接。在自定义控件中获取这些属性
    //本类继承于LinearLayout,构造方法略
    @Override
    public LinearLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MyLayoutParams(getContext(), attrs);
    }

    public static class MyLayoutParams extends LinearLayout.LayoutParams{
        int animatorType;
        public static final int TYPE_ALPHA = 0x1;
        public static final int TYPE_TRANSLATE = 0x2;
        public MyLayoutParams(Context c,AttributeSet set){
            super(c,set);
            //加载对应的LayoutParams参数
            TypedArray array = c.obtainStyledAttributes(set, R.styleable.MyLinearLayout_LayoutParams);
            for(int x = 0;x<array.getIndexCount();x++){
                int index = array.getIndex(x);
                switch (index){
                    case R.styleable.MyLinearLayout_LayoutParams_layout_animator:
                        animatorType = array.getInt(R.styleable.MyLinearLayout_LayoutParams_layout_animator,0);
                        break;
                }
            }
            array.recycle();
        }
    }
        这样,一个含有自定义LayoutParams的自定义控件就完成了。在xml布局时,该控件的所有子View都可以使用自定义的layout_animator属性。

        在将ScrllView中的onScrollChanged修改如下:

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        for (int x = 0; x < mContainer.getChildCount(); x++) {
            View child = mContainer.getChildAt(x);//mContainer便是上面自定义的LinearLayout
            //获取mContainer的各个子View的LayoutParames,并强转成自定义的MyLayoutParams,因为只
            //有MyLayoutParams中才有自定义的layout_animator属性
            MyLayoutParams params = (MyLayoutParams) child.getLayoutParams();
            if (child.getTop() <= t + getHeight() && child.getBottom() >= t + getHeight()) {
                float fraction = (t + getHeight() - child.getTop()) / (float) child.getHeight();
                //判断有没有该声明该类型的动画,如果有就进行相应的操作
                if ((params.animatorType & MyLayoutParams.TYPE_ALPHA) == MyLayoutParams.TYPE_ALPHA) {
                    child.setBackgroundColor((Integer) mEvaluator.evaluate(fraction, Color.RED, Color.BLUE));
                }
                if ((params.animatorType & MyLayoutParams.TYPE_TRANSLATE) == MyLayoutParams.TYPE_TRANSLATE) {
                    child.setTranslationX((fraction - 1) * child.getRight());
                }
            } else {
                child.setBackgroundColor(Color.BLUE);
            }
        }
    }
        如此一套自定义的效果便完成了。使用如下:
        <ImageView
            demo:layout_animator="translate|alpha"
            android:layout_width="wrap_content"
            android:src="@mipmap/ic_launcher"
            android:layout_height="100dp" />
        <ImageView
            demo:layout_animator="translate"
            android:layout_width="wrap_content"
            android:src="@mipmap/ic_launcher"
            android:layout_height="100dp" />
        <ImageView
            android:layout_width="wrap_content"
            android:src="@mipmap/ic_launcher"
            android:layout_height="100dp" />
        <ImageView
            demo:layout_animator="alpha"
            android:layout_width="wrap_content"
            android:src="@mipmap/ic_launcher"
            android:layout_height="100dp" />
        <ImageView
            android:layout_width="wrap_content"
            android:src="@mipmap/ic_launcher"
            android:layout_height="100dp" />
    </com.example.hufeng.demo.MyLinearLayout>
</com.example.hufeng.demo.CustomLinearLayout>
        布局中前面一部分被省略了。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值