Ihor M.
Ihor M.

Reputation: 302

SwiftUI expandable component Animation issue

I created a custom bottom bar with horizontal expandable tabs.

I have two animations: (1) tab expand/collapse animation, (2) tab bar translation animation (when some tab was expanded, it affects move other tabs)

struct AirTabView: View {
    
    @Binding var isActive: Bool
    
    var model: TabModel
    var action: (() -> ())
    
    var body: some View {
        HStack(spacing: 10) {
            Image(model.imageName)
                .foregroundColor(.black)
            if isActive {
                Text(model.title)
                    .font(.subheadline)
                    .fontWeight(.medium)
                    .foregroundColor(.init(uiColor: .label)
                    )
                    .lineLimit(1)
            }
        }
        .padding(10)
        .background(isActive ? Color(.secondarySystemBackground) : .clear)
        .cornerRadius(11)
        .onTapGesture(perform: action)
        .animation(.linear(duration: 2), value: isActive)
    }
    
}

struct AirTabBar: View {
    
    var tabs: [TabModel]
    var actions: [TabActionModel]
    
    @State private var selectedIndex = 0
    
    var body: some View {
        HStack(spacing: 10) {
            ForEach(0..<tabs.count, id: \.self) { index in
                AirTabView(isActive: .constant(selectedIndex == index), model: tabs[index]) {
                    selectedIndex = index
                }
            }
            Spacer()
            ForEach(0..<actions.count, id: \.self) { index in
                AirTabActionView(model: actions[index])
            }
            
        }
        .padding(.horizontal, 20)
        .padding(.vertical, 10)
        .background()
        .cornerRadius(16)
        .shadow(
            color: .init(uiColor: .black
                .withAlphaComponent(0.07)
            ),
            radius: 15,
            x: 2)
        .animation(.linear(duration: 2))
    }
    
}

But sometimes, I have a visual bug when text that appears in an expanded cell overlaps the image at the animation start. I want that text always be and appear right side of the image.

Please explain to me what I did wrong. Sometimes RIGHT behavior happens, but I want to understand and fix WRONG

enter image description here

Upvotes: 1

Views: 429

Answers (1)

Asperi
Asperi

Reputation: 258097

Expected effect is not clear, but observed behavior is due to transition (by default it is opacity), ie. when text is added conditionally it appears with opacity transition.

Here is a demo how it could be managed (so you can tune more if some other effect is needed).

Tested with Xcode 13.4 / iOS 15.5 (some missed things replaced)

demo

Main part:

    HStack(spacing: 10) {
        if isActive {
            HStack {
                Image(systemName: model.imageName)  // system name for testing !!
                    .foregroundColor(.black)
                Text(model.title)
                    .font(.subheadline)
                    .fontWeight(.medium)
                    .foregroundColor(.init(uiColor: .label)
                    )
                    .lineLimit(1)
            }
            .transition(.identity)  // content is same !!
        } else {
            Image(systemName: model.imageName)
                .foregroundColor(.black)
                .transition(.identity)    // same is here !!
        }
    }
    .animation(.none, value: isActive) // << don't animate !!
    .padding(10)

so content of label is not animated and replaced Image <> Image Title, which gives title always appears right after image, and only highlighting box is animated.

Test module on GitHub

Upvotes: 1

Related Questions