使用Glide加载远程SVG丢失背景颜色的修复方案咨询
Glide加载SVG丢失背景颜色的问题
问题描述
使用Glide加载远程SVG资源时,SVG背景颜色丢失,但在Chrome浏览器显示正常。
正常显示效果:
Glide加载后的异常效果:
(注:为让白色文字可见,自行设置了黑色背景)
相关代码及SVG地址:
Glide.with(this) .`as`(PictureDrawable::class.java) .listener(SvgSoftwareLayerSetter()) .load("https://api.edns.domains/metadata/0x53a0018f919bde9C254bda697966C5f448ffDDcB/30610703517456202125772346661883251373457451536551224931705160096554106665587/image.svg") .into(binding.iv1)
public class SvgDecoder implements ResourceDecoder<InputStream, SVG> { @Override public boolean handles(@NonNull InputStream source, @NonNull Options options) { return true; } public Resource<SVG> decode( @NonNull InputStream source, int width, int height, @NonNull Options options) throws IOException { try { SVG svg = SVG.getFromInputStream(source); return new SimpleResource<>(svg); } catch (SVGParseException ex) { throw new IOException("Cannot load SVG from stream", ex); } } }
public class SvgDrawableTranscoder implements ResourceTranscoder<SVG, PictureDrawable> { @Nullable @Override public Resource<PictureDrawable> transcode(@NonNull Resource<SVG> toTranscode, @NonNull Options options) { SVG svg = toTranscode.get(); Picture picture = svg.renderToPicture(); PictureDrawable drawable = new PictureDrawable(picture); return new SimpleResource<>(drawable); } }
@GlideModule public class SvgModule extends AppGlideModule { @Override public void registerComponents( @NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) { registry .register(SVG.class, PictureDrawable.class, new SvgDrawableTranscoder()) .append(InputStream.class, SVG.class, new SvgDecoder()); } @Override public boolean isManifestParsingEnabled() { return false; } }
public class SvgSoftwareLayerSetter implements RequestListener<PictureDrawable> { @Override public boolean onLoadFailed(GlideException e, Object model, Target<PictureDrawable> target, boolean isFirstResource) { ImageView view = ((ImageViewTarget<?>) target).getView(); view.setLayerType(ImageView.LAYER_TYPE_NONE, null); return false; } @Override public boolean onResourceReady(PictureDrawable resource, Object model, Target<PictureDrawable> target, DataSource dataSource, boolean isFirstResource) { ImageView view = ((ImageViewTarget<?>) target).getView(); view.setLayerType(ImageView.LAYER_TYPE_SOFTWARE, null); return false; } }
解决方案
原因分析
当前的SvgDrawableTranscoder仅渲染了SVG的矢量图形,但Android的PictureDrawable不会自动解析并应用SVG的背景色属性,导致背景丢失。
修复方案1:修改Transcoder添加背景色处理
修改SvgDrawableTranscoder,提取SVG根节点的背景色并设置到PictureDrawable上:
public class SvgDrawableTranscoder implements ResourceTranscoder<SVG, PictureDrawable> { @Nullable @Override public Resource<PictureDrawable> transcode(@NonNull Resource<SVG> toTranscode, @NonNull Options options) { SVG svg = toTranscode.get(); Picture picture = svg.renderToPicture(); PictureDrawable drawable = new PictureDrawable(picture); // 提取SVG根节点的背景色 Element root = svg.getDocument().getDocumentElement(); String styleAttr = root.getAttribute("style"); if (styleAttr != null && styleAttr.contains("background-color")) { // 解析颜色值 String colorValue = styleAttr.split(":")[1].replace(";", "").trim(); try { int color = Color.parseColor(colorValue); drawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_OVER)); } catch (IllegalArgumentException ignored) {} } return new SimpleResource<>(drawable); } }
修复方案2:解析SVG时插入背景层
如果背景色定义在SVG内部元素而非根节点,可在SvgDecoder中手动添加背景矩形:
public class SvgDecoder implements ResourceDecoder<InputStream, SVG> { @Override public boolean handles(@NonNull InputStream source, @NonNull Options options) { return true; } public Resource<SVG> decode( @NonNull InputStream source, int width, int height, @NonNull Options options) throws IOException { try { SVG svg = SVG.getFromInputStream(source); Document doc = svg.getDocument(); Element svgRoot = doc.getDocumentElement(); // 获取SVG视口尺寸 float viewWidth = svg.getDocumentViewBox().getWidth(); float viewHeight = svg.getDocumentViewBox().getHeight(); // 创建白色背景矩形(可替换为SVG实际背景色) Element bgRect = doc.createElementNS("http://www.w3.org/2000/svg", "rect"); bgRect.setAttribute("x", "0"); bgRect.setAttribute("y", "0"); bgRect.setAttribute("width", String.valueOf(viewWidth)); bgRect.setAttribute("height", String.valueOf(viewHeight)); bgRect.setAttribute("fill", "#ffffff"); // 插入到SVG最底层 svgRoot.insertBefore(bgRect, svgRoot.getFirstChild()); return new SimpleResource<>(svg); } catch (SVGParseException ex) { throw new IOException("Cannot load SVG from stream", ex); } } }
修复方案3:使用Glide官方SVG扩展库
最简便的方式是使用Glide官方维护的SVG扩展,它已处理所有兼容性问题:
- 添加依赖到
build.gradle:
implementation 'com.github.bumptech.glide:svg:4.16.0'
- 删除自定义的
SvgDecoder、SvgDrawableTranscoder、SvgModule和SvgSoftwareLayerSetter,直接简化加载代码:
Glide.with(this) .load("https://api.edns.domains/metadata/0x53a0018f919bde9C254bda697966C5f448ffDDcB/30610703517456202125772346661883251373457451536551224931705160096554106665587/image.svg") .into(binding.iv1)
这样就能正常显示SVG的背景色了。
内容的提问来源于stack exchange,提问作者dwh
相关产品推荐
相关产品推荐

