每次进入详情页,标题栏都会闪一下,特别是图标部分,很明显,可以看下面的gif
如果不明显,可以看下面两张对比图片
异常态
正常态
可以看到,在打开详情页的动画过程中,会闪一下异常的UI
首先看下现有的代码
<TextView
style="@style/detail_tag_style"
android:layout_marginRight="6dp"
android:text="@string/platform_offers"
android:visibility="@{(item.isCashBack == true)?View.VISIBLE:View.GONE}" />
<ImageView
android:id="@+id/ivAllowInvoice"
android:background="@drawable/icon_invoice"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginRight="6dp"
android:visibility="@{(item.allowInvoice == true)?View.VISIBLE:View.GONE}" />
可以看到,布局是使用databinding来实现的,用item的值来判断可见性,自行验证了下,item的值没有问题,设置item是在onbindviewholder设置的,我们看下代码
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val detailItem = detail.spuDetailResult
if (holder is ImageItemHolder) {
//忽略
} else if (holder is DetailTopHolder) {
holder.topBinding.item = detailItem //绑定数据的地方
//其他代码忽略
}
}
topBinding的对象是ItemDetailTopItemBinding,设置item的方法,是AS自动生成的,叫做ItemDetailTopItemBindingImpl,具体实现在这个类里面
public void setItem(@Nullable com.ygp.mro.data.GoodsDetail Item) {
this.mItem = Item;
synchronized(this) {
mDirtyFlags |= 0x1L;
}
notifyPropertyChanged(BR.item);
super.requestRebind(); //这里触发刷新
}
继续往下看
protected void requestRebind() {
//其他代码忽略
if (USE_CHOREOGRAPHER) {
mChoreographer.postFrameCallback(mFrameCallback);
} else {
mUIThreadHandler.post(mRebindRunnable);
}
}
最终实现的是mChoreographer.postFrameCallback方法,可以知道,其实是异步实现的,所以问题的是
databinding设置data是异步生效(下一次绘制),不是直接生效
问题的解决,有两个方案
val visilble = if (detailItem.allowInvoice) {
View.VISIBLE
} else {
View.GONE
}
holder.topBinding.ivAllowInvoice.visibility = visilble
这样就可以避免闪烁的问题了,不过同时也没有用到databidning特性了,违背了原本的设计思路
可以在xml里面,设置view默认为不可见
<ImageView
android:id="@+id/ivAllowInvoice"
android:background="@drawable/icon_invoice"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginRight="6dp"
android:visibility="@{(item.allowInvoice == true)?View.VISIBLE:View.GONE,default=gone}" />
最后的这个default=gone就会设置默认不可见(感谢伟华提供方案),所以也就不会闪一下了,这个default属性在官方的文档里面没有提到,还是在网上搜索到的
为什么加了default=gone就不会闪了,抱着这个疑问,分别对比了有设置default=gone跟没有设置,自动生成的ItemDetailTopItemBinding类,有没有差别,最终发现,没有任何差别
接着怀疑,问题应该是处在最终的apk上面,于是把生成的apk的xml打开,发现如下情况
<ImageView
android:id="@ref/0x7f0a0171"
android:tag="binding_11"
android:background="@ref/0x7f08009d"
android:visibility="2"
android:layout_width="dimension(4097)"
android:layout_height="dimension(4097)"
android:layout_marginRight="dimension(1537)" />
自动给view加了visibility="2"的属性,2就是代表View.GONE,原来是在apk打包的时候,给view自动加了不可见的属性
databinding设置data,是异步生效,如果碰到闪烁情况,可以加default属性 其实还有个疑问,虽然是异步生效,但其实是下一帧绘制的时候生效,理论上也是不应该出现闪烁的,这个闪烁,我发现是部分机型上才会出现,也不是所有机型必现的,这个涉及不同rom底层的实现,暂时也还没弄清楚...