真-ViewPager与ScrollView间的ViewPager消失及滑动冲突关系
来源:互联网 发布:whatsapp mac 编辑:程序博客网 时间:2024/06/12 20:02
前话
今天公司项目遇到了ViewPager+ScrollView的布局方式,水平滑动+垂直滑动,可想而知可能会产生冲突。作为老司机,自信满满的准备好了解决冲突的方案,开撸。
写好运行一波后发现,尼玛啊,ViewPager不见了,说实话以前还真没有写过这种嵌套。没办法,试试将ViewPager固定一下高度呢,看看它存不存在。还真在,这下能看见了。可是不科学啊,我怎么知道页面数据有多少呢,固定值肯定行不通啊。
很自然的,打开浏览器—>谷歌一波。
搜索ViewPager+ScrollView嵌套ViewPager消失的网页很多,大多都一句话:设置ScrollView android:fillViewport=”true”!没想到这么简单,试试看!
果然,可行!网上说,用了这个之后ViewPager会无法滑动,我试了一下没出现啊,结果垂直方向滑不动了,妈的不按套路出牌。心想滑动冲突还不是smallCase。
于是按套路去解决了。至于套路是啥:无非分为外部解决和内部解决。具体方案本文不介绍了,出于:《安卓开发艺术探索》。网上也一大堆,可自行搜索。
ScrollView
经过一番折腾后发现并无卵用,他俩的事件分发完全没错,这就很尴尬了。那不是滑动的问题,会是啥呢?只能是控件本身高度就不够咯,嗯,测量出了问题。
翻翻源码吧,先看ScrollView。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (!mFillViewport) { return; } final int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (heightMode == MeasureSpec.UNSPECIFIED) { return; } if (getChildCount() > 0) { final View child = getChildAt(0); final int widthPadding; final int heightPadding; final int targetSdkVersion = getContext() .getApplicationInfo().targetSdkVersion; final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (targetSdkVersion >= VERSION_CODES.M) { widthPadding = mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin; heightPadding = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin; } else { widthPadding = mPaddingLeft + mPaddingRight; heightPadding = mPaddingTop + mPaddingBottom; } final int desiredHeight = getMeasuredHeight() - heightPadding; if (child.getMeasuredHeight() < desiredHeight) { final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, widthPadding, lp.width); final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(desiredHeight, MeasureSpec.EXACTLY); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } } }
关键是:
if (!mFillViewport) { return; }
这个mFillViewport看名字就很熟悉,就是刚刚我网上的方案咯,XML里面设置为True了。这里能看出来如果是false,直接返回了,相当于啥也没写,走父类的正常测量方式了。
为true的话,往下走,由于ScrollView只有一个子View,所以测量起来也很简单了。上面的代码用文字解释为:
首先获取儿子大小,如果儿子比自己小,把儿子撑到和自己一样大。如果儿子更大,就任由发展,如下:
难怪我最开始固定设置很大的时候能显示。那也就是说,滑不动是因为撑到一样大而已,并不能显示更多。换句话来说,不是“滑不动”,而是“没有了”。
ViewPager
ViewPager为什么高度不够呢,明明我在里面cang了很多东西啊,好吧,继续看ViewPager源码。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // For simple implementation, our internal size is always 0. // We depend on the container to specify the layout size of // our view. We can't really know what it is since we will be // adding and removing different arbitrary views and do not // want the layout to change as this happens.setMeasuredDimension(getDefaultSize(0,widthMeasureSpec), getDefaultSize(0, heightMeasureSpec)); //省略儿子的测量代码 }
卧槽,看到第一句我就惊呆了,直接按最初大小了,根本没有管Pager里面的控件,不管塞多少大小都是最初的(固定值:父布局分配的)。
好吧,终于找到原因了,我们重写onMeasure帮它测一下儿子的高度,再决定自己的高度。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); View maxHeightView = getChildAt(0); int size = getChildCount(); //一个一个测量子View for (int i = 0; i < size; i++) { View child = getChildAt(i); if (child != null && child.getVisibility() != GONE) { child.measure(widthMeasureSpec, heightMeasureSpec); if (child.getHeight() > maxHeightView.getHeight()) { maxHeightView = child; } } } //按viewpager里最大的那个高度算。 if (maxHeightView != null) { setMeasuredDimension(getMeasuredWidth(), measureHeight(heightMeasureSpec, maxHeightView)); } } private int measureHeight(int measureSpec, View view) { int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); //如果是固定值或match_parent if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { result = view.getMeasuredHeight(); //wrap_content if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; }
运行,成功!果然百度谷歌不是万能的,有时候学会看源码也是很重要的,熟悉理解View绘制原理的话,解决起来一定不会很耗时。
至于滑动冲突,TMD我压根没遇到,应该是viewpager内部已经做好了处理吧,害我一开始就走错了方向。
参考文献:
http://smilehacker.com/zai-scrollviewzhong-shi-yong-viewpageryi-ji-viewpagershi-yong-wrap_content.html
- 真-ViewPager与ScrollView间的ViewPager消失及滑动冲突关系
- Android ScrollView与ViewPager滑动上下左右冲突
- ScrollView嵌入ViewPager 滑动冲突的解决方法
- scrollview 嵌套 viewpager 滑动冲突的解决办法
- ScrollView嵌套ViewPager滑动冲突的解决
- ScrollView嵌套ViewPager滑动冲突的问题
- ScrollView中嵌入ViewPager,ViewPager的左右滑动冲突问题
- scrollview嵌套viewpager 滑动冲突
- viewpager+fragment+viewpager+scrollview滑动冲突问题
- ViewPager,ScrollView 嵌套ViewPager滑动冲突解决
- ViewPager,ScrollView 嵌套ViewPager滑动冲突解决
- ViewPager,ScrollView 嵌套ViewPager滑动冲突解决
- ViewPager,ScrollView 嵌套ViewPager滑动冲突解决
- ViewPager,ScrollView 嵌套ViewPager滑动冲突解决
- ViewPager,ScrollView 嵌套ViewPager滑动冲突解决
- ViewPager,ScrollView 嵌套ViewPager滑动冲突解决
- ViewPager,ScrollView 嵌套ViewPager滑动冲突解决
- ViewPager,ScrollView 嵌套ViewPager滑动冲突解决
- 二维线段树专题
- tornado压测
- 微信图灵机器人
- 配置Nginx正向代理
- BZOJ 4800: [Ceoi2015]Ice Hockey World Championship meet_in_the_middle
- 真-ViewPager与ScrollView间的ViewPager消失及滑动冲突关系
- TensorBoard使用
- 每天一个linux命令(48):watch命令
- 未来的模式等着我们开启,hello world!
- 栈和队列之仅用递归函数和栈操作逆序一个栈
- POJ 2279 Mr. Young's Picture Permutations(杨氏矩阵和钩子公式)
- 判断STL list是否为空的小技巧
- Javascript程序设计思维
- NKOJ 3615(CQOI 2016) 路由表(trie)