全网第二好的Android课程表控件之替换滚动布局

替换滚动布局

https://github.com/zfman/TimetableView
一个开源的、完善的、简洁的课程表控件

为什么会有这个功能?想象这样几个场景:下拉时有反弹效果、下拉时有刷新效果、滚动时可以监听到滚动的位置、滚动布局嵌套导致滑动冲突。这几个需求都可以使用自定义View的方式来解决。替换滚动布局的意思是:你可以使用自定义的ScrollView来替换控件中的普通的ScrollView,可以想象它将有更好的扩展性。本节将演示如何实现一个有下拉反弹效果的课表界面,自定义View的知识不在本节的范围之内,有兴趣可以百度。

自定义View

你需要先准备好一个自定义View,根据你的需求而定,以下是一个有反弹效果的ScrollView

/**
 * 弹性滚动布局,下拉时会反弹
 */
public class ElasticScrollView extends ScrollView {
    private View inner;  
    private float y;  
    private Rect normal = new Rect();  
    private boolean animationFinish = true;  

    public ElasticScrollView(Context context) {  
        super(context);  
    }  

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

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        if (getChildCount() > 0) {
            inner = getChildAt(0);
        }
    }

    @Override  
    public boolean onInterceptTouchEvent(MotionEvent ev) {  
        return super.onInterceptTouchEvent(ev);  
    }  

    @Override  
    public boolean onTouchEvent(MotionEvent ev) {  
        if (inner == null) {  
            return super.onTouchEvent(ev);  
        } else {  
            commOnTouchEvent(ev);  
        }  
        return super.onTouchEvent(ev);  
    }  

    public void commOnTouchEvent(MotionEvent ev) {  
        if (animationFinish) {  
            int action = ev.getAction();  
            switch (action) {  
            case MotionEvent.ACTION_DOWN:
                y = ev.getY();  
                super.onTouchEvent(ev);  
                break;  
            case MotionEvent.ACTION_UP:
                y = 0;  
                if (isNeedAnimation()) {  
                    animation();  
                }  
                super.onTouchEvent(ev);  
                break;  
            case MotionEvent.ACTION_MOVE:
                final float preY = y == 0 ? ev.getY() : y;  
                float nowY = ev.getY();  
                int deltaY = (int) (preY - nowY);

                y = nowY;  
                // 当滚动到最上或者最下时就不会再滚动,这时移动布局  
                if (isNeedMove()) {  
                    if (normal.isEmpty()) {  
                        // 保存正常的布局位置  
                        normal.set(inner.getLeft(), inner.getTop(), inner.getRight(), inner.getBottom());  
                    }  
                    // 移动布局  
                    inner.layout(inner.getLeft(), inner.getTop() - deltaY / 2, inner.getRight(), inner.getBottom() - deltaY / 2);  
                } else {  
                    super.onTouchEvent(ev);  
                }  
                break;  
            default:  
                break;  
            }  
        }  
    }  

    // 开启动画移动
    public void animation() {  
        // 开启移动动画
        TranslateAnimation ta = new TranslateAnimation(0, 0, 0, normal.top - inner.getTop());  
        ta.setDuration(200);  
        ta.setAnimationListener(new AnimationListener() {  
            @Override  
            public void onAnimationStart(Animation animation) {  
                animationFinish = false;
            }  

            @Override  
            public void onAnimationRepeat(Animation animation) {
            }

            @Override  
            public void onAnimationEnd(Animation animation) {  
                inner.clearAnimation();
                inner.layout(normal.left, normal.top, normal.right, normal.bottom);  
                normal.setEmpty();  
                animationFinish = true;  
            }  
        });  
        inner.startAnimation(ta);  
    }  

    // 是否需要开启动画  
    public boolean isNeedAnimation() {  
        return !normal.isEmpty();  
    }  

    // 是否需要移动布局  
    public boolean isNeedMove() {  
        int offset = inner.getMeasuredHeight() - getHeight();  
        int scrollY = getScrollY();  
        if (scrollY == 0 || scrollY == offset) {  
            return true;  
        }  
        return false;  
    }  

}  

布局文件

准备一个布局文件,命名任意,这里命名为custom_myscrollview.xml,将以下内容复制到布局文件中,然后将根控件换成自定义控件

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/id_scrollview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="none">

    <include layout="@layout/view_content"/>

</ScrollView>

custom_myscrollview.xml中的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<com.zhuangfei.android_timetableview.ElasticScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/id_scrollview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="none">

    <include layout="@layout/view_content"/>

</com.zhuangfei.android_timetableview.ElasticScrollView>

设置监听

/**
         * 过程很简单,步骤如下:
         * 1.创建一个xml文件,命名为custom_myscrollview.xml
         * 2.拷贝一段代码至该文件中,具体内容可以参见custom_myscrollview.xml
         * 3.将根布局控件修改为自定义的控件,其他内容无需修改
         * 4.设置setOnScrollViewBuildListener()并实现其方法,将自定义的xml转换为View返回即可
         *
         */
        mTimetableView.setSource(mySubjects)
                .setOnScrollViewBuildListener(new ISchedule.OnScrollViewBuildListener() {
                    @Override
                    public View getScrollView(LayoutInflater mInflate) {
                        return mInflate.inflate(R.layout.custom_myscrollview, null, false);
                    }
                })
                .showView();

上一篇:全网第二好的Android课程表控件之颜色池
下一篇:全网第二好的Android课程表控件之工具类

猜你喜欢

转载自blog.csdn.net/lzhuangfei/article/details/80744555