ScrollView嵌套EditText联带滑动的解决办法

解决ScrollView嵌套EditText的滑动事件,并且实现它们两者之间的联带滑动。什么是联带滑动呢,就是当EditText滑动到底部的时候,这时就应该让外部的ScrollView跟着滑动,好让它们之间完成连贯的滑动事件。先来看看效果把。

网上没找到完整实现的例子,只好自己撸demo了。
代码里有注释,全部代码如下:

package chn.fz.thatjay.scrolleditview.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.Layout;
import android.util.AttributeSet;
import android.support.v7.widget.AppCompatEditText;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;

import chn.fz.thatjay.scrolleditview.R;


public class ScrollMulrowsEditText extends AppCompatEditText {

    private final String TAG = "ScMulrowsEditText";
    //滑动距离的最大边界
    private int mOffsetHeight;

    private int mHeight;


    private int mVert = 0;


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

    public ScrollMulrowsEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttribute(context, attrs, 0);
    }

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


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int paddingTop;
        int paddingBottom;
        int height;
        int mLayoutHeight;

        //获得内容面板
        Layout mLayout = getLayout();
        //获得内容面板的高度
        mLayoutHeight = mLayout.getHeight();
        //获取上内边距
        paddingTop = getTotalPaddingTop();
        //获取下内边距
        paddingBottom = getTotalPaddingBottom();

        //获得控件的实际高度
        height = mHeight; // getHeight()第一次得到0,所以最好从外部指定设置值

        //计算滑动距离的边界  mOffsetHeight 当内容少,没有滚动条时候,值为0
        mOffsetHeight = mLayoutHeight + paddingTop + paddingBottom - height;

        setOnTouchListener();
        if(getId() == R.id.edittext2) {
            Log.d(TAG, "ffffaaaa onMeasure == " + mOffsetHeight);
        }
    }

    private void initAttribute(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ScrollMulrowsEditText, defStyleAttr, 0);
        int count = array.getIndexCount();
        for (int i = 0; i < count; i++) {
            int attr = array.getIndex(i);
            switch (attr) {
                case R.styleable.ScrollMulrowsEditText_sc_mul_edit_height:
                    mHeight = array.getDimensionPixelSize(attr, 0);
                    break;
            }
        }
        array.recycle();
    }

    @Override
    protected void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) {
        super.onScrollChanged(horiz, vert, oldHoriz, oldVert);
        mVert = vert;
        if(getId() == R.id.edittext2){
            Log.d(TAG,"ffffaaaa mOffsetHeight == " + mOffsetHeight + "  ,, vert ===  " + vert );
        }
        if (vert == mOffsetHeight || vert == 0) {
            //这里触发父布局或祖父布局的滑动事件
            getParent().requestDisallowInterceptTouchEvent(false);
            Log.d(TAG, "vert requestDisallowInterceptTouchEvent  false ");
        }
    }

    //滑动到上边缘
    public boolean isUpperEdge(){
        return mVert == 0;
    }

    //滑动到下边缘
    public boolean isLowerEdge(){
        return mVert == mOffsetHeight;
    }

    private float scrollBeginY;
    public void setOnTouchListener(){
        setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                //canScrollVertically()方法为判断指定方向上是否可以滚动,参数为正数或负数,负数检查向上是否可以滚动,正数为检查向下是否可以滚动
                if(MotionEvent.ACTION_DOWN == event.getAction()){
                    scrollBeginY = event.getY();
                    v.getParent().requestDisallowInterceptTouchEvent(true);//要求父类布局不在拦截触摸事件
                    return false;
                }
                Log.d(TAG, "event.getY" + event.getY());//edittext 如果在最边缘,getY得到的也不是固定的值
                if(canScrollVertically(1)){//可以向下滚动
                    if(isUpperEdge() && event.getY() >= scrollBeginY){//已经在上边缘,向下手势滑动
                        v.getParent().requestDisallowInterceptTouchEvent(false);//交给父布局
                    } else {
                        v.getParent().requestDisallowInterceptTouchEvent(true);
                    }
                } else if(canScrollVertically(-1)){//可以向上滚动
                    if(isLowerEdge() && event.getY() <= scrollBeginY){//已经在下边缘,向上手势滑动
                        v.getParent().requestDisallowInterceptTouchEvent(false);//交给父布局
                    } else {
                        v.getParent().requestDisallowInterceptTouchEvent(true);
                    }
                } else {
                    v.getParent().requestDisallowInterceptTouchEvent(false);//交给父布局
                }
                //getY  手机屏幕上边 getY  值小
                //getY  手机屏幕下边 getY  值大
                return false;
            }
        });
    }


}

 

activity代码,下面是ImmersionBar的第三方库,用来监听输入法键盘消失的时候,让edittext失去焦点,否则edittext光标一直在,很难看。

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initStatusBar(edittext1, edittext2, edittext3, edittext4, edittext5);
}
public void initStatusBar(final EditText... ets){
        ImmersionBar.with(this)
                .fitsSystemWindows(true)
                .statusBarColor(R.color.color1)
                .keyboardEnable(true)
                .setOnKeyboardListener(new OnKeyboardListener() {
                    @Override
                    public void onKeyboardChange(boolean isPopup, int keyboardHeight) {
                        if (!isPopup) {
                            for (EditText et:ets
                            ) {
                                et.clearFocus();
                            }
                        }
                    }
                })
                .init();
    }

 

完整项目代码:github下载地址

 

posted @ 2019-09-08 17:38  圣剑Jay  阅读(247)  评论(0编辑  收藏  举报