文章开头先说一下listView和ScrollView相互嵌套的问题,由于需求和UI布局上的要求多样化,自然而然的衍生了ScrollView嵌套listView等的需求,虽然谷歌官方是不建议这样,关于listView嵌套后的滑动冲突,网上有很多方法,在此只说一下自己的方法:
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // TODO 自动生成的方法存根
- int expandSpec = MeasureSpec.makeMeasureSpec(
- Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
- super.onMeasure(widthMeasureSpec, expandSpec);
- }
这个代码原理是禁用了ListView本身的滑动功能,强制它们的item全部显示,简而言之就是取消listView子控件的滑动,并且强制定义高度,接下来就是我们重点要说明的问题,既然我们为了嵌套取消了listView的滑动,自然也不存在上拉刷新下拉加载的监听,所以为了方便就自定义了ScrollViewBottom。
第一:ScrollViewBottom继承ScrollView
定义了ScrollViewBottom类之后,直接继承ScrollView就好。需要注意的是定义View时必须派生实现基类View的三个构造函数 ,否则当程序运行时会出现布局文件报错异常,例如:
android.view.InflateException: Binary XML file line #22: Binary XML file line #22:
出现此类问题常见的原因和解决方法:
1.自定义View必须使用完整路径名。
2.定义View,必须派生实现基类View的三个构造函数 。
View(Context context) //Simple constructor to use when creating a view from code
View(Context context, AttributeSet attrs) //Constructor that is called when inflating a view from XML
View(Context context, AttributeSet attrs, int defStyle) //Perform inflation from XML and apply a class-specific base style
3.Rebuild project
4.资源文件引用错误(例如drawable引用为color之类)。
第二定义监听:
/**
* 描述:定义到达顶部和底部响应事件接口OnBorderListener
*/
public interface OnBorderListener {
/**
* Called when scroll to bottom
*/
public void onBottom();
/**
* Called when scroll to top
*/
public void onTop();
}
第三实现自定义ScrollViewBottom:
private OnBorderListener onBorderTouchListener;
/**
* 初始化滑动监听方法
*/
private void initListener() {
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_UP:
doOnBorderListener(view);
break;
}
return false;
}
});
}
private void doOnBorderListener(View contentView) {
int scrollY = contentView.getScrollY();
int height = contentView.getHeight();
int scrollViewMeasuredHeight = getChildAt(0).getMeasuredHeight();
if (contentView != null && (scrollY + height) == scrollViewMeasuredHeight) {
// 到达底部,刷新数据
if (onBorderTouchListener != null) {
onBorderTouchListener.onBottom();
}
} else if (scrollY == 0) {
if (onBorderTouchListener != null) {
onBorderTouchListener.onTop();
}
}
}
public void setOnScrollToBottomLintener(OnBorderListener listener) {
onBorderTouchListener = listener;
}
在布局中引用自定义的ScrollViewBottom后,直接在界面中声明
ScrollViewBottom.setOnScrollToBottomLintener(new OnBorderListener() {
@Override
public void onBottom() {
// 到达底部,加载数据
}
@Override
public void onTop() {
// 到达顶部,刷新数据
}
});
滚动到顶部判断:getScrollY() == 0
滚动到底部判断:
View contentView = getChildAt(0);
contentView.getMeasuredHeight() <= getScrollY() + getHeight();
View contentView = getChildAt(0);
contentView.getMeasuredHeight() <= getScrollY() + getHeight();
其中getChildAt表示得到ScrollView的child View,因为ScrollView只允许一个child view,所以contentView.getMeasuredHeight()表示得到子View的高度, getScrollY()表示得到y轴的滚动距离,getHeight()为scrollView的高度。当getScrollY()达到最大时加上scrollView的高度就的就等于它内容的高度