dnfield / flutter_svg

SVG parsing, rendering, and widget library for Flutter
MIT License
1.66k stars 455 forks source link

SVG disappear #809

Closed kirill-21 closed 1 year ago

kirill-21 commented 1 year ago

https://github.com/dnfield/flutter_svg/issues/760

In this issue SVGs disappear on IOS, i have the same problem on Windows. No errors are printed to FlutterError.onError callback. I have no idea how to repeat it, they just disappear after some time.

Sometimes it happens after changing theme brightness, sometimes after minimizing->maximizing the app, sometimes after using setState. I just leave app launched in background while doing something else and when i return and do something inside the app svgs fade away. (This happens both in Debug and Release mode)

Issue appeared somewhere in latest updates of package/flutter version.

kirill-21 commented 1 year ago

ExLoader_JlJdlfcdvP

By the way they do not fade away completely and are shown back when you rebuild whole widget tree(not just the widget where icon is used), but only for a second.

image

And if you try to render this same icon(that disappeared) somewhere else in the app without restarting it - almost all icons that are rendered in the same widget with this icon instantly fade away

kirill-21 commented 1 year ago

After some research i started using such blank where i provide both color and SvgTheme with currentColor. image

SVGs still disappear, but this helps with restoring icons back by switching app's theme/rebuilding the widget with setState. My suggestion is that SvgPicture widget loses color properties at some time and start's using default SvgTheme's color which is set to transparent even though custom theme is provided. Have no idea why this happens.

I also tried rolling back package version one by one down to 1.1.1 and it seems that issue appeared somewhere between 1.1.1 and 1.1.2.

Dohmanlechx commented 1 year ago

I have the same problem, but it's super intermittent. Not found a way to reproduce.

Dohmanlechx commented 1 year ago

So you stopped having this problem by 1.1.1?

kirill-21 commented 1 year ago

So you stopped having this problem by 1.1.1?

Yes

tusharch12 commented 1 year ago

i also have same problem

wizardlyc commented 1 year ago

Having same problem on both Android and iOS. I tried version 1.1.1+1, 1.1.0, doesn't work. It seems comes with flutter version 3.3. before upgrading to flutter 3.3, I never met this problem.

Dohmanlechx commented 1 year ago

So you stopped having this problem by 1.1.1?

Yes

Update: Not for us. Still a problem.

kirill-21 commented 1 year ago

So you stopped having this problem by 1.1.1?

Yes

Update: Not for us. Still a problem.

Then maybe it's a flutter issue and we need more data to provide it to flutter's team.

@wizardlyc, @tusharch12 , @Dohmanlechx, can you share more info about when and how you recreate this issue?

Dohmanlechx commented 1 year ago

@wizardlyc, @tusharch12 , @Dohmanlechx, can you share more info about when and how you recreate this issue?

Once I find a reproducible scenario, I promise to write it here.

kirill-21 commented 1 year ago

@wizardlyc, @tusharch12 , @Dohmanlechx, can you share more info about when and how you recreate this issue?

Once I find a reproducible scenario, I promise to write it here.

I believe it might take a while, maybe comparing of our actions (what we did right before this issue occured) might help

Dohmanlechx commented 1 year ago

I believe it might take a while, maybe comparing of our actions (what we did right before this issue occured) might help

When it happened today, I had the simulator running the app for a while, and I came back after some minutes. I didn't put it into the background or so. I believe some kind of setState caused that.

kirill-21 commented 1 year ago

@dnfield might it be related to the svg package or maybe you have any ideas where is the core of this problem?

dnfield commented 1 year ago

I need a reproduction. There's also about to be a new major release of this package

eli1stark commented 1 year ago

Are you sure it disappears? Because for me it becomes the square with the color of SVG, don't know how to reproduce either

Dohmanlechx commented 1 year ago

Are you sure it disappears? Because for me it becomes the square with the color of SVG, don't know how to reproduce either

Actually, I had problem with disappearing SVGs until I downgraded to 1.1.1, and then I got white squared SVGs.

kirill-21 commented 1 year ago

Are you sure it disappears? Because for me it becomes the square with the color of SVG, don't know how to reproduce either

I do had the same with old package versions

kirill-21 commented 1 year ago

I need a reproduction. There's also about to be a new major release of this package

Try launching the app in background for 10 minutes, then return and hover your SVG widget to call setstate(wrap the widget with mouseregion onEnter callback before the test start), seems that issue happens after this actions

isAlmogK commented 1 year ago

I have the same issue on the latest version

kirill-21 commented 1 year ago

Are you sure it disappears? Because for me it becomes the square with the color of SVG, don't know how to reproduce either

image Having these even on the latesst version

kirill-21 commented 1 year ago

And new flutter 3.3.10 has this issue :c image

eli1stark commented 1 year ago

I don't know how to reproduce it but I know how to fix it in the runtime. If you swipe down notification bar (in the top left corner) of your iPhone several times, SVG will comeback to normal.

kirill-21 commented 1 year ago

I don't know how to reproduce it but I know how to fix it in the runtime. If you swipe down notification bar (in the top left corner) of your iPhone several times, SVG will comeback to normal.

Theme brightness switch also works

justincbeck commented 1 year ago

FWIW, I am also having this issue and cannot reliably reproduce it. I am on Flutter 3.3 using Flutter SVG 1.1.6.

isAlmogK commented 1 year ago

Following, I have this issue, but I'm loading it locally only happing on iOS

my code

Center(
                      child: SvgPicture.asset(
                        'assets/svg/team/${team.icon}.svg',
                        color: CustomColors.primary,
                      ),
                    ),

Lastest package version

Error

══╡ EXCEPTION CAUGHT BY SVG ╞═══════════════════════════════════════════════════════════════════════
The following assertion was thrown resolving a single-frame picture stream:
Unable to load asset: assets/svg/team/general-team.svg

When the exception was thrown, this was the stack:
#0      PlatformAssetBundle.load (package:flutter/src/services/asset_bundle.dart:258:7)
<asynchronous suspension>
#1      AssetBundle.loadString (package:flutter/src/services/asset_bundle.dart:83:27)
<asynchronous suspension>
#2      AssetBundlePictureProvider._loadAsync (package:flutter_svg/src/picture_provider.dart:546:25)
<asynchronous suspension>

Picture provider: ExactAssetPicture(name: "assets/svg/team/general-team.svg", bundle: null,
  colorFilter: null)
Picture key: AssetBundlePictureKey(bundle: PlatformAssetBundle#a27c5(), name:
  "assets/svg/team/general-team.svg", colorFilter: null, theme: SvgTheme(currentColor:
  Color(0xff000000), fontSize: 14.0, xHeight: 7.0))
════════════════════════════════════════════════════════════════════════════════════════════════════

Another exception was thrown: Unable to load asset: assets/svg/team/dog-ball.svg

Another exception was thrown: Unable to load asset: assets/svg/team/rescue-dog.svg
eli1stark commented 1 year ago

@isAlmogK this is unrelated issue, in our case there is no error thrown. In your case there are 3 errors thrown, the last two are likely just the wrong provided path to the asset. The first one can be malformed SVG or something, run it through online SVG checker. The first one can be related to the wrong path as well.

isAlmogK commented 1 year ago

@eli1stark thanks you are correct had an issue in pub file

domesticmouse commented 1 year ago

I've attempted to build a reproduction sample, and I'm not seeing the disappearing behaviour. Here's my understanding of the original code, but pulled out as a stand alone reproduction case. The SVG in question is the Ghostscript Tiger.

import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';

const String assetName = 'assets/Ghostscript_Tiger.svg';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: Scaffold(
        body: Center(
          child: SizedBox(
            width: 512,
            height: 512,
            child: SvgPicture.asset(
              assetName,
              semanticsLabel: 'Ghostscript Tiger',
              color: Colors.amber,
            ),
          ),
        ),
      ),
    );
  }
}

Please modify this minimal repro until the disappearing SVG is reproduced.

kirill-21 commented 1 year ago

@domesticmouse, @dnfield

The code in the the video is from another project, it's just a replay of the moment when issue was recreated in a test project, recorded with amd alternative of ShadowPlay.

https://user-images.githubusercontent.com/63228361/212660476-17eaef07-2e11-4d53-bbe6-b37b9296638b.mp4

code ```dart import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_weather_bg_null_safety/flutter_weather_bg.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); runApp(const MyApp()); /// Helps to save event background position; final GlobalKey eventBackgroundKey = GlobalKey(); OverlayEntry? weatherBgOverlay; // Animated event background for event themes final Widget weatherBg = Positioned.fill( key: eventBackgroundKey, child: IgnorePointer( child: Opacity( opacity: 0.1, child: WeatherBg( weatherType: WeatherType.heavySnow, width: 1280.0, height: 720.0, ), ), ), ); weatherBgOverlay = OverlayEntry(builder: (_) => weatherBg); WidgetsBinding.instance.addPostFrameCallback((_) { Overlay.of(appContext)?.insert(weatherBgOverlay!); }); } late BuildContext appContext; class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( title: 'Material App', home: AppScaffold(), ); } } class AppScaffold extends StatelessWidget { const AppScaffold({super.key}); @override Widget build(BuildContext context) { appContext = context; return Scaffold( backgroundColor: Colors.black12, appBar: AppBar( title: const Text('Material App Bar'), ), body: Center( child: Column( children: [ for (int i = 0; i < 5; i++) Padding( padding: const EdgeInsets.only(top: 10.0), child: CustomButton(isImage: i.isOdd), ), ], ), ), ); } } class CustomButton extends StatefulWidget { const CustomButton({super.key, required this.isImage}); final bool isImage; @override State createState() => _CustomButtonState(); } class _CustomButtonState extends State { @override Widget build(BuildContext context) { return ExLButton( buttonColor: Colors.white.withOpacity(0.0), hoverOpacityValue: 0.08, callback: () { /* Do nothing */ }, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ if (!widget.isImage) SvgPicture.string( """ """, color: Theme.of(context).backgroundColor, width: 24.0, height: 24.0, ), if (widget.isImage) Image.network( 'https://i.pinimg.com/736x/d1/ea/b2/d1eab219ecd4bb7f077d30ff44b6fb4b.jpg', width: 24.0, height: 24.0, color: Theme.of(context).backgroundColor, ), Text( 'svg test', style: TextStyle( color: Theme.of(context).backgroundColor, fontSize: 16.0, ), ), ], ), ); } } class ExLButton extends StatefulWidget { final Function? callback; final Function? secondCallback; final String? buttonLabel; final IconData? icon; final IconData? secondIcon; final double? iconSize; final double? labelSize; final double? labelHeight; final double? overrideHeight; final String? iconPath; final String? secondIconPath; final Color? buttonColor; final Color? secondButtonColor; final Color? labelColor; final Widget? child; final Widget? secondChild; final EdgeInsets? insets; final EdgeInsets? tapInsets; final List? shadow; final double? borderRadius; final bool overrideColorIfDisabled; final String? tooltip; final double tooltipOffsetWithoutScale; final String? secondTooltip; final bool useSecondStateByDefault; final double? hoverOpacityValue; final Duration? switchDuration; final Size? extendedIconSize; final BorderRadius? customBorderRadius; final Function? onMouseHover; final Function? onMouseExit; final bool passTapUpDetails; final double? tooltipFontSize; final double? rotationAngle; final bool showTooltipBelow; final Color? tooltipBackgroundColor; final Color? secondTooltipBackgroundColor; final Color? tooltipTextColor; final Color? secondTooltipTextColor; final bool renderTooltipBelowStack; final MouseCursor? cursorOverride; final bool skipTooltipRedrawOnTap; const ExLButton({ super.key, this.callback, this.secondCallback, this.buttonLabel, this.icon, this.secondIcon, this.iconSize, this.labelSize, this.overrideHeight, this.iconPath, this.secondIconPath, this.buttonColor, this.secondButtonColor, this.labelColor, this.child, this.secondChild, this.insets, this.tapInsets, this.shadow, this.borderRadius, this.overrideColorIfDisabled = false, this.tooltip, this.secondTooltip, this.useSecondStateByDefault = false, this.tooltipOffsetWithoutScale = 28.0, this.hoverOpacityValue, this.switchDuration, this.extendedIconSize, this.customBorderRadius, this.onMouseHover, this.onMouseExit, this.passTapUpDetails = false, this.tooltipFontSize, this.rotationAngle, this.labelHeight, this.showTooltipBelow = true, this.tooltipBackgroundColor, this.secondTooltipBackgroundColor, this.tooltipTextColor, this.secondTooltipTextColor, this.renderTooltipBelowStack = false, this.cursorOverride, this.skipTooltipRedrawOnTap = false, }); @override State createState() => _ExLButtonState(); } class _ExLButtonState extends State { @override void initState() { WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted && widget.useSecondStateByDefault && widget.secondButtonColor != null) { _updateColor(isHovered: false); } }); super.initState(); } late Color _realColor; bool _toInitial = false; late bool _useSecondIcon = widget.useSecondStateByDefault; late double currentOpacity = initialOpacity; late final double initialOpacity = (widget.callback == null && !widget.overrideColorIfDisabled ? Theme.of(context).disabledColor : widget.buttonColor ?? (widget.icon != null || widget.iconPath != null ? Theme.of(context).iconTheme.color! : Theme.of(context).primaryColor)) .opacity; String get _tooltipText => _useSecondIcon && widget.secondTooltip != null ? widget.secondTooltip ?? '' : !_useSecondIcon && widget.tooltip != null ? widget.tooltip ?? '' : ''; Future _updateColor({ bool isHovered = true, Duration delay = Duration.zero, bool executeCallback = false, bool toDefaultState = false, final TapUpDetails? details, }) async { _toInitial = toDefaultState; if (widget.callback != null) { await Future.delayed( _toInitial ? const Duration(milliseconds: 25) : delay, ); if (mounted) { setState(() { if (isHovered) { currentOpacity = widget.hoverOpacityValue ?? 0.85; } else { currentOpacity = initialOpacity; } if (executeCallback) { if (_useSecondIcon && widget.secondCallback != null) { if (widget.passTapUpDetails) { widget.secondCallback?.call(details); } else { widget.secondCallback?.call(); } } else { if (widget.passTapUpDetails) { widget.callback?.call(details); } else { widget.callback?.call(); } } } }); if ((widget.secondChild != null || widget.secondIcon != null || widget.secondIconPath != null) && executeCallback) { _useSecondIcon = !_useSecondIcon; } if (_toInitial) await Future.delayed(const Duration(milliseconds: 99)); if (mounted && _toInitial) { setState(() { currentOpacity = initialOpacity; }); } } } } @override Widget build(BuildContext context) { _realColor = (widget.callback == null && !widget.overrideColorIfDisabled ? Theme.of(context).disabledColor : _useSecondIcon && widget.secondButtonColor != null ? widget.secondButtonColor! : widget.buttonColor ?? (widget.icon != null || widget.iconPath != null ? Theme.of(context).iconTheme.color! : Theme.of(context).primaryColor)) .withOpacity(currentOpacity); return GestureDetector( onTapDown: (_) => _updateColor(isHovered: false), onTapUp: (TapUpDetails details) => _updateColor( delay: const Duration(milliseconds: 125), executeCallback: true, details: details, ), child: MouseRegion( onEnter: (_) { widget.onMouseHover?.call(); _updateColor(); }, onExit: (_) { widget.onMouseExit?.call(); _updateColor(isHovered: false, toDefaultState: true); }, cursor: widget.cursorOverride ?? (widget.callback == null ? SystemMouseCursors.forbidden : SystemMouseCursors.click), child: AnimatedSwitcher( duration: widget.switchDuration ?? const Duration( milliseconds: 250, ), switchOutCurve: Curves.easeOutCubic, switchInCurve: Curves.easeOutCubic, child: Tooltip( message: _tooltipText, key: ValueKey(_useSecondIcon), child: AnimatedContainer( height: widget.overrideHeight, padding: widget.insets ?? const EdgeInsets.only( top: 6.0, bottom: 8.0, left: 16.0, right: 16.0, ), duration: const Duration(milliseconds: 125), curve: Curves.easeInOutCubic, decoration: BoxDecoration( color: _realColor, borderRadius: widget.customBorderRadius ?? BorderRadius.all( Radius.circular(widget.borderRadius ?? 6.0), ), boxShadow: widget.shadow, ), child: _useSecondIcon ? widget.secondChild : widget.child ?? Center( child: Text( widget.buttonLabel ?? '', overflow: TextOverflow.visible, style: TextStyle( color: widget.labelColor ?? Colors.white, fontSize: widget.labelSize ?? 14.0, ), textAlign: TextAlign.center, ), ), ), ), ), ), ); } } ```

Steps to reproduce:

  1. Import these dependencies
    flutter_weather_bg_null_safety: ^1.0.0
    flutter_svg: ^1.1.6
  2. Paste all code to main.dart and run app
  3. Go to the browser, do whatever you did before, forget about the app for 10 minutes, then come back and hover the button. The svg should disappear/become a filled cube/convert to a strange shape.

flutter_weather_bg_null_safety pacakge is used for constant rendering of elements (with this the issue replecates faster)

I've also added an image to this test to ensure that it's just svg error.

bstolinski commented 1 year ago

I also have this problem, iOS simulator, flutter 3.3.10, flutter_svg: 1.1.6. I have no idea how to reproduce it, it seems very random.

https://user-images.githubusercontent.com/53336850/212675569-eb82e975-6245-45b4-84a5-e7fecb9f9c83.mov

image
Dohmanlechx commented 1 year ago

Not a repro scenario, but I locked the computer (Macbook) and went for lunch. Came back 1 hour later, unlocked the computer and the SVG icons had disappeared in the app that was running on a simulator. Tried locking the computer again and unlocked it immediately but the icons were still there. Hope this helps in some way.

dnfield commented 1 year ago

@kirill-21 - your issue looks different, it doesn't look like the SVGs are disappearing but changing...?

Can anyone who has this try to use the latest code on the master branch in this repo? There are significant changes that may have obsoleted this bug.

kirill-21 commented 1 year ago

It's the same issue, this bug is just random and sometimes they disappear, sometimes become a cube, sometimes change to a strange shape

eli1stark commented 1 year ago

@dnfield I'll try, are those changes production ready?

bstolinski commented 1 year ago

@dnfield I have not been able to repro it from the master branch, but I would wait for someone else to confirm because I don't have a 100% repro path (it just happens sometimes)

TomBeckett commented 1 year ago

@dnfield Do you know when there maybe a production build for v2?

dnfield commented 1 year ago

I will publish something soon. I was working on validating it in Google's monorepo before I had to take some time away - I have validated it (although it will be difficult to roll into Google because of a large number of small golden changes).

dnfield commented 1 year ago

Ah, I still am going to keep it as a dev version because the new version requires features currently only available in the Flutter beta. Once the new Flutter stable is released I'll publish a non-dev version.

dnfield commented 1 year ago

Is this still happening on latest stable/preview version of flutter_svg?

eli1stark commented 1 year ago

@dnfield I haven't encountered it since adopting the version with vector graphics.

kirill-21 commented 1 year ago

Is this still happening on latest stable/preview version of flutter_svg?

Why new version loads icons very slow? 4-5 seconds after widget is rendered on the screen swiftsoft_UJWYY5P1Aw

dnfield commented 1 year ago

@kirill-21 what platform is that on?

dnfield commented 1 year ago

And are those network or asset SVGs?

kirill-21 commented 1 year ago

@kirill-21 what platform is that on?

Windows, the 3.7.0 flutter update. These are asset and memory svgs

dnfield commented 1 year ago

Can you share a timeline recording?

kirill-21 commented 1 year ago

Can you share a timeline recording?

How do i do that?

https://user-images.githubusercontent.com/63228361/214948936-7a9663ed-cc7d-4328-9c05-be98520b308a.mp4

dnfield commented 1 year ago

https://docs.flutter.dev/development/tools/devtools/performance#timeline-events-chart - from there you should also be able to export the file in JSON format so we can view it.

Or, you can do it from the observatory on the timeline page if you're more familiar with the observatory than devtools.

jonahwilliams commented 1 year ago

please attach that as a zipped file so we don't ahve to try to copy that. Also, a timeline capture on the old version of flutter_svg would be idea so we can compare / contrast

kirill-21 commented 1 year ago

please attach that as a zipped file so we don't ahve to try to copy that. Also, a timeline capture on the old version of flutter_svg would be idea so we can compare / contrast

dart_devtools_2023-01-27_00_06_22.116.zip

P.S. Updated to the clear timeline from first app launch to the same position as on the video

kirill-21 commented 1 year ago

And here is a timeline from stable package version dart_devtools_2023-01-27_00_11_48.361.zip