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下载地址

原文地址:https://www.cnblogs.com/that-jay/p/11487535.html

时间: 2024-10-09 01:45:50

ScrollView嵌套EditText联带滑动的解决办法的相关文章

从ScrollView嵌套EditText的滑动事件冲突分析触摸事件的分发机制以及TextView的简要实现和冲突的解决办法

本篇文章假设读者没有任何的触摸事件基础知识,所以我们会从最基本的触摸事件分发处说起. ScrollView为什么会出现嵌套EditText出现滑动事件冲突呢?相信你会有这种疑问,我们来看这么一种情况: 有一个固定高度的EditText,假设它只能显示3行文本,但是,我们在其中输入的文本多余三行时,那么这时就需要可以在EditText内部进行小幅滚动了.那么将这个EditText放入了ScrollView当中, 并且ScrollView内容过多以致ScrollView也可以滑动,这时候就会出现Ed

Java Runtime.getRuntime().exec 执行带空格命令解决办法

String command = OpenOffice_HOME + "program\\soffice -headless -accept=\"socket,host=127.0.0.1,port=8100;urp;\" -nofirststartwizard "; command = "cmd /c start "+command.replaceAll(" ","\" \""); P

ScrollView+ListView滚动冲突,没有滑动效果 解决办法

问题背景 今天做个界面需要在整个布局都要滚动的基础上添加一个ListView元素,整个布局滚动当然用ScrollView.但是在ScrollView+ListView的布局画好后,发现整个界面都无法滚动,而且ListView只显示了第一条元素. 查看布局提示:The vertically scrolling ScrollView should not contain another vertically scrolling widget (ListView). 问题分析: 由上面那个提示可以看到

Android ScrollView中嵌套ListView只显示一行的解决办法

Android编程中,ScrollView嵌套ListView时,会无法正确的计算ListView的大小.解决的办法如下: (非原创,网上搜到的解决方法) public class MainActivity extends Activity { private ListView listView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); s

ScrollView与ListView冲突的四种解决办法

在工作中,曾多次碰到ScrollView嵌套ListView的问题,网上的解决方法有很多种,但是杂而不全.我试过很多种方法,它们各有利弊. 在这里我将会从使用ScrollView嵌套ListView结构的原因.这个结构碰到的问题.几种解决方案和优缺点比较,这4个方面来为大家阐述.分析.总结. 实际上不光是ListView,其他继承自AbsListView的类也适用,包括ExpandableListView.GridView等等,为了方便说明,以下均用ListView来代表. 一. 为什么要使用S

多个EditText 监听矛盾的 解决办法 (Overstack)溢出栈

这里有A,B,C 三个edittext,他们三个之间通过后台的计算来改变互相的值.具体来说,A在变得时候,BC会随之而变;B在变得时候AC会随之而变.因此,一开始我给他们三个都分别添加textChangedListener的时候就出现的StackOver 栈溢出的问题.原因是他们进入了死循环!! 解决办法: 自认为很简单的方法,以后不管是editText还是什么控件,出现类似的死循环问题都可以用这个方法解决: 设立一个flag!! 首先默认该flag=false; Then at each ed

解决ScrollView嵌套ViewPager出现的滑动冲突问题

/** * */ public class ScrollView1 extends ScrollView { private boolean canScroll; private GestureDetector mGestureDetector; View.OnTouchListener mGestureListener; public ScrollView1(Context context, AttributeSet attrs) { super(context, attrs); mGestu

ScrollView嵌套recyclerView出现的滑动问题

记得以前在解决scrollView与ListView嵌套问题时,那个时候是自定义了listView去测量listView高度,今天项目中刚 好碰到了要用recycerView,同样也是嵌套在scrollView中,但是按照以前listView方法居然不显示了,后来发现原来是要重写的是 LayoutManager... 在此说明,这是copy大神的,我只是为了学习啊!大神真的很牛啊! 原创博客:http://blog.csdn.net/u010623588/article/details/5026

scrollview 中嵌套多个listview的最好解决办法

在scrollview中嵌套多个listview的显示问题. 只需要调用如下的方法传入listview和adapter数据即可. /** * 动态设置ListView组建的高度 */ public static void setListViewHeightBasedOnChildren(ListView listView,Adapter adapter) { Adapter listAdapter = (Adapter) listView.getAdapter(); if (listAdapte