swiftanimationswiftuisf-symbols

SF Symbol replace animation size is off


I want to achieve this animation where the wifi symbol is slashed:

sf-symbol animation

It's partly working, but the wifi bars are scaling and moving

buggy animation

I'm using this code:

Image(systemName: showSlash ? "wifi.slash" : "wifi")
    .font(.system(size: 22))
    .frame(width: 24, height: 24)
    .foregroundStyle(.black)
    .symbolRenderingMode(.hierarchical)
    .contentTransition(.symbolEffect(.replace))

It seems the wifi bars in the "wifi.slash" icon are smaller, but in the SF symbols app they appear the same size. What am I doing wrong?


Solution

  • The reason for the jumping is because the symbols have different dimensions:

    This is how the two symbols look when shown adjacent to each other with a red border around each, using (vertical) center alignment:

    Screenshot

    Although the base part of the symbol is not center-aligned in the version with the slash, it seems the two versions do align on the text baseline. So if you show the symbol in a ZStack and use a hidden copy of the version with a slash to provide the reference for alignment, the jumping can be avoided:

    ZStack(alignment: .centerFirstTextBaseline) {
        Image(systemName: "wifi.slash")
            .hidden()
        Image(systemName: showSlash ? "wifi.slash" : "wifi")
            .contentTransition(.symbolEffect(.replace))
    }
    .font(.system(size: 22))
    .frame(width: 24, height: 24)
    .foregroundStyle(.black)
    .symbolRenderingMode(.hierarchical)
    

    I was testing on iOS 17, so I just commented out the .contentTransition to confirm that the jumping wasn't happening. I hope the transition works as expected when running with iOS 18.