1

So my app needs SVGs now or I want to switch png to svg so it can scale well with difference screen sizes. I know I can draw svg using <Path> but <Path> doesn't have data triggers but they do have GestureRecognizers which is useful but without data triggers idk how else to achieve what I want.

This is my current xaml for a button to data trigger and switch its content depending on playing state of a MediaElement. I would like to switch the Text to a SVG of play pause images.

<Button x:Name="OnPlayPauseButtonClicked"
                    Grid.Row="1"
                    Text="&#x25B6;&#xFE0F; Play"
                    VerticalOptions="End"
                    Clicked="OnPlayPauseButton_Clicked">
                <Button.Triggers>
                    <DataTrigger TargetType="Button"
                                 Binding="{Binding CurrentState}"
                                 Value="{x:Static xct:MediaElementState.Playing}">
                        <Setter Property="Text"
                                Value="&#x23F8; Pause"/>
                    </DataTrigger>
                    <DataTrigger TargetType="Button"
                                 Binding="{Binding CurrentState}"
                                 Value="{x:Static xct:MediaElementState.Buffering}">
                        <Setter Property="IsEnabled"
                                Value="False"/>
                    </DataTrigger>
                </Button.Triggers>
            </Button>

I have tried putting my play and pause svg files into drawable folder and apply the Value to property of ImageSource. That didn't work. I then tried converting the SVG to XML and use the instead and it didn't work.

Is there a way to do this without using any dependencies?

Thanks in advance.

2 Answers2

1

You have a few options here:

1. Font Icons

There is a much better way to accomplish what you are trying to do using Font Icons, e.g. Material Design Icons. Here is a cheat sheet for the icons.

This is not strictly a dependency, if you add the fonts as a resource (which you need to do in either case using PNGs, SVGs or - in this case - an image font).

<Button x:Name="OnPlayPauseButtonClicked" Grid.Row="1" Text="&#xF040A;" VerticalOptions="End" Clicked="OnPlayPauseButton_Clicked"
        FontFamily="materialdesignicons">
    <Button.Triggers>
        <DataTrigger TargetType="Button"
                     Binding="{Binding CurrentState}"
                     Value="{x:Static xct:MediaElementState.Playing}">
            <!-- Pause Button Icon -->
            <Setter Property="Text" Value="&#xF03E4;"/>
        </DataTrigger>
                <DataTrigger TargetType="Button"
                     Binding="{Binding CurrentState}"
                     Value="{x:Static xct:MediaElementState.Paused}">
            <!-- Play Button Icon -->
            <Setter Property="Text" Value="&#xF040A;"/>
        </DataTrigger>
        <DataTrigger TargetType="Button"
                     Binding="{Binding CurrentState}"
                     Value="{x:Static xct:MediaElementState.Buffering}">
            <Setter Property="IsEnabled" Value="False"/>
        </DataTrigger>
    </Button.Triggers>
</Button>

James Montemagno also has a great blog post on this: https://montemagno.com/using-font-icons-in-xamarin-forms-goodbye-images-hello-fonts/

2. ImageButton

You can add your images to your project's resources and load them into an ImageButton. How to use ImageButtons refer to this link: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/imagebutton.

SVGs

There is a library that allows you to load SVGs, this will require the following nuget to be installed: https://github.com/luberda-molinet/FFImageLoading/

<ImageButton x:Name="OnPlayPauseButtonClicked" Grid.Row="1" VerticalOptions="End" Clicked="OnPlayPauseButton_Clicked">
    <ImageButton.Triggers>
        <DataTrigger TargetType="ImageButton"
                     Binding="{Binding CurrentState}"
                     Value="{x:Static xct:MediaElementState.Playing}">
            <!-- Pause Button Icon -->
            <Setter Property="Source">
               <Setter.Value>
                   <ffimageloadingsvg:SvgCachedImage Source="resource://YourAppName.Resources.Pause.svg"/>
               </Setter.Value>
            </Setter>
        </DataTrigger>
                <DataTrigger TargetType="ImageButton"
                     Binding="{Binding CurrentState}"
                     Value="{x:Static xct:MediaElementState.Paused}">
            <!-- Play Button Icon -->
            <Setter Property="Source">
               <Setter.Value>
                   <ffimageloadingsvg:SvgCachedImage Source="resource://YourAppName.Resources.Play.svg"/>
               </Setter.Value>
            </Setter>
        </DataTrigger>
        <DataTrigger TargetType="ImageButton"
                     Binding="{Binding CurrentState}"
                     Value="{x:Static xct:MediaElementState.Buffering}">
            <Setter Property="IsEnabled" Value="False"/>
        </DataTrigger>
    </ImageButton.Triggers>
</ImageButton>

PNGs

To see how to add images to your app, refer to this page: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/images?tabs=windows#embedded-images

<ImageButton x:Name="OnPlayPauseButtonClicked" Grid.Row="1" VerticalOptions="End" Clicked="OnPlayPauseButton_Clicked">
    <ImageButton.Triggers>
        <DataTrigger TargetType="ImageButton"
                     Binding="{Binding CurrentState}"
                     Value="{x:Static xct:MediaElementState.Playing}">
            <!-- Pause Button Icon -->
            <Setter Property="Source" Value="{local:ImageResource Pause.PNG}" />
        </DataTrigger>
                <DataTrigger TargetType="ImageButton"
                     Binding="{Binding CurrentState}"
                     Value="{x:Static xct:MediaElementState.Paused}">
            <!-- Play Button Icon -->
            <Setter Property="Source" Value="{local:ImageResource Play.PNG}" />
        </DataTrigger>
        <DataTrigger TargetType="ImageButton"
                     Binding="{Binding CurrentState}"
                     Value="{x:Static xct:MediaElementState.Buffering}">
            <Setter Property="IsEnabled" Value="False"/>
        </DataTrigger>
    </ImageButton.Triggers>
</ImageButton>

[Update] 3: Use SvgCachedImage directly

You can also use SvgCachedImage directly instead of a Button and attach a TapGestureRecognizer to it:

<ffimageloadingsvg:SvgCachedImage x:Name="OnPlayPauseButtonClicked" Grid.Row="1" VerticalOptions="End">
    <ffimageloadingsvg:SvgCachedImage.Triggers>
        <DataTrigger TargetType="ffimageloadingsvg:SvgCachedImage"
                     Binding="{Binding CurrentState}"
                     Value="{x:Static xct:MediaElementState.Playing}">
            <!-- Pause Button Icon -->
            <Setter Property="Source"
                    Value="resource://YourAppName.Resources.Pause.svg"/>
        </DataTrigger>
        <DataTrigger TargetType="ffimageloadingsvg:SvgCachedImage"
                     Binding="{Binding CurrentState}"
                     Value="{x:Static xct:MediaElementState.Paused}">
            <!-- Play Button Icon -->
            <Setter Property="Source"
                    Value="resource://YourAppName.Resources.Play.svg"/>
        </DataTrigger>
        <DataTrigger TargetType="ffimageloadingsvg:SvgCachedImage"
                     Binding="{Binding CurrentState}"
                     Value="{x:Static xct:MediaElementState.Buffering}">
            <Setter Property="IsEnabled" Value="False"/>
        </DataTrigger>
    </ffimageloadingsvg:SvgCachedImage.Triggers>
    <ffimageloadingsvg:SvgCachedImage.GestureRecognizers>
        <TapGestureRecognizer Tapped="OnPlayPauseButton_Clicked"/>
    </ffimageloadingsvg:SvgCachedImage.GestureRecognizers>
</ffimageloadingsvg:SvgCachedImage>
Julian
  • 5,290
  • 1
  • 17
  • 40
  • Can this solution use a custom Icon? As this game is for my company and it targets younger children to play it and I require to add things like stars, hearts. Also need to add things like outlines to the stars and hearts and make things sorta 3D. This is why I want to use SVG as we already have the assets sorta created. Is it also possible to create such Icons with colors, blurs, 3D illusions, and outlines in 1? – ThisQRequiresASpecialist Oct 11 '22 at 13:20
  • Ah no, I didn't know that you wanted highly customized images. I will provide an answer for that later when I have time for it. – Julian Oct 11 '22 at 14:01
  • I have added alternative solutions for SVGs and PNGs now. I hope this helps – Julian Oct 11 '22 at 14:41
  • @ThisQRequiresASpecialist let me know if any of the alternative solutions are viable for you – Julian Oct 11 '22 at 17:56
  • Unfortunately, I had to remove this as an answer **for now,** as it doesn't work after trying to get it to work for a couple of hours now. I got the SVG to load inside a new content page but it doesn't want to show up on `ImageButton` or `Button` -> `ImageSource` but my drawable folder images work fine but the SVG doesn't show up... – ThisQRequiresASpecialist Oct 12 '22 at 09:07
  • @ThisQRequiresASpecialist The problem might be the ImageButton itself. I thought it would work with the SvgCachedImage, because that works with other ContentViews as well. However, you could also create your own Button class or simply use the SvgCachedImage and attach a `TapGestureRecognizer` to it instead. I've updated the answer accordingly. – Julian Oct 12 '22 at 09:49
  • Yeah, I was thinking to do that but I was really trying to find an actual solution with `DataTriggers` but I don't think it exists. As you've pointed out it could be something with `ImageButton` and `Button` -> `ImageSource`. It's unfortunate it's like this but I'm very positive that `TapGestures` will do the job but just more code behind and having to change `IsVisible` depending on the current state of the player. – ThisQRequiresASpecialist Oct 12 '22 at 10:02
  • TapGestures do not require more code behind. My updated answer provides all the needed changes, you can even reuse your event handler. – Julian Oct 12 '22 at 10:04
  • I think `DataTriggers` are broken on `FFImageLoadingSVG` which doesn't work either. After trying for some time again nothing wants to show up on the screen. When I do ``. Works fine and shows up... So I do not have a clue anymore on whats going on here. – ThisQRequiresASpecialist Oct 12 '22 at 11:05
  • You could also wrap everything inside a Frame and put a ContentView inside which then holds the SvgCachedImage. Then you add the TapGestureRecognizer to the Frame and exchange the ContentView's content based on the Media Player state. – Julian Oct 12 '22 at 12:16
0

You can use SkiaSharp to draw patterns, create custom controls to load it. For drawing patterns, refer to this document. The answer to this issue can also help you.

Zack
  • 1,255
  • 1
  • 2
  • 5