- android:fillViewport=“true”
android:fillViewport=“true”
这样ScrollView就会被强制要求测量ChildView并设置模式MeasureSpec.EXACTLY,所以ListView会完全展开。
第二个问题
=========
ScrollView嵌套ListView时,一般我们有两种需求
第一种是ListVIew完全伸展并跟随ScrollView一起滑动,那只要按照上面的解决了伸展的问题, 就实现这种效果了,因为ScrollView默认是拦截ListView的滑动事件的。
第二种是ScrollView不拦截滑动事件,当我们在ListView区域滑动时,由ListView处理滑动事件,只有在ListView已到达顶部还继续向上滑或者ListView已到达底部还继续向下滑时才重新拦截滑动事件。而当我们在非ListView区域滑动时,则直接由ScrollView处理滑动事件,那么我们看看怎么实现这种效果。
首先,我们先了解为什么ListView无法获取到滑动事件,我们先看一下ScrollView的onInterceptTouchEvent方法
[java] view plain copy
-
@Override
-
public boolean onInterceptTouchEvent(MotionEvent ev) {
-
final int action = ev.getAction();
-
if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
-
return true;
-
}
-
省略
-
//………
-
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
return true;
}
省略
//…
}
不重要的部分被我省略了,mIsBeingDragged是最小滑动像素,超过这个值才被认为是发生滑动了。那从上面的代码我们可以看出的,当发生滑动的第一时间,事件就被ScrollView拦截了,所以ListView不能滑动
但是我们注意到,在MotionEvent.ACTION_MOVE之前是会产生一个MotionEvent.ACTION_DOWN的,那么这个事件是没有被拦截的,并且在滑动未超过最小像素之前,
MotionEvent.ACTION_MOVE也是未被拦截的,那么其实我们是可以在ListView里面接收到MotionEvent.ACTION_DOWN和几个MotionEvent.ACTION_MOVE的。
既然如此,那我们在自定义ListView里面请求ScrollView不要拦截事件不就好了吗。
[java] view plain copy
-
public class MyListview extends ListView{
-
private ScrollView mParent;
-
private float mDownY;
-
public MyListview(Context context) {
-
super(context);
-
}
-
public MyListview(Context context, AttributeSet attrs) {
-
super(context, attrs);
-
}
-
public MyListview(Context context, AttributeSet attrs, int defStyleAttr) {
-
super(context, attrs, defStyleAttr);
-
}
-
public void setParent(ScrollView view){
-
mParent = view;
-
}
-
//重写该方法 在按下的时候让父容器不处理滑动事件
-
@Override
-
public boolean onTouchEvent(MotionEvent ev) {
-
switch (ev.getAction()) {
-
case MotionEvent.ACTION_DOWN:
-
setParentScrollAble(false);
-
mDownY = ev.getY();
-
break;
-
case MotionEvent.ACTION_MOVE:
-
//
-
if (isListViewReachTop() && ev.getY() - mDownY > 0) {
-
setParentScrollAble(true);
-
} else if (isListViewReachBottom() && ev.getY() - mDownY < 0) {
-
setParentScrollAble(true);
-
}
-
break;
-
case MotionEvent.ACTION_UP:
-
case MotionEvent.ACTION_CANCEL:
-
setParentScrollAble(true);
-
break;
-
default:
-
break;
-
}
-
return super.onTouchEvent(ev);
-
}
-
/**
-
* @param flag
-
*/
-
private void setParentScrollAble(boolean flag) {
-
mParent.requestDisallowInterceptTouchEvent(!flag);
-
}
-
public boolean isListViewReachTop() {
-
boolean result=false;
-
if(getFirstVisiblePosition()==0){
-
View topChildView = getChildAt(0);
-
if (topChildView != null) {
-
result=topChildView.getTop()==0;
-
}
-
}
-
return result ;
-
}
-
public boolean isListViewReachBottom() {
-
boolean result=false;
-
if (getLastVisiblePosition() == (getCount() - 1)) {
-
View bottomChildView = getChildAt(getLastVisiblePosition() - getFirstVisiblePosition());
-
if (bottomChildView != null) {
-
result= (getHeight() >= bottomChildView.getBottom());
-
}
-
}
-
return result;
-
}
-
}
public class MyListview extends ListView{
private ScrollView mParent;
private float mDownY;
public MyListview(Context context) {
super(context);
}
public MyListview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyListview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setParent(ScrollView view){
mParent = view;
}
//重写该方法 在按下的时候让父容器不处理滑动事件
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
setParentScrollAble(false);
mDownY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
//
if (isListViewReachTop() && ev.getY() - mDownY > 0) {
setParentScrollAble(true);
} else if (isListViewReachBottom() && ev.getY() - mDownY < 0) {
setParentScrollAble(true);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
setParentScrollAble(true);
break;
default:
break;
}
return super.onTouchEvent(ev);
}
/**
- @param flag
*/
private void setParentScrollAble(boolean flag) {
mParent.requestDisallowInterceptTouchEvent(!flag);
}
如何做好面试突击,规划学习方向?
面试题集可以帮助你查漏补缺,有方向有针对性的学习,为之后进大厂做准备。但是如果你仅仅是看一遍,而不去学习和深究。那么这份面试题对你的帮助会很有限。最终还是要靠资深技术水平说话。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。建议先制定学习计划,根据学习计划把知识点关联起来,形成一个系统化的知识体系。
学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。
同时我还搜集整理2020年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。
在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。
[外链图片转存中…(img-SOyJ2PTG-1715392188659)]
在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。
[外链图片转存中…(img-DpZX7Z3P-1715392188659)]
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!