自定义ScrollView实现头尾部的下拉,上拉

本文介绍了一个自定义的ScrollView实现方案,允许用户通过上下滑动来调整头部和尾部的内容位置。该实现包括了如何拦截触摸事件、判断是否需要移动及执行动画等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自定义ScrollView实现头尾部的下拉,上拉

public class MyScrollView extends ScrollView {


private View childView;


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

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

public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

//假设ScrollView中有个LinearLayout,首先获取LinearLayout
@Override
protected void onFinishInflate() {
    super.onFinishInflate();
    childView = this.getChildAt(0);
}

private int lastY;//上次移动的Y坐标
private Rect normal = new Rect();//记录默认的坐标
private boolean isFinishAnimation = true;
private int lastX, downX, downY;

/**
 * 事件拦截:拦截:实现父视图对子视图的拦截
 * 是否拦截成功,取决于方法的返回值。返回值true:拦截成功。反之,拦截失败
 */
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    boolean isIntercept = false;
    int eventX = (int) ev.getX();
    int eventY = (int) ev.getY();
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            downX = lastX = eventX;
            downY = lastY = eventY;
            break;
        case MotionEvent.ACTION_MOVE:
            //获取水平和垂直方向的移动距离
            int absX = Math.abs(eventX - downX);
            int absY = Math.abs(eventY - downY);
            if (absY > absX && absY > UIUtils.dp2px(10)) {
                isIntercept = true;
            }
            lastY=eventY;
            lastX=eventX;
            break;
    }
    return isIntercept;
}


@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (childView == null || !isFinishAnimation) {//没有完成动画的情况下不可再点击触摸事件
        return super.onTouchEvent(ev);
    }
    int eventY = (int) ev.getY();
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            lastY = eventY;
            break;
        case MotionEvent.ACTION_MOVE:
            int dy = eventY - lastY;
            if (isNeedMove()) {
                if (normal.isEmpty()) {
                    normal.set(childView.getLeft(), childView.getTop()
                            , childView.getRight(), childView.getBottom());
                }
                //重新布局
                childView.layout(childView.getLeft(), childView.getTop() + dy / 2
                        , childView.getRight(), childView.getBottom() - dy / 2);
            }
            lastY = eventY;//重新赋值
            break;
        case MotionEvent.ACTION_UP:
            if (isNeedAnimation()) {
                //使用平移动画
                int translateY = childView.getBottom() - normal.bottom;
                TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, 0, -translateY);
                translateAnimation.setDuration(200);
                //translateAnimation.setFillAfter(true);//不能使用该方法,使用后点击事件还留在原本的位置
                translateAnimation.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {
                        isFinishAnimation = false;
                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
                        isFinishAnimation = true;
                        childView.clearAnimation();//清除动画
                        //重新布局
                        childView.layout(normal.left, normal.top, normal.right, normal.bottom);
                        //清楚normal的数据
                        normal.setEmpty();
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {

                    }
                });
                //启动动画
                childView.startAnimation(translateAnimation);
            }

            break;
    }

    return super.onTouchEvent(ev);
}

private boolean isNeedMove() {
    //获取子视图LinearLayout的高
    int childMeasureHeight = childView.getMeasuredHeight();
    //获得布局的高度(ScrollView)的高度
    int scrollViewMeasuredHeight = this.getMeasuredHeight();
    int dy = childMeasureHeight - scrollViewMeasuredHeight;
    //获取用户在y轴方向上的偏移量(上 + 下 -)
    int scrollY = this.getScrollY();
    Log.e("TAG", scrollY + "");
    if (scrollY <= 0 || scrollY >= dy) {//默认的的时候scroolY是处于0
        return true;//按照我们自定义的MyScrollView的方式处理
    }
    //其他处在临界范围内的,返回false。即表示,仍按照ScrollView的方式处理
    return false;
}

//判断是否需要执行平移动画
public boolean isNeedAnimation() {
    return !normal.isEmpty();
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值