ScrollView ViewPager ListView三者共存

来源:互联网 发布:如何选择导师 知乎 编辑:程序博客网 时间:2024/05/27 20:51
ScrollView嵌套ViewPager,然后Viewpager又嵌套ListView
ScrollView嵌套Viewpager,viewPager中再嵌套RecyclerView

> ScrollView ViewPager ListView三者共存的问题
http://www.tuicool.com/articles/meIV3a

http://blog.csdn.net/zxm317122667/article/details/50913317


>自定义ScrollView

/**
 * 主要解决ScrollView中嵌套ViewPager,ViewPager嵌套ListView或RecycleView
 * @author 
 *
 */
public class CustomMyScrollView extends ScrollView {
private float xDistance, yDistance, xLast, yLast;


private OnScrollListener onScrollListener;
/**
* 主要是用在用户手指离开CustomMyScrollView,CustomMyScrollView还在继续滑动,我们用来保存Y的距离,然后做比较
*/
private int lastScrollY;


public CustomMyScrollView(Context context) {
this(context, null);
}


public CustomMyScrollView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}


public CustomMyScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}


/**
* 设置滚动接口

* @param onScrollListener
*/
public void setOnScrollListener(OnScrollListener onScrollListener) {
this.onScrollListener = onScrollListener;
}


/**
* 用于用户手指离开CustomMyScrollView的时候获取MyScrollView滚动的Y距离,然后回调给onScroll方法中
*/
private Handler handler = new Handler() {


public void handleMessage(android.os.Message msg) {
int scrollY = CustomMyScrollView.this.getScrollY();


// 此时的距离和记录下的距离不相等,在隔5毫秒给handler发送消息
if (lastScrollY != scrollY) {
lastScrollY = scrollY;
handler.sendMessageDelayed(handler.obtainMessage(), 5);
}
if (onScrollListener != null) {
onScrollListener.onScroll(scrollY);
}


};


};


/**
* 重写onTouchEvent, 当用户的手在MyScrollView上面的时候,
* 直接将CustomMyScrollView滑动的Y方向距离回调给onScroll方法中,当用户抬起手的时候,
* CustomMyScrollView可能还在滑动,所以当用户抬起手我们隔5毫秒给handler发送消息,在handler处理
* CustomMyScrollView滑动的距离
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (onScrollListener != null) {
onScrollListener.onScroll(lastScrollY = this.getScrollY());
}
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
handler.sendMessageDelayed(handler.obtainMessage(), 5);
break;
}
return super.onTouchEvent(ev);
}


/**

* 滚动的回调接口

*/
public interface OnScrollListener {
/**
* 回调方法, 返回CustomMyScrollView滑动的Y方向距离
*/
public void onScroll(int scrollY);
}


/**
* 解决ViewPager与ScrollView手势冲突的问题
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
xDistance = yDistance = 0f;
xLast = ev.getX();
yLast = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
final float curX = ev.getX();
final float curY = ev.getY();
xDistance += Math.abs(curX - xLast);
yDistance += Math.abs(curY - yLast);
xLast = curX;
yLast = curY;
if (xDistance > yDistance) {
return false;
}
}
return super.onInterceptTouchEvent(ev);
}
}

-----------------------------------

> 自定义CustomLinearLayoutManager,解决ScrollView嵌套RecycleView高度不适配问题

引用:http://blog.csdn.net/tan6458/article/details/51168390

import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;


public class CustomLinearLayoutManager extends LinearLayoutManager {
private static final String TAG = CustomLinearLayoutManager.class
.getSimpleName();


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


public CustomLinearLayoutManager(Context context, int orientation,
boolean reverseLayout) {
super(context, orientation, reverseLayout);
}

//------------------------------------------------
private static final int CHILD_WIDTH = 0;
    private static final int CHILD_HEIGHT = 1;
    private static final int DEFAULT_CHILD_SIZE = 100;
    private final int[] childDimensions = new int[2];
    private int childSize = DEFAULT_CHILD_SIZE;
    private boolean hasChildSize;
    private int[] mMeasuredDimension = new int[2];


    @Override
    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
        final int widthMode = View.MeasureSpec.getMode(widthSpec);
        final int heightMode = View.MeasureSpec.getMode(heightSpec);
        final int widthSize = View.MeasureSpec.getSize(widthSpec);
        final int heightSize = View.MeasureSpec.getSize(heightSpec);
        int width = 0;
        int height = 0;
        for (int i = 0; i < getItemCount(); i++) {
            try {
                measureScrapChild(recycler, i,
                        widthSpec,
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                        mMeasuredDimension);
            } catch (IndexOutOfBoundsException e) {


                e.printStackTrace();
            }


            if (getOrientation() == HORIZONTAL) {
                width = width + mMeasuredDimension[0];
                if (i == 0) {
                    height = mMeasuredDimension[1];
                }
            } else {
                height = height + mMeasuredDimension[1];
                if (i == 0) {
                    width = mMeasuredDimension[0];
                }
            }
        }
        switch (widthMode) {
            case View.MeasureSpec.EXACTLY:
//                    width = widthSize;
            case View.MeasureSpec.AT_MOST:
            case View.MeasureSpec.UNSPECIFIED:
        }


        switch (heightMode) {
            case View.MeasureSpec.EXACTLY:
                height = heightSize;
            case View.MeasureSpec.AT_MOST:
            case View.MeasureSpec.UNSPECIFIED:
        }
        setMeasuredDimension(widthSpec, height);


    }


    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[] measuredDimension) {
        View view = recycler.getViewForPosition(position);


        // For adding Item Decor Insets to view
//        super.measureChildWithMargins(view, 0, 0);


        if (view != null) {
            RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                    getPaddingTop() + getPaddingBottom(), p.height);
            view.measure(widthSpec, childHeightSpec);
            measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
            measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
            recycler.recycleView(view);
        }
    }


    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
//        Logger.e("SyLinearLayoutManager state:" + state.toString());
            super.onLayoutChildren(recycler, state);
    }



// private int[] mMeasuredDimension = new int[2];
//
// @Override
// public void onMeasure(RecyclerView.Recycler recycler,
// RecyclerView.State state, int widthSpec, int heightSpec) {
//
//
//
// final int widthMode = View.MeasureSpec.getMode(widthSpec);
// final int heightMode = View.MeasureSpec.getMode(heightSpec);
// final int widthSize = View.MeasureSpec.getSize(widthSpec);
// final int heightSize = View.MeasureSpec.getSize(heightSpec);
// int width = 0;
// int height = 0;
// for (int i = 0; i < getItemCount(); i++) {
// measureScrapChild(recycler, i, View.MeasureSpec.makeMeasureSpec(i,
// View.MeasureSpec.UNSPECIFIED),
// View.MeasureSpec.makeMeasureSpec(i,
// View.MeasureSpec.UNSPECIFIED), mMeasuredDimension);
//
// if (getOrientation() == HORIZONTAL) {
// width = width + mMeasuredDimension[0];
// if (i == 0) {
// height = mMeasuredDimension[1];
// }
// } else {
// height = height + mMeasuredDimension[1];
// if (i == 0) {
// width = mMeasuredDimension[0];
// }
// }
// }
// switch (widthMode) {
// case View.MeasureSpec.EXACTLY:
// width = widthSize;
// case View.MeasureSpec.AT_MOST:
// case View.MeasureSpec.UNSPECIFIED:
// }
//
// switch (heightMode) {
// case View.MeasureSpec.EXACTLY:
// height = heightSize;
// case View.MeasureSpec.AT_MOST:
// case View.MeasureSpec.UNSPECIFIED:
// }
//
// setMeasuredDimension(width, height);
// }
//
// private void measureScrapChild(RecyclerView.Recycler recycler,
// int position, int widthSpec, int heightSpec, int[] measuredDimension) {
// try {
// View view = recycler.getViewForPosition(0);// fix
// // 动态添加时报IndexOutOfBoundsException
//
// if (view != null) {
// RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view
// .getLayoutParams();
//
// int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
// getPaddingLeft() + getPaddingRight(), p.width);
//
// int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
// getPaddingTop() + getPaddingBottom(), p.height);
//
// view.measure(childWidthSpec, childHeightSpec);
// measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin
// + p.rightMargin;
// measuredDimension[1] = view.getMeasuredHeight()
// + p.bottomMargin + p.topMargin;
// recycler.recycleView(view);
// }
// } catch (Exception e) {
// e.printStackTrace();
// } finally {
// }
// }
}

-------------------------------

> Android获取view高度的三种方式:
getMeasuredHeight()与getHeight的区别
实际上在当屏幕可以包裹内容的时候,他们的值相等,
只有当view超出屏幕后,才能看出他们的区别:
getMeasuredHeight()是实际View的大小,与屏幕无关,
而getHeight的大小此时则是屏幕的大小。
当超出屏幕后,getMeasuredHeight()等于getHeight()加上屏幕之外没有显示的大小
具体方法
我们知道在oncreate中View.getWidth和View.getHeight无法获得一个view的高度和宽度,这是因为View组件 布局要在onResume回调后完成。
下面说三种方式
1> getViewTreeObserver
 使用 getViewTreeObserver().addOnGlobalLayoutListener()来获得宽度或者高度。
OnGlobalLayoutListener 是ViewTreeObserver的内部类,当一个视图树的布局发生改变时,可以被ViewTreeObserver监听到,这是一个注册监听视图树的观察者(observer),在视图树的全局事件改变时得到通知。ViewTreeObserver不能直接实例化,而是通过getViewTreeObserver()获得。
除了OnGlobalLayoutListener ,ViewTreeObserver还有如下内部类:
interfaceViewTreeObserver.OnGlobalFocusChangeListener
当在一个视图树中的焦点状态发生改变时,所要调用的回调函数的接口类
interfaceViewTreeObserver.OnGlobalLayoutListener
当在一个视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变时,所要调用的回调函数的接口类
interfaceViewTreeObserver.OnPreDrawListener
当一个视图树将要绘制时,所要调用的回调函数的接口类
interfaceViewTreeObserver.OnScrollChangedListener
当一个视图树中的一些组件发生滚动时,所要调用的回调函数的接口类
interfaceViewTreeObserver.OnTouchModeChangeListener
当一个视图树的触摸模式发生改变时,所要调用的回调函数的接口类
其中,我们可以利用OnGlobalLayoutListener来获得一个视图的真实高度。


private int mHeaderViewHeight; 
private View mHeaderView; 
 
..... 
 
mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener( 
 new OnGlobalLayoutListener() { 
  @Override 
  public void onGlobalLayout() { 
                                                         
   mHeaderViewHeight = mHeaderView.getHeight(); 
   mHeaderView.getViewTreeObserver() 
     .removeGlobalOnLayoutListener(this); 
  } 
}); 
但是需要注意的是OnGlobalLayoutListener可能会被多次触发,因此在得到了高度之后,要将OnGlobalLayoutListener注销掉。


-------------------------
2> 还可以在VIew的post方法中获取
View post事件中获取
 public class TestHeight extends Activity { 
 TextView tv; 
 
 @Override 
 protected void onCreate(Bundle savedInstanceState) { 
  super.onCreate(savedInstanceState); 
  setContentView(R.layout.activity_activity_b); 
   tv = (TextView) findViewById(R.id.textView); 
  tv.post(new Runnable() { 
   @Override 
   public void run() { 
    int height= tv.getHeight(); 
   } 
  }); 
 } 

-------------------------
3> int intw=View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED); 
int inth=View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED); 
textView.measure(intw, inth); 
int intwidth = textView.getMeasuredWidth(); 
int intheight = textView.getMeasuredHeight(); 

0 0
原创粉丝点击