Having trouble transitioning list onto screen.

I am tryign to write something that acts like a drod down menu. The view is composed of a VStack with an TextField and List. When the binding has 0 objects i am trying to animate the list into view. The code looks like so:


struct Search: Identifiable {
    let id: UUID
    let text: String
}

struct SearchBox: View {
    @State var searchParam: String = ""
    @State var stuff = [Search]()

    init() {
        // To remove only extra separators below the list:
        UITableView.appearance().tableFooterView = UIView()

        // To remove all separators including the actual ones:
        UITableView.appearance().separatorStyle = .none
    }

    var body: some View {
        var binding = Binding(
        get: {
            self.searchParam
        },
        set: {
            self.stuff.append(
                Search(id: UUID(), text: $0))
                self.searchParam = $0
        })

        return VStack(spacing: 0.0) {
            TextField("Search", text: binding )
                .font(.title)
                .padding()
                .background(Color.white)

            Color(.darkGray)
                .frame(height: 1.0)

            if stuff.count > 0 {
                List(stuff, id: \.id) {
                    Text($0.text)
                }
                .transition(.slide)
            }
        }
    }

    struct SearchBox_Preview: PreviewProvider {
        static var previews: some View{
            SearchBox()
        }
    }
}

Its embedded in a ZStack on the content view like so:


struct Search: Identifiable {
    let id: UUID
    let text: String
}

struct SearchBox: View {
    @State var searchParam: String = ""
    @State var stuff = [Search]()

    init() {
        // To remove only extra separators below the list:
        UITableView.appearance().tableFooterView = UIView()

        // To remove all separators including the actual ones:
        UITableView.appearance().separatorStyle = .none
    }

    var body: some View {
        var binding = Binding(
        get: {
            self.searchParam
        },
        set: {
            self.stuff.append(
                Search(id: UUID(), text: $0))
                self.searchParam = $0
        })

        return VStack(spacing: 0.0) {
            TextField("Search", text: binding )
                .font(.title)
                .padding()
                .background(Color.white)

            Color(.darkGray)
                .frame(height: 1.0)

            if stuff.count > 0 {
                List(stuff, id: \.id) {
                    Text($0.text)
                }
                .transition(.slide)
            }
        }
    }

    struct SearchBox_Preview: PreviewProvider {
        static var previews: some View{
            SearchBox()
        }
    }
}


I can slow the default fade and i can scale (but not from the top down). But none of the slide or move transitions are working.

Accepted Reply

import SwiftUI

struct Search: Identifiable {
    let id: UUID
    let text: String
}

struct SearchBox: View {
    @State var searchParam: String = ""
    @State var stuff = [Search]()
    @State var showList = false

    init() {
        // To remove only extra separators below the list:
        UITableView.appearance().tableFooterView = UIView()

        // To remove all separators including the actual ones:
        UITableView.appearance().separatorStyle = .none
    }

    var body: some View {
        var binding = Binding<String>(
            get: {
                self.searchParam
        },
            set: {
                self.stuff.append(
                    Search(id: UUID(), text: $0)
                )
                self.searchParam = $0
                
                withAnimation {
                    self.showList = self.stuff.count > 0
                }
        })

        return VStack(spacing: 0.0) {
            TextField("Search", text: binding )
                .font(.title)
                .padding()
                .background(Color.white)


            if stuff.count > 0 {
                List {
                    Text("foo")
                }
                .transition(.slide)
            }
        }
    }

    struct SearchBox_Preview: PreviewProvider {
        static var previews: some View{
            SearchBox()
        }
    }
}


I had to change my state in a withAnimation block. That allowed the animation to happen.

Replies

import SwiftUI

struct Search: Identifiable {
    let id: UUID
    let text: String
}

struct SearchBox: View {
    @State var searchParam: String = ""
    @State var stuff = [Search]()
    @State var showList = false

    init() {
        // To remove only extra separators below the list:
        UITableView.appearance().tableFooterView = UIView()

        // To remove all separators including the actual ones:
        UITableView.appearance().separatorStyle = .none
    }

    var body: some View {
        var binding = Binding<String>(
            get: {
                self.searchParam
        },
            set: {
                self.stuff.append(
                    Search(id: UUID(), text: $0)
                )
                self.searchParam = $0
                
                withAnimation {
                    self.showList = self.stuff.count > 0
                }
        })

        return VStack(spacing: 0.0) {
            TextField("Search", text: binding )
                .font(.title)
                .padding()
                .background(Color.white)


            if stuff.count > 0 {
                List {
                    Text("foo")
                }
                .transition(.slide)
            }
        }
    }

    struct SearchBox_Preview: PreviewProvider {
        static var previews: some View{
            SearchBox()
        }
    }
}


I had to change my state in a withAnimation block. That allowed the animation to happen.