开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情
自定义ViewGroup
generateLayoutParams(AttributeSet)
注意此方法存在重载方法generateLayoutParams(params)(这个是用于在addView函数中,当
checkLayoutParams(params)返回false时会通过generateLayoutParams(params)重新生成新的params),还有一个generateDefaultParams(),当 generateLayoutParams(AttributeSet)生成的params为null时,会通过这个函数生成一个默认的params,作用不同,需要区分。
当viewGroup自定义view,需要对直接子view的LayoutParams做处理并生成新的LayoutParams可以覆盖此方法
原因:inflate时,在addView()之前会通过该viewGroup的generateLayoutParams(AttributeSet)生成该子view的LayoutParams并作为参数传递给addView,像FrameLayout都覆盖了此方法。
出错处:继承ViewGroup时,没有覆盖此方法就在measure中调用measureChildwWithMargins导致报错,因为measureChildwWithMargins会把子view的Layoutparams强转为Layoutparams的子类MarginLayoutParams,但是由于generateLayoutParams(params)默认返回LayoutLarams,导致强转失败。
解决办法就是使generateLayoutParams(params)返回MarginLayoutParams类型。
只能操作直接子view的layoutParams,孙子view不可以
onMeasure
如果在onmeasure不对子view的margin做处理,也就是不调用measureChildwWithMargins而调用measureChildren,会导致子view设置margin失效。
ViewGroup处理子view滑动时,可以使用ViewDragHelper。
使用方法:ViewDragHelper.create()创建ViewDragHelper并添加回调函数
在回调函数中可以处理事件的响应包括滑动的距离
在onTouchEvent中通过ViewDragHelper.processTouchEvent交由ViewDragHelper处理
如果滑动后会在回调函数中调用onViewPositionChanged可以在这个函数里面继续滑动或者做其他事情
onInterCeptTouchEvent可以交由ViewDragHelper.shouldInterceptTouchEvent处理
自定义View
在处理Move事件时,如果只是简单的将getX,getY处理滑动距离,会导致响应Move事件的view移动时产生抖动。
解决办法:
1.将getX,getY换成getRawX,getRawY(返回屏幕绝对坐标);
2.有可能是Move事件中没有记录当前滑动到的地方,
比如:
switch (ev.getActionMasked())
{
case MotionEvent.ACTION_DOWN:{
lastx = (int)ev.getX();
}
case MotionEvent.ACTION_MOVE:
{
int dx = (int)ev.getX()-lastx;
ViewCompat.offsetLeftAndRight(getChildAt(0),dx);
//这里需要更新当前移动到的位置,方便下次Move事件到来时,从新位置开始计算
lastx += dx;
}
}
同时,移动View尽量选择ViewCompat.offsetLeftAndRight和ViewCompat.offsetTopAndBottom
虽然View.setTranslationY()和View.setTranslationY()也可以移动,但这个函数没有改变view的left、top、right的值,对view做动画时可以选择这个函数,如果只是单纯的移动view则使用ViewCompat.offsetLeftAndRight和ViewCompat.offsetTopAndBottom
不要使用setLayoutParams的方式改变view的方式,这种性能比ViewCompat.offsetTopAndBottom低,因为它会导致重绘的发生。
invalidate()会导致draw()的发生,但是不一定会导致onDraw(),因为内部有判断是否发生onDraw(),但是类似ViewCompat.offsetTopAndBottom不会导致draw()的发生
computeScroll() 每次绘制时(执行draw())都会调用这个函数。
谷歌这样解释这个函数的:在必要时更新其 mScrollX 和 mScrollY 的值。如果正在使用Scroller对象对滚动进行动画处理,通常会这样做。