// // AppDelegate.swift // TestSearch3 // // Created by Guy Brooker on 30/6/20. // Copyright © 2020 Guy Brooker. All rights reserved. // import UIKit import SwiftUI @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Create the SwiftUI view that provides the window contents. let contentView = ContentView() // Use a UIHostingController as window root view controller. let window = UIWindow(frame: UIScreen.main.bounds) window.rootViewController = UIHostingController(rootView: contentView) self.window = window window.makeKeyAndVisible() return true } func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. } func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. } func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } } // MARK:- ContentView struct ContentView: View { @State private var selection = 0 @ObservedObject var state = SearchState() var body: some View { TabView(selection: $selection){ Text("First View").font(.title) .tabItem { Text("First") } .tag(0) Text("Second View").font(.title) .tabItem { Text("Second") } .tag(1) PageView(TestView(state: state), state: state) .tabItem { Text("Search") } .tag(2) } } } // MARK: - Search class SearchState: NSObject, ObservableObject, UISearchResultsUpdating { @Published var text: String = "" func updateSearchResults(for searchController: UISearchController) { let searchBar = searchController.searchBar self.text = searchBar.text ?? "" } } struct PageView<Page: View>: View { var viewController: UIHostingController<Page> @ObservedObject var state: SearchState init(_ resultsView: Page, state: SearchState) { self.viewController = UIHostingController(rootView: resultsView) self.state = state } var body: some View { PageViewController(controller: viewController, state: state) } } struct PageViewController: UIViewControllerRepresentable { var controller: UIViewController @ObservedObject var state: SearchState func makeUIViewController(context: Context) -> UINavigationController { let searchController = UISearchController(searchResultsController: controller) searchController.searchResultsUpdater = state searchController.searchBar.placeholder = NSLocalizedString("Enter search (e.g. Shawshank)", comment: "") // Contain the `UISearchController` in a `UISearchContainerViewController`. let searchContainer = UISearchContainerViewController(searchController: searchController) searchContainer.title = NSLocalizedString("Search", comment: "") // Finally contain the `UISearchContainerViewController` in a `UINavigationController`. let searchNavigationController = UINavigationController(rootViewController: searchContainer) return searchNavigationController } func updateUIViewController(_ searchContainer: UINavigationController, context: Context) { print("Update Page Search Controller") // Add horizontal constraint uiKBfv.left = super.left - 90 to // searchContainer.children[0] as? UISearchContainerViewController)?.searchController.view.constraints if searchContainer.children.count > 0, let searchController = (searchContainer.children[0] as? UISearchContainerViewController)?.searchController, let searchControllerView = searchController.view, searchController.children.count > 1, let uiKBFocusView = searchController.children[1].view, !searchControllerView.constraints.reduce(false, {$0 || ($1.firstAttribute == NSLayoutConstraint.Attribute.centerX) }){ let horizontalConstraint = NSLayoutConstraint(item: uiKBFocusView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: searchControllerView, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0) searchControllerView.addConstraints([horizontalConstraint]) } } } // MARK:- Results view struct PosterView: View { let item: String let width: CGFloat @State private var showingChildView = false var body: some View { Group { NavigationLink(destination: Button(action: { self.showingChildView = false }, label: { Text("Back from \(item)") }), isActive: self.$showingChildView ) { VStack { Image(systemName: "film") .font(.largeTitle) Text(item) }.frame(width: width, height: 400) }.frame(width: width+80, height: 440) .background(Color.yellow) } } } struct TestView: View { @ObservedObject var state: SearchState let list = ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"] var body: some View { let contentWidth: CGFloat = 200 let buttonHPadding: CGFloat = 40*2 let buttonWidth = (contentWidth + buttonHPadding) let horizontalSpacing: CGFloat = 40 let count: CGFloat = CGFloat(list.count) let scrollWidth: CGFloat = max((buttonWidth * count) + (horizontalSpacing * (count + 2)), 1920.0) // Leave enough space for the shadows return ScrollView(.horizontal) { NavigationView { HStack(spacing: horizontalSpacing) { if state.text == "" { ForEach(list, id: \.self) { item in PosterView(item: item, width: contentWidth) } } else { ForEach(list.filter({$0.lowercased().contains(state.text.lowercased())}), id: \.self) { item in PosterView(item: item, width: contentWidth) } } }.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading) .padding(EdgeInsets(top: 0, leading: 80, bottom: 0, trailing: 80)) } .frame(minWidth: scrollWidth, maxWidth: .infinity, alignment: .leading) }.frame(width: 1740, height: 475, alignment: .leading) } }