Android使用Kaspresso测试时VectorDrawable比对失败问题咨询
问题根因
- 尺寸不匹配:默认的
hasDrawable方法加载预期VectorDrawable时,直接从资源读取未关联目标ImageView的测量参数,转Bitmap时采用drawable自身的固有宽高;而手动设置到ImageView上的VectorDrawable会被缩放适配ImageView的尺寸,两者生成的Bitmap尺寸不一致,像素比对直接失败。DataBinding设置图片时内部会自动将加载的VectorDrawable尺寸与ImageView参数做预适配,因此转出来的Bitmap和预期值尺寸一致,比对可通过。 - Tint配置未对齐:如果你在代码中手动给ImageView设置了tint属性,但调用
hasDrawable时未传入对应的tint色值ID,匹配器不会给预期drawable添加相同的tint效果,最终生成的Bitmap颜色差异导致比对失败。 - 版本适配差异:Android 5.0以下系统中VectorDrawable的兼容包装逻辑不一致,如果手动设置时未通过DrawableCompat包装VectorDrawable,和匹配器内部包装后的预期drawable生成的Bitmap也会存在差异。
解决方案
方案1:自定义VectorDrawable专用匹配器(最稳定)
直接抛弃默认的像素比对逻辑,改为匹配VectorDrawable的ConstantState,代码示例:
fun hasVectorDrawable(@DrawableRes resId: Int): ViewAssertion { return ViewAssertion { view, noViewFoundException -> noViewFoundException?.let { throw it } if (view !is ImageView) { throw AssertionError("View is not an ImageView") } val actualDrawable = view.drawable ?: throw AssertionError("ImageView has no drawable") val expectedDrawable = ContextCompat.getDrawable(view.context, resId) ?: throw AssertionError("Expected drawable not found") // 校验ConstantState,同资源VectorDrawable的ConstantState默认一致 if (actualDrawable.constantState != expectedDrawable.constantState) { throw AssertionError("Drawable does not match expected resource $resId") } } }
使用方式:
withId<KImageView>(R.id.criticalErrorImage) { check(hasVectorDrawable(R.drawable.error_graphic)) }
注意:如果业务代码中对drawable调用过
mutate()方法修改属性,ConstantState会发生变化,此场景下推荐使用方案2。
方案2:修改默认hasDrawable的Bitmap转换逻辑
调用hasDrawable时传入自定义的toBitmap参数,强制将两个drawable都缩放到相同尺寸再转Bitmap:
withId<KImageView>(R.id.criticalErrorImage) { hasDrawable( resId = R.drawable.error_graphic, toBitmap = { drawable -> // 可自定义统一缩放尺寸,也可读取目标ImageView的测量尺寸作为参数 Bitmap.createScaledBitmap(drawable.toBitmap(), 200, 200, true) } ) }
方案3:补全Tint参数
如果是tint导致的比对失败,调用hasDrawable时主动传入你设置的tint色值ID即可:
withId<KImageView>(R.id.criticalErrorImage) { hasDrawable( resId = R.drawable.error_graphic, tintColorId = R.color.your_tint_color ) }
内容的提问来源于stack exchange,提问作者Filnik
相关产品推荐
相关产品推荐

