解決ScrollView嵌套EditText的滑動事件,而且實現它們二者之間的聯帶滑動。什麼是聯帶滑動呢,就是當EditText滑動到底部的時候,這時就應該讓外部的ScrollView跟着滑動,好讓它們之間完成連貫的滑動事件。先來看看效果把。android
網上沒找到完整實現的例子,只好本身擼demo了。
代碼裏有註釋,所有代碼以下:git
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光標一直在,很難看。github
@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(); }