解决 ScrollView 嵌套 ListView 时,高度不正常和滑动冲突的问题

  1. 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

print ?

  1. @Override

  2. public boolean onInterceptTouchEvent(MotionEvent ev) {

  3. final int action = ev.getAction();

  4. if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {

  5. return true;

  6. }

  7. 省略

  8. //………

  9. }

@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

print ?

  1. public class MyListview extends ListView{

  2. private ScrollView mParent;

  3. private float mDownY;

  4. public MyListview(Context context) {

  5. super(context);

  6. }

  7. public MyListview(Context context, AttributeSet attrs) {

  8. super(context, attrs);

  9. }

  10. public MyListview(Context context, AttributeSet attrs, int defStyleAttr) {

  11. super(context, attrs, defStyleAttr);

  12. }

  13. public void setParent(ScrollView view){

  14. mParent = view;

  15. }

  16. //重写该方法 在按下的时候让父容器不处理滑动事件

  17. @Override

  18. public boolean onTouchEvent(MotionEvent ev) {

  19. switch (ev.getAction()) {

  20. case MotionEvent.ACTION_DOWN:

  21. setParentScrollAble(false);

  22. mDownY = ev.getY();

  23. break;

  24. case MotionEvent.ACTION_MOVE:

  25. //

  26. if (isListViewReachTop() && ev.getY() - mDownY > 0) {

  27. setParentScrollAble(true);

  28. } else if (isListViewReachBottom() && ev.getY() - mDownY < 0) {

  29. setParentScrollAble(true);

  30. }

  31. break;

  32. case MotionEvent.ACTION_UP:

  33. case MotionEvent.ACTION_CANCEL:

  34. setParentScrollAble(true);

  35. break;

  36. default:

  37. break;

  38. }

  39. return super.onTouchEvent(ev);

  40. }

  41. /**

  42. * @param flag

  43. */

  44. private void setParentScrollAble(boolean flag) {

  45. mParent.requestDisallowInterceptTouchEvent(!flag);

  46. }

  47. public boolean isListViewReachTop() {

  48. boolean result=false;

  49. if(getFirstVisiblePosition()==0){

  50. View topChildView = getChildAt(0);

  51. if (topChildView != null) {

  52. result=topChildView.getTop()==0;

  53. }

  54. }

  55. return result ;

  56. }

  57. public boolean isListViewReachBottom() {

  58. boolean result=false;

  59. if (getLastVisiblePosition() == (getCount() - 1)) {

  60. View bottomChildView = getChildAt(getLastVisiblePosition() - getFirstVisiblePosition());

  61. if (bottomChildView != null) {

  62. result= (getHeight() >= bottomChildView.getBottom());

  63. }

  64. }

  65. return  result;

  66. }

  67. }

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(实际上比预期多花了不少精力),包含知识脉络 + 分支细节

image

在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。

image

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节

[外链图片转存中…(img-SOyJ2PTG-1715392188659)]

在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。

[外链图片转存中…(img-DpZX7Z3P-1715392188659)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值