我们如何向导航视图添加带有侧边栏图标的搜索栏?

时间:2021-03-03 19:59:38

标签: swiftui

我想在导航栏中添加搜索栏,但我不知道如何在同一个 HStack 中使用带有侧边栏图标的搜索栏。我将示例屏幕截图与 ContentView 代码放在一起。任何帮助将不胜感激。

截图:

enter image description here

内容视图:

struct ContentView: View {
@State private var isShowing = false
var body: some View {
    ZStack {
        if isShowing {
            SideMenuView(isShowing: $isShowing)
        }
        
        TabView {
            NavigationView {
                HomeView()
                    .navigationBarItems(leading: Button(action: {
                        withAnimation(.spring()) {
                            isShowing.toggle()
                        }
                    } , label: {
                        Image(systemName: "list.bullet")
                    }))
            }
            .tabItem {
                Image(systemName: "1.circle")
                Text("Page 1")
            }
            NavigationView {
                HomeTwoView()
                    .navigationBarItems(leading: Button(action: {
                        withAnimation(.spring()) {
                            isShowing.toggle()
                        }
                    } , label: {
                        Image(systemName: "list.bullet")
                    }))
            }
            .tabItem {
                Image(systemName: "2.circle")
                Text("Page 2")
            }
        }
        .edgesIgnoringSafeArea(.bottom)
        //.cornerRadius(isShowing ? 20 : 0) //<< disabled due to strange effect
        .offset(x: isShowing ? 300 : 0, y: isShowing ? 44: 0)
        .scaleEffect(isShowing ? 0.8 : 1)

    }.onAppear {
        isShowing=false
    }
  } 
 }

1 个答案:

答案 0 :(得分:2)

正如我在评论中提到的,这在 SwiftUI (2.0) 中是不可能的。您可以做的是与 UIKit 集成。


与 UIKit 集成

class UIKitSearchBar: NSObject, ObservableObject {
  @Published var text: String = ""
  let searchController = UISearchController(searchResultsController: nil)
  override init() {
    super.init()
    self.searchController.obscuresBackgroundDuringPresentation = false
    self.searchController.definesPresentationContext = true
    self.searchController.searchResultsUpdater = self
  }
}

extension UIKitSearchBar: UISearchResultsUpdating {
  func updateSearchResults(for searchController: UISearchController) {
    // Publish search bar text changes.
    if let searchBarText = searchController.searchBar.text {
      self.text = searchBarText
    }
  }
}

struct SearchBarModifier: ViewModifier {
  let searchBar: UIKitSearchBar
  func body(content: Content) -> some View {
    content
      .overlay(
        ViewControllerResolver { viewController in
          viewController.navigationItem.searchController = self.searchBar.searchController
        }
        .frame(width: 0, height: 0)
      )
  }
}

extension View {
  func add(_ searchBar: UIKitSearchBar) -> some View {
    return self.modifier(SearchBarModifier(searchBar: searchBar))
  }
}

final class ViewControllerResolver: UIViewControllerRepresentable {
  let onResolve: (UIViewController) -> Void
  init(onResolve: @escaping (UIViewController) -> Void) {
    self.onResolve = onResolve
  }
  func makeUIViewController(context: Context) -> ParentResolverViewController {
    ParentResolverViewController(onResolve: onResolve)
  }
  func updateUIViewController(_ uiViewController: ParentResolverViewController, context: Context) { }
}

class ParentResolverViewController: UIViewController {
  let onResolve: (UIViewController) -> Void
  init(onResolve: @escaping (UIViewController) -> Void) {
    self.onResolve = onResolve
    super.init(nibName: nil, bundle: nil)
  }
  @available(*, unavailable)
  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
  override func didMove(toParent parent: UIViewController?) {
    super.didMove(toParent: parent)
    if let parent = parent {
      onResolve(parent)
    }
  }
}

用法

struct Example: View {

  @StateObject var searchBar = UIKitSearchBar()

  var body: some View {
    NavigationView {
      Text("Example")
        .add(searchBar)
        .navigationTitle("Example")
    }
  }
}

在我自己的项目中,我使用计算属性来过滤内容,它对您也有帮助。这是我的代码:

var filteredExams: [Exam] {
        examModel.exams.filter({ searchBar.text.isEmpty || $0.examName.localizedStandardContains(searchBar.text)})
    }

截图

enter image description here