父容器onTouch和子View的OnClick兼容解决,定制特殊刷新,底部回弹

最近一个功能是定制特殊的刷新是拉伸特定布局,刷新状态标识也是特定的位置,我是重写了一个linearlayout–ParentCanOnTouchLinearLayout,但是由于子View有很多OnClick事件,导致父容器的(拉伸)滑动效果(onTouch事件失效)
本文旨在解决父子兼容,并没有封装死 刷新事件,开放了按下 和move中的产生的高度,和up的回调。

先看一下实际完成效果
实际效果
思路分析:

  1. 头部拉伸
  2. 重写ParentCanOnTouchLinearLayout中onInterceptTouchEvent
  3. 重写ParentCanOnTouchLinearLayout中onTouchEvent拉伸高度的获取
  4. 根据自定义的接口去处理 定制的刷新 这个可以根据你的实际情况,由于我这里比较特殊 就没有封装好了 类似下拉刷新固定刷新事件

头部拉伸效果分析

无论拉伸是采用什么逻辑,都只需要知道手下滑的距离,作为基本参数,然后按比例给你想要拉伸的布局设置params.height

考虑到我这里的实际场景 采用的是两个 view作为占位

<View
                    android:id="@+id/refreshZone1"
                    android:layout_width="match_parent"
                    android:layout_height="1dp"
                    android:background="@color/main_color" />

<View
                    android:id="@+id/refreshZone2"
                    android:layout_width="match_parent"
                    android:layout_height="1dp"
                    android:background="@color/main_color" />

重写ParentCanOnTouchLinearLayout中onInterceptTouchEvent

因为如果子view中有很多点击事件会导致父view onTouch事件失效我们需要在子view使其失效前,干掉子view的点击事件。
当然只是在满足我们上下拉的时候去干掉,其他的时候依然执行子view点击事件

   private int yyy = -1;
    private int xxx = -1;
    private boolean isMove = false;

    /**
     * 核心方法
     * @param event
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {

        switch (event.getAction()) {


            case MotionEvent.ACTION_DOWN:
                isMove = false;
                //此处为break所以返回值为false执行 子OnClick 所以父onTouch中没有Down 所以子view中初始化也要在move的第一个 坐标中获取
                break;

            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                if (!isMove) {
                    return false;
                }
                Log.i("rex", "onInterceptTouchEvent --- ACTION_UP");
                isMove = false;
                break;
            case MotionEvent.ACTION_MOVE:
                if (!isMove) {
                    yyy = (int) event.getRawY();
                    xxx = (int) event.getRawX();
                }
                isMove = true;
                Log.i("rex", "yyy --- " + yyy);
                Log.i("rex", "onInterceptTouchEvent --- ACTION_MOVE");


                Log.i("rex", "yyy --- " + yyy);
                //细节优化 短距离移除
                float moveY = event.getRawY();
                float moveX = event.getRawX();

                Log.i("rex", "moveY --- " + moveY);
                Log.i("rex", "moveX --- " + moveX);

                //如果是非点击事件就拦截 让父布局接手onTouch 否则执行子ViewOnClick

                if (Math.abs(moveY - yyy) > dip2px(getContext(), 20) || Math.abs(moveX - xxx) > dip2px(getContext(), 20)) {
                    final ViewParent parent = getParent();
                    if (parent != null) {
                        parent.requestDisallowInterceptTouchEvent(true);
                    }
                    Log.i("rex", "确定当前为父view滑动");
                    return true;
                }
//                if (Math.abs(moveY - yyy) < Math.abs(moveX - xxx)) {
//                    Log.i("rex", "onInterceptTouchEvent --- 横滑");
                    return false;
//                }
                break;

        }
        return false;
    }

重写ParentCanOnTouchLinearLayout中onTouchEvent拉伸高度的获取



  private OnPullDownImpl impl;
    private boolean isNeedReresh;
    private boolean isRefreshing;

    private int y1 = -1;
    private int max = 300;
    private int height = -1;
    private int paddingTop;
    public interface OnPullDownImpl {
        void moveHeight(int height);

        void up();

        void refreshHeigh();
    }

    public void setOnPullDownImpl(OnPullDownImpl impl) {

        this.impl = impl;
    }

    public boolean isCanReresh() {
        return isNeedReresh && !isRefreshing;
    }

    public void setRefreshing(boolean is) {
        isRefreshing = is;
    }

    public boolean isRefreshing() {
        return isRefreshing;
    }

    public void reSet() {
        isRefreshing = false;
        isNeedReresh = false;
        y1 = -1;
        height = -1;
    }

  @Override
    public boolean onTouchEvent(MotionEvent event) {


        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:
//其实这里毫无意义,因为onInterceptTouchEvent为true  所以初始值应该在move中取
                if (y1 == -1) {
                    isNeedReresh = false;
                    y1 = (int) event.getRawY();
                }
                Log.i("rex", "onTouchEvent --- ACTION_DOWN y1===" + y1);
                break;

            case MotionEvent.ACTION_MOVE:
                if (y1 == -1) {
                    //当为子View Ontouch时候 可能不走上面的down
                    isNeedReresh = false;
                    y1 = (int) event.getRawY();
                }

                height = (int) event.getRawY() - y1;
                Log.i("rex", "height=====" + height);
                if (height > 120) {
                    isNeedReresh = true;
                    impl.refreshHeigh();
                }

                if (0 < height && height < max) {

                    if (impl != null) {
                        //下拉
                        impl.moveHeight(height);
                    }
                }

                if (height < 0) {
                    //底部拉伸

                    if (height < -max) {
                        height = -max;
                    }
                    setPadding(0, height, 0, 0);
                }
                break;

            case MotionEvent.ACTION_UP:
                Log.i("rex", "ACTION_UP");
                if (impl != null) {
                    //拓展
                    impl.up();
                }


                paddingTop = getPaddingTop();
                if (paddingTop < 0) {
                    //底部回弹
                    if (mRunnable != null) {
                        removeCallbacks(mRunnable);
                        mRunnable = null;
                    }
                    mRunnable = runnable;
                    postDelayed(mRunnable, 20);


                }


                break;
        }

        return true;
    }

    private Runnable mRunnable = null;
    //循环回弹的Runnable 
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            paddingTop = paddingTop + 20;

            if (paddingTop > -6) {
                setPadding(0, 0, 0, 0);
            } else {
                setPadding(0, paddingTop, 0, 0);
                postDelayed(this, 20);
            }

        }
    };

/**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

根据自定义的接口去处理 定制的刷新

 /**
     * 设置界面更新
     */
    int y = -1;

    private Runnable mRunnable = null;

    private void setRootRresh() {
        /**
         * 初始化 自定义刷新控件
         */


        ballView2 = (BallView2) view.findViewById(R.id.ballView2);
        llRefreshRex = (ParentCanOnTouchLinearLayout) view.findViewById(R.id.llRefreshRex);
        final View view1 = view.findViewById(R.id.refreshZone1);
        final View view2 = view.findViewById(R.id.refreshZone2);
        final ViewGroup.LayoutParams lp = view1.getLayoutParams();


        final Runnable runnable = new Runnable() {
            @Override
            public void run() {
                lp.height = lp.height - 10;

                view1.setLayoutParams(lp);
                view2.setLayoutParams(lp);
                if (lp.height < 6) {
                    lp.height = 0;
                    view1.setLayoutParams(lp);
                    view2.setLayoutParams(lp);
                    y = -1;
                    if (llRefreshRex.isCanReresh()) {

                        llRefreshRex.setRefreshing(true);
                        Log.i("rex", "请求刷新!");
                        initDatas();

                    } else if (llRefreshRex.isRefreshing()) {
                        //不做处理
                        Log.i("rex", "正在刷新中");
                    } else {
                        //不刷新
                        ballView2.setVisibility(View.GONE);
                        llRefreshRex.reSet();
                    }
                } else {
                    view1.postDelayed(this, 20);
                }
            }
        };

        llRefreshRex.setOnPullDownImpl(new ParentCanOnTouchLinearLayout.OnPullDownImpl() {
            @Override
            public void moveHeight(int height) {
                lp.height = height / 3;
                view1.setLayoutParams(lp);
                view2.setLayoutParams(lp);
            }


            @Override
            public void refreshHeigh() {
                ballView2.setVisibility(View.VISIBLE);
            }

            @Override
            public void up() {
                if (mRunnable != null) {
                    view1.removeCallbacks(mRunnable);
                    mRunnable = null;
                }
                mRunnable = runnable;
                view1.postDelayed(mRunnable, 20);

            }
        });

    }
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值