前几天爆出来一个线上bug:处于“已售完”状态的菜品,依然可以点击加菜。好在提交订单时有校验,对于这种订单会直接打回。 究其原因,是加减控件中的代码出了问题
问题回顾 在加减控件中,提供了enlargeEmptyAddBtnClickArea
方法,用来扩大第一次加菜按钮的点击区域(PM提出的渣渣,更渣渣的是UX居然通过了这个需求)。
Talk is cheap, read the code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public void enlargeEmptyAddBtnClickArea (final View parentView, final int unit) { parentView.post(new Runnable() { @Override public void run () { if (emptyAddBtn.getVisibility() != VISIBLE) { return ; } checkContext(); Context context = getContext(); int [] emptyAddBtnCoord = new int [2 ]; emptyAddBtn.getLocationOnScreen(emptyAddBtnCoord); int [] parentViewCoord = new int [2 ]; parentView.getLocationOnScreen(parentViewCoord); int [] relativeCoord = {emptyAddBtnCoord[0 ] - parentViewCoord[0 ], emptyAddBtnCoord[1 ] - parentViewCoord[1 ]}; Rect delegateArea = new Rect(relativeCoord[0 ], relativeCoord[1 ], relativeCoord[0 ] + emptyAddBtn.getMeasuredWidth(), relativeCoord[1 ] + emptyAddBtn.getMeasuredHeight()); int enlargeUnit = ViewUtils.dip2px(context, unit); delegateArea.left -= enlargeUnit; delegateArea.top -= enlargeUnit; delegateArea.right += enlargeUnit; delegateArea.bottom += enlargeUnit; CustomTouchDelegate touchDelegate = new CustomTouchDelegate(delegateArea, emptyAddBtn); parentView.setTouchDelegate(touchDelegate); } }); }
这样通过直接operateBtn.enlargeEmptyAddBtnClickArea
就可以扩大点击区域。
乍看起来没什么问题对吧?代码中同样考虑到了如果加菜按钮
当前不可见,就不会主动扩大其区域。
但是为什么,还会出现文章开头提到的“已售完的菜品仍然可以添加至购物车”问题!!!
原因分析 在debug后,发现问题出在这段代码中的判断
1 2 3 if (emptyAddBtn.getVisibility() != VISIBLE) { return ; }
当整个加减控件(OperateButton)的Visibility == INVISIBLE or GONE时,其内部emptyAddBtn
的Visibility居!然!还!是!Visible!
写个Demo验证一下
Talk is cheap, just code demo功能很简单,外层的ViewGroup & 内层的View,当outer置为不可见(INVISIBLE or GONE)时,输出inner的Visibility。界面如下:
验证后发现一个惊人的事实,Outer的Visibility不会影响Inner的Visibility!也就是说,不论Outer设置为Gone还是Invisible,只要Inner之前是Visible,那么调用inner.getVisibility()
后,都会返回Visible!
正确的判断方法 View.java中为我们提供了isShown()
方法,从注释中即可看出它会将外层ViewGroup可见性计算进去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public boolean isShown () { View current = this ; do { if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { return false ; } ViewParent parent = current.mParent; if (parent == null ) { return false ; } if (!(parent instanceof View)) { return true ; } current = (View) parent; } while (current != null ); return false ; }
反思 起初编码的时候,谁能想到,外层设置Invisibile后,内层View居然还是Visible的状态呢?
出现这个问题的根本原因在于自己对View的机制研究不够深入,引以为戒。
更应该注意到View本身提供了isShown()方法来判断可见性,根本不需要使用Visibility来重复造轮子,更何况还是错误的轮子。
=========END=========
最后更新时间:2016-06-29 13:21:54
本文系作者原创,如转载请注明出处。欢迎留言讨论,或通过邮件进行沟通~