You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI自定义搜索栏子视图显隐过渡动画失效问题

SwiftUI自定义搜索栏淡入淡出动画失效问题解决

问题根源

你的清除按钮(X)和Cancel按钮的过渡动画失效,核心原因是状态变化未在动画上下文内执行。虽然外层HStack添加了animation修饰符,但@FocusState的切换以及条件视图的插入/移除,需要明确通过withAnimation包裹状态更新,才能触发transition定义的动画效果。

解决方案

  1. 在触发isEditing状态变更的动作中,用withAnimation包裹状态更新
  2. 移除外层HStack的全局animation修饰符,避免与withAnimation产生冲突
  3. 修正onSubmit的错误声明(无需@State修饰)

修改后的完整代码

struct CustomSearchBar: View {
    var prompt: String
    @Binding var query: String
    @FocusState private var isEditing: Bool
    var onSubmit: () -> Void // 移除不必要的@State修饰
    
    var body: some View {
        HStack(alignment: .center) {
            TextField(prompt, text: $query)
                .onSubmit(onSubmit)
                .focused($isEditing)
                .padding(8)
                .padding(.horizontal, 25)
                .background(Color(.systemGray6))
                .overlay(
                    HStack {
                        Image(systemName: "magnifyingglass")
                            .foregroundColor(.gray)
                            .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
                            .padding(.leading, 8)
                        
                        if isEditing {
                            Button {
                                query = ""
                            } label: {
                                Image(systemName: "multiply.circle.fill")
                                    .foregroundColor(.gray)
                                    .padding([.leading, .trailing], 8)
                            }
                            .transition(.opacity)
                        }
                    }
                )
                .onTapGesture {
                    // 用withAnimation包裹状态切换,触发动画上下文
                    withAnimation(.linear(duration: 0.3)) {
                        isEditing = true
                    }
                }
                .submitLabel(.search)
                .transition(.slide)
            
            if isEditing {
                Button {
                    // 同样用withAnimation包裹状态回退
                    withAnimation(.linear(duration: 0.3)) {
                        isEditing = false
                        query = ""
                    }
                } label: {
                    Text("Cancel")
                        .foregroundColor(.red)
                }
                .padding(.trailing, 10)
                .transition(.opacity)
            }
        }
        // 移除全局animation修饰符,避免冲突
    }
}

关键修改说明

  • withAnimation的作用:当修改isEditing状态时,withAnimation会为该状态变化创建动画上下文,所有依赖此状态的视图过渡(如transition(.opacity))都会自动应用指定的动画参数。
  • 移除全局动画修饰符:全局animation修饰符的作用范围较宽泛,容易和局部动画逻辑冲突,对于条件视图的过渡,使用withAnimation做精准控制更可靠。
  • 修正闭包参数声明:onSubmit作为组件的闭包参数,不需要@State修饰,否则会引发编译错误。

内容的提问来源于stack exchange,提问作者cenas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 01:40:24