携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天,点击查看活动详情
背景
今天接到一个需求,需要在以前的列表部分添加一个栏目,同时要一个事件,效果图如下:
心想这个不是分分钟搞定吗,结果不到十分钟搞完,搞完之后自己一测试,直接懵逼了,怎么我操作我的按钮把别的栏目的状态也改了,我回过头仔细看一下源码
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
initSwitchView()
}
private fun initSwitchView() {
var isWriteInvoice = AppPrefsUtils.getBoolean(BaseConstant.SP_IS_WRITE_INVOICE, true)
var isPrintInvoice = AppPrefsUtils.getBoolean(BaseConstant.SP_IS_PRINT_INVOICE, true)
var isPrintInvoiceDetail =
AppPrefsUtils.getBoolean(BaseConstant.SP_IS_PRINT_INVOICE_DETAIL, true)
var isDeliveryWriteInvoice =
AppPrefsUtils.getBoolean(BaseConstant.SP_IS_DELIVERY_WRITE_INVOICE, true)
cmvSwitchWriteInvoice.setRightSwitchBtnStatus(isWriteInvoice)
cmvDeliveryWriteInvoice.setRightSwitchBtnStatus(isDeliveryWriteInvoice)
cmvSwitchPrintInvoice.setRightSwitchBtnStatus(isPrintInvoice)
cmvSwitchPrintDetail.setRightSwitchBtnStatus(isPrintInvoiceDetail)
}
怎么初始化给控件赋值放到onWindowFocusChanged这个方法里面,难怪会改变别的栏目的状态.
继续进入对应控件的方法中去分析,发现一个问题
public void setCurrentState(Boolean isOpen){
if(isOpen&&mCurrentState==State.CLOSE){
mCurrentState = State.OPEN;
animate(mStrokeRadius, BALL_X_RIGHT, greyColor, greenColor);
}else if(!isOpen&&mCurrentState==State.OPEN){
mCurrentState = State.CLOSE;
animate(BALL_X_RIGHT, mStrokeRadius, greenColor, greyColor);
}
}
这个BALL_X_RIGHT的值是需要等onSizeChanged执行完之后才有值
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mViewHeight = h;
mViewWidth = w;
// 默认描边宽度是控件宽度的1/30, 比如控件宽度是120dp, 描边宽度就是4dp
switchViewStrockWidth = w * 1.0f / 30;
mStrokeRadius = mViewHeight / 2;
mSolidRadius = (mViewHeight - 2 * switchViewStrockWidth) / 2;
BALL_X_RIGHT = mViewWidth - mStrokeRadius;
mSwitchBallx = mStrokeRadius;
mBgStrokeRectF = new RectF(0, 0, mViewWidth, mViewHeight);
}
感觉有可能是控件还没有绘制完导致设置状态的显示有问题.在解决问题之前我们要看看onWindowFocusChanged的作用
onWindowFocusChanged
会调用onWindowFocusChanged方法的场景:
- 在Activity窗口获得或失去焦点时被调用,例如创建时首次呈现在用户面前;
- 当前Activity被其他Activity覆盖;
- 当前Activity转到其他Activity或按Home键回到主屏,自身退居后台;
- 用户退出当前Activity。
以上几种情况都会调用,并且当Activity被创建时是在onResume之后被调用,当Activity被覆盖或者退居后台或者当前Activity退出时,它是在onPause之后被调用。
这个方法在某种场合下还是很有用的,例如程序启动时想要获取视特定视图组件的尺寸大小,在onCreate中可能无法取到,因为窗口Window对象还没创建完成,这个时候我们就需要在onWindowFocusChanged里获取。
解决办法
现在需要解决的问题在UI测量完成之后调用给控件设置的方法
可以通过ViewTreeObserver这个类来监听addOnPreDrawListener或者addOnGlobalLayoutListener事件解决这个问题,我选择使用addOnPreDrawListener这个方法来处理
btSave.viewTreeObserver.addOnGlobalLayoutListener {
initSwitchView()
}
备注:btSave是xml里面的任意一个控件