资讯动态

Fresco Drawee 圆角与圆形图片实战指南:RoundingParams 配置、原理与权衡

发布时间:2026/9/21 15:22:35 来源:尧图企业网站定制
Fresco Drawee 圆角与圆形图片实战指南RoundingParams 配置、原理与权衡【免费下载链接】frescoAn Android library for managing images and the memory they use.项目地址: https://gitcode.com/gh_mirrors/fr/fresco在 Android 应用中并非所有图片都是矩形——圆角卡片、圆形头像、标签气泡等场景随处可见。Fresco 的 Drawee 体系为此提供了完整的圆角Rounded Corners与圆形Circle支持SimpleDraweeView只需一行 XML 属性或少量 Java 代码即可完成形状裁剪且全程不复制位图、不产生额外内存开销。本文以 Fresco 仓库中的官方文档 docs/_docs/rounded-corners-and-circles.md 为主体结合drawee模块的源码实现为你讲透两种形状、两种实现方式、全部配置项、底层渲染原理与已知陷阱读完即可在生产项目中直接落地。一、设计目标不加内存开销地“变圆”Drawee 圆角方案的核心承诺是所有圆角/圆形效果都在绘制层Drawable 层完成而不是通过拷贝位图来实现。传统做法是创建一张圆角裁剪后的临时 Bitmap这在图片较大时会产生显著的内存峰值且与 Fresco 高效管理位图内存的宗旨相悖。Drawee 的RoundedDrawable系列如 RoundedBitmapDrawable.kt、RoundedColorDrawable.java、RoundedCornersDrawable.java在绘制时对原始 Drawable 做形状约束因此内存模型与普通矩形图片完全一致。二、两种形状圆形与圆角矩形图片可以被裁剪成两种基本形状圆形Circle将roundAsCircle设为true。此时以控件宽高中较小者为直径绘制内切圆roundedCornerRadius会被忽略。圆角矩形Rounded Rectangle将roundedCornerRadius设为某个值dimension 类型四个角统一使用该半径。矩形还支持四个角各自不同的半径但这一能力只能通过 Java 代码指定XML 无法表达XML 只能通过roundTopLeft、roundBottomRight等布尔开关独立控制某个角是否圆角半径仍是统一的。从源码看RoundingParams.java 内部用float[] mCornersRadii长度 8保存半径每个角包含 X、Y 两个半径值按左上、右上、右下、左下顺序排列。对应代码 API// 统一半径像素 RoundingParams.fromCornersRadius(7f); // 四个角各自不同半径像素顺序topLeft, topRight, bottomRight, bottomLeft RoundingParams.fromCornersRadii(10f, 5f, 10f, 5f); // 更精细的 8 值版本[X, Y] 成对顺序为左上、右上、右下、左下 RoundingParams.fromCornersRadii(new float[] {10f, 10f, 5f, 5f, 10f, 10f, 5f, 5f});源码中的setCornersRadii(float[] radii)RoundingParams.java会校验数组必须恰好包含 8 个值否则抛出异常setCornersRadius(float radius)则用Arrays.fill一次填充所有角。工厂方法asCircle()则直接返回setRoundAsCircle(true)的实例见 RoundingParams.java。三、两种实现方式BITMAP_ONLY 与 OVERLAY_COLOR圆角可以通过两种不同的方法实现对应 RoundingParams.java 中的RoundingMethod枚举3.1 BITMAP_ONLY默认使用BitmapShader位图着色器将位图按圆角路径绘制是默认方法对应枚举值BITMAP_ONLY。它有两条硬性限制不支持动画GIF、WebP 动图等无法圆角只支持有限的 ScaleTypecenterCrop默认、focusCrop、fit_xy。若搭配center等其他缩放类型不会抛异常但显示效果可能错误例如源图小于控件时出现边缘重复详见第五节。从实现看RoundedBitmapDrawable.kt 中正是paint.setShader(BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP))——使用CLAMP 平铺模式绘制位图这直接解释了图片未铺满控件时边缘像素被重复填充的经典现象。3.2 OVERLAY_COLOR通过在图片上方叠加一层调用者指定的纯色来遮出圆角。使用前提是 Drawee 的背景必须是静态的、与叠加色相同的纯色。XML 中用roundWithOverlayColor指定叠加色代码中用setOverlayColor指定。源码细节setOverlayColor(ColorInt int overlayColor)在设置颜色值的同时会自动把mRoundingMethod切换为OVERLAY_COLOR见 RoundingParams.java无需手动再调setRoundingMethod。3.3 两种方式的底层分发逻辑圆角最终由 WrappingUtils.java 负责应用它根据RoundingMethod走两条完全不同的路径BITMAP_ONLY → 叶子圆角updateLeafRoundingWrappingUtils.java沿 Drawable 链找到最内层的叶子调用applyLeafRounding将其替换为RoundedBitmapDrawable/RoundedColorDrawable等圆角包装。applyLeafRounding明确只处理BitmapDrawable与ColorDrawable见 WrappingUtils.java遇到无法识别的类型会通过FLog.w打印 Dont know how to round that drawable 并原样返回。OVERLAY_COLOR → 顶层叠加updateOverlayColorRoundingWrappingUtils.java在层级最外层包一层RoundedCornersDrawable把叠加色画在图片之上。每次调用GenericDraweeHierarchy.setRoundingParams()时两个方法会被同步执行保证两种模式可以随时切换、增删见 GenericDraweeHierarchy.java。四、在 XML 中配置SimpleDraweeView会将其上声明的圆角相关属性转发给内部的RoundingParams。属性定义在 drawee/src/main/res/values/attrs.xml 的GenericDraweeHierarchystyleable 中SimpleDraweeView通过继承完整复用见 attrs.xml。完整示例com.facebook.drawee.view.SimpleDraweeView android:layout_width100dp android:layout_height100dp app:actualImageUrihttps://example.com/image.jpg fresco:roundedCornerRadius5dp fresco:roundBottomStartfalse fresco:roundBottomEndfalse fresco:roundWithOverlayColorcolor/blue fresco:roundingBorderWidth1dp fresco:roundingBorderColorcolor/red /注意 XML 命名空间前缀需与你工程声明一致示例中为fresco。全部圆角相关属性及含义如下属性类型说明roundAsCircleboolean是否裁剪为圆形开启后roundedCornerRadius被忽略roundedCornerRadiusdimension统一圆角半径被roundAsCircle忽略roundTopLeft/roundTopRight/roundBottomLeft/roundBottomRightboolean是否圆角对应角落默认 trueroundTopStart/roundTopEnd/roundBottomStart/roundBottomEndboolean逻辑边Start/End版本自动适配 RTL 布局roundWithOverlayColorcolor设置后即切换到OVERLAY_COLOR方式roundingBorderWidthdimension圆角边框宽度默认 0roundingBorderColorcolor/reference圆角边框颜色默认透明roundingBorderPaddingdimension圆角内边距仅BITMAP_ONLY生效默认 0这些属性的解析逻辑在 GenericDraweeHierarchyInflater.javaroundedCornerRadius用getDimensionPixelSize读取注意px 单位XML 中写 dp 会被框架自动换算roundWithOverlayColor、roundingBorderColor用getColor布尔开关逐个读取。四个角的最终半径由开关组合决定见 GenericDraweeHierarchyInflater.java。特别值得一提的是 RTL 支持解析器会检查当前资源配置的布局方向在 RTL 环境下将roundTopStart解释为右上角、roundBottomEnd解释为左下角等实现逻辑角与物理角的自动映射见 GenericDraweeHierarchyInflater.java。五、在代码中配置5.1 构建层级时指定在构造GenericDraweeHierarchy时将RoundingParams实例传给GenericDraweeHierarchyBuilderRoundingParams roundingParams RoundingParams.fromCornersRadius(7f); mSimpleDraweeView.setHierarchy(new GenericDraweeHierarchyBuilder(getResources()) .setRoundingParams(roundingParams) .build());setRoundingParams定义于 GenericDraweeHierarchyBuilder.java构建完成后该实例会被GenericDraweeHierarchy持有并在层级构建时应用。5.2 层级构建后动态修改层级构建完成后所有圆角参数仍然可以随时修改int color getResources().getColor(R.color.red); RoundingParams roundingParams RoundingParams.fromCornersRadius(5f); roundingParams.setBorder(color, 1.0f); roundingParams.setRoundAsCircle(true); mSimpleDraweeView.getHierarchy().setRoundingParams(roundingParams);RoundingParams是可变对象、支持链式调用除上述方法外还提供以下能力定义于 RoundingParams.javasetRoundingMethod(RoundingMethod)显式指定BITMAP_ONLY或OVERLAY_COLORsetBorder(ColorInt color, float width)/setBorderWidth/setBorderColor设置圆角边框宽度为 0 表示无边框边框颜色默认Color.TRANSPARENTsetPadding(float)圆角内边距仅BITMAP_ONLY生效宽度和边距均不可为负带参数校验setScaleDownInsideBorders(boolean)图片是否缩放到边框内部否则边框会画在图片之上setPaintFilterBitmap(boolean)为 Paint 设置FILTER_BITMAP_FLAG绘制位图时建议开启软件渲染或追求像素风时可关闭setRepeatEdgePixels(boolean)源图小于控件时是否重复边缘像素以填满整个圆角视口对纯色小图标填充大圆角场景很有用。完整的类说明可参考仓库内 JavadocRoundingParams.html。六、注意事项与权衡Caveats使用默认的BITMAP_ONLY模式时存在以下已知限制只有能解析为BitmapDrawable或ColorDrawable的图片才能圆角。NinePatchDrawable、ShapeDrawable等其他 Drawable 不支持圆角无论 XML 还是代码指定。需要说明的是从当前仓库源码看WrappingUtils.applyLeafRounding 已额外支持NinePatchDrawable包装为RoundedNinePatchDrawable说明这一限制在演进中有所放宽但使用前仍建议在目标机型验证。动画无法圆角GIF、WebP 动图在BITMAP_ONLY下不生效。AndroidBitmapShader的固有缺陷图片未完全覆盖控件时空白区域不会绘制为空而是重复边缘像素CLAMP 模式参见 RoundedBitmapDrawable.kt。两种规避方案换用能铺满整个控件的缩放类型如centerCrop在图片文件四周留1px 的透明边框让透明像素被重复填充——这是 PNG 资源图的最佳解法。若上述限制影响了你的图片可以考虑OVERLAY_COLOR模式它没有上述问题但本质是用纯色盖出圆角只有当视图下方背景是静态且同色时效果才理想。此外源码注释还提示该模式下叠加边框会裁剪图像边缘不透明色时不易察觉低透明度时非常明显。另外两个被否决/禁用的方案CLIPPING路径裁剪模式Drawee 内部保留了CLIPPING实现见 RoundedCornersDrawable.java 的枚举与case CLIPPING分支但该模式已被禁用且未对外暴露——部分Canvas实现不支持路径裁剪且裁剪不支持抗锯齿圆角边缘会严重像素化。临时位图方案用 Bitmap 预裁剪确实能绕开以上所有问题但会带来显著的内存开销因此 Fresco 明确不支持。结论正如官方文档所言Android 上并不存在真正完美的圆角方案开发者必须在上述方案与各自代价之间做取舍。七、Showcase 完整示例Fresco 的 showcase 示例应用提供了完整的圆角演示。原文档指向的DraweeRoundedCornersFragment在当前仓库中已演进为 Vito 架构下的 VitoRoundedCornersFragment.java它一次性演示了四种形态// 圆形 mImageRoundOptions mImageRoundOptions.extend().round(RoundingOptions.asCircle()).build(); // 四角统一 16dp 圆角 mImageRadiusOptions mImageRadiusOptions.extend().round(RoundingOptions.forCornerRadiusPx(radius)).build(); // 只有左上、右下圆角其余为直角 mImageSomeOptions mImageSomeOptions.extend().round(RoundingOptions.forCornerRadii(radius, 0, radius, 0)).build(); // 四角各自不同的花式圆角 动态边框 mImageFancyOptions mImageFancyOptions.extend().round(RoundingOptions.forCornerRadii(/* 4 个分别来自 dimens.xml 的半径 */)).build();该示例还支持通过 Spinner 实时切换 ScaleType、通过复选框开关圆角边框BorderOptions.create以及图片是否缩放进边框内scaleInside是理解圆角与缩放类型交互的最佳活教材——尤其能直观看到在center等非兼容缩放类型下BITMAP_ONLY的边缘重复问题。结语Fresco Drawee 的圆角体系是一套零拷贝、可配置、可热更新的绘制层方案用BITMAP_ONLY默认享受位图着色器的高效裁剪用OVERLAY_COLOR绕开位图限制、换取纯色背景下的简易圆角必要时用roundingBorder*系列参数叠加边框与内边距。理解RoundingParams的全部 API 与WrappingUtils的分发机制后无论是 XML 静态布局还是代码动态切换都能在控制内存开销的前提下稳定输出美观的圆角与圆形图片。【免费下载链接】frescoAn Android library for managing images and the memory they use.项目地址: https://gitcode.com/gh_mirrors/fr/fresco创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价