1

当搜索栏出现时,我试图让 tableView 向上移动。看一下问题:

在此处输入图像描述

我想我知道问题出在哪里,但我想不出解决方案。在 SearchResultsUpdating 我有一个动画块:

func updateSearchResults(for searchController: UISearchController) {

    UIView.animateKeyframes(withDuration: 1, delay: 0, options: UIView.KeyframeAnimationOptions(rawValue: 7)) {

    self.tableView.frame = CGRect(x: 20, y: self.view.safeAreaInsets.top, width: 
    self.view.frame.size.width-40, height: self.view.frame.size.height - 
    self.view.safeAreaInsets.top)

    }
}

在我看来,动画块只接收 y 原点的先前坐标,因此它的动画不同步。我尝试将目标添加到 tableView、navigationBar 或 searchBarTextField,但没有任何效果。

任何帮助表示赞赏,谢谢!

编辑:在实施肖恩的第二个建议后,结果如下:

在此处输入图像描述

我无法想象为什么它现在动画不流畅......非常令人沮丧!

编辑 2 - 要求的代码:

class ViewController: UIViewController{

//City TableView
let cityTableView = UITableView()

let searchVC: UISearchController = {
    let searchController = UISearchController(searchResultsController: nil)
    searchController.obscuresBackgroundDuringPresentation = true
    searchController.searchBar.placeholder = "Search"
        return searchController
    }()

//viewDidLoad
override func viewDidLoad() {
    super.viewDidLoad()

    //Do any setup for the view controller here
    setupViews()
    
    //CityViewController
    setupCityViewTableView()
    
}

//setupViews
func setupViews(){
    //NAVIGATIONBAR:
    //title
    title = "Weather"
    //set to hidden because on initial load there is a scroll view layered over top of the CityViewTableView (code not shown here). This gets set to false when the scrollView alpha is set to 0 and the CityViewTableView is revealed
    navigationController?.navigationBar.isHidden = true
    navigationController?.navigationBar.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
    
    //NAVIGATION ITEM:
    navigationItem.searchController = searchVC
    
    //UISEARCHBARCONTROLLER:
    searchVC.searchResultsUpdater = self
    }
}

//MARK:  -CityViewController Functions
extension ViewController{

//setUp TableView
func setupCityViewTableView(){
    
    cityTableView.translatesAutoresizingMaskIntoConstraints = false
    //set tableView delegate and dataSource
    cityTableView.delegate = self
    cityTableView.dataSource = self
    //background color
    cityTableView.backgroundColor = .black
    //separator color
    cityTableView.separatorColor = .clear
    //is transparent on initial load
    cityTableView.alpha = 0
    //set tag
    cityTableView.tag = 1000
    //hide scroll indicator
    cityTableView.showsVerticalScrollIndicator = false
    //register generic cell
    cityTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cityCell")
    //add subview
    view.addSubview(cityTableView)
    //Auto Layout
    cityTableView.leadingAnchor
        .constraint(equalTo: view.leadingAnchor,
                    constant: 20).isActive = true

    cityTableView.topAnchor
        .constraint(equalTo: view.topAnchor,
                    constant: 0).isActive = true

    cityTableView.trailingAnchor
        .constraint(equalTo: view.trailingAnchor,
                    constant: -20).isActive = true

    cityTableView.bottomAnchor
        .constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor,
                    constant: 0).isActive = true
    
    }
}

//MARK: -TableView Controller
extension ViewController: UITableViewDelegate, 
UITableViewDataSource{

//number of rows
func tableView(_ tableView: UITableView, numberOfRowsInSection 
section: Int) -> Int {
    
    if tableView.tag == 1000{
        return 5
    }
    return self.models[tableView.tag].count
    
}

//cell for row
func tableView(_ tableView: UITableView, cellForRowAt indexPath: 
IndexPath) -> UITableViewCell {
    
    //CityViewController
    if tableView.tag == 1000{
        
        let cell = tableView.dequeueReusableCell(withIdentifier: 
"cityCell", for: indexPath)
        cell.textLabel?.text = "Test"
        cell.textLabel?.textAlignment = .center
        cell.backgroundColor = .systemGray
        cell.selectionStyle = .none
        cell.layer.cornerRadius = 30
        cell.layer.borderColor = UIColor.black.cgColor
        cell.layer.borderWidth = 5
        cell.layer.cornerCurve = .continuous

        return cell
    }
    
    //WeatherViewController
    //code here for scrollView tableViews
}

//Height for row
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if tableView.tag == 1000{
        return view.frame.size.height/7
    }
    return view.frame.size.height/10
}

//Should Highlight Row
func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
    if tableView.tag == 1000{
        return true
    }
    return false
}

//Did select row
func tableView(_ tableView: UITableView, didSelectRowAt 
indexPath: IndexPath) {
    
    //calls function for segue to Weather Scroll View (not shown)
    if tableView.tag == 1000{
        segueToWeatherView(indexPath: indexPath)
        
        }
    
    }

}

编辑 3:当我注释掉另一个函数时,它终于可以工作了,但我不确定为什么,或者如何修复它。这是有问题的函数, addSubViews()

//setup viewController
func addSubViews(){
    //add weatherView as subView of ViewController
    view.addSubview(weatherView)
    //add subviews to weatherView
    weatherView.addSubview(scrollView)
    weatherView.addSubview(pageControl)
    weatherView.addSubview(segueToCityViewButton)
    weatherView.addSubview(segueToMapViewButton)
    
}

具体来说,当我注释掉这一行时它会起作用:

view.addSubview(weatherView)

以下是有关设置 weatherView 及其所有子视图的所有代码:

//Any additional setup goes here
private func setupViews(){
    
    //VIEWCONTROLLER:
    //title
    title = "Weather"
    //Background color of view Controller
    view.backgroundColor = .darkGray
    
    //WEATHERVIEW:
    //Background color of weather view Controller
    weatherView.backgroundColor = .clear
    //weatherView frame
    weatherView.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height)
    
    //SCROLLVIEW:
    //background color of scroll view
    scrollView.backgroundColor = .clear
    //scrollView frame
    scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height)
    //changed
    
    //PAGECONTROL:
    //page control frame
    pageControl.frame = CGRect(x: 0, y: view.frame.height-view.frame.size.height/14, width: view.frame.width, height: view.frame.size.height/14)
    
    //TRANSITIONVIEW:
    //TransitionView frame
    transitionView.frame = CGRect(x: 20, y: 0, width: view.frame.size.width-40, height: view.frame.size.height)
    
    //BUTTONS:
    //segue to CityView
    segueToCityViewButton.frame = CGRect(x: (weatherView.frame.width/5*4)-20, y: weatherView.frame.height-weatherView.frame.size.height/14, width: weatherView.frame.width/5, height: pageControl.frame.height)
    //segue to MapView:
    segueToMapViewButton.frame = CGRect(x: 20, y: weatherView.frame.height-weatherView.frame.size.height/14, width: weatherView.frame.width/5, height: pageControl.frame.height)
    
    //LABELS:
    transitionViewLabel.frame = transitionView.bounds
    
    //NAVIGATIONBAR:
    //set to hidden on initial load
    navigationController?.navigationBar.isHidden = true
    navigationController?.navigationBar.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
    
    //NAVIGATION ITEM:
    navigationItem.searchController = searchVC
    
    //UISEARCHBARCONTROLLER:
    searchVC.searchResultsUpdater = self
    
    
}

为了彻底起见,这里是完整的 viewDidLoad() 函数:

override func viewDidLoad() {
    super.viewDidLoad()

    //MARK: View Controller
    
    //These two will eventually be moved to the DispatchQueue in APICalls.swift
    configureScrollView()
    pageControl.numberOfPages = models.count
    
    
    //Do any setup for the view controller here
    setupViews()
    
    //setup ViewController
    addSubViews()

    //Add Target for the pageControl
    addTargetForPageControl()
    
    //MARK: CityViewController
    setupCityViewTableViews()
    
}

编辑 4:通过 viewDidLoad() 中的以下更改,我终于让它工作了!

override func viewDidLoad() {
super.viewDidLoad()

//MARK: CityViewController
//Moved to a position before setting up the other views
setupCityViewTableViews()

//MARK: View Controller

//These two will eventually be moved to the DispatchQueue in APICalls.swift
configureScrollView()
pageControl.numberOfPages = models.count

//Do any setup for the view controller here
setupViews()

//setup ViewController
addSubViews()

//Add Target for the pageControl
addTargetForPageControl()

}
4

1 回答 1

1

以您现在的方式进行操作是一种方法,但我认为这是最具挑战性的方法,原因如下:

  1. 您对导航栏中搜索控制器动画的实现没有太多控制和访问权限,因此获取正确的坐标可能是一项任务

  2. 即使您确实设法获得了正确的坐标,尝试同步您的动画帧和时间以与导航栏上的搜索动画同步和无缝也会很棘手

我建议您使用以下 2 种替代方案来替代您目前正在做的事情,在那里您可以免费获得开箱即用的新闻体验。

选项 1:使用 UITableViewController 而不是 UIViewController

这是使用 aUITableViewController并将 a 添加UISearchController到导航栏的所有代码。

class NewsTableViewVC: UITableViewController
{
    private let searchController: UISearchController = {
        let sc = UISearchController(searchResultsController: nil)
        sc.obscuresBackgroundDuringPresentation = false
        sc.searchBar.placeholder = "Search"
        sc.searchBar.autocapitalizationType = .allCharacters
        return sc
    }()
    
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = .black
        
        title = "Weather"
        
        // Ignore this as you have you own custom cell class
        tableView.register(CustomCell.self,
                           forCellReuseIdentifier: CustomCell.identifier)
        
        setUpNavigationBar()
    }
    
    private func setUpNavigationBar()
    {
        navigationItem.searchController = searchController
    }
}

这是您可以期待的体验

UITableViewController 搜索控制器动画搜索栏新闻app iOS swift

选项 2:使用自动布局而不是框架来配置你的 UITableView

如果您不想使用 a UITableViewController,请配置您的UITableViewusingauto layout而不是frameswhich 有更多工作但不要太多:

class NewsTableViewVC: UIViewController, UITableViewDataSource, UITableViewDelegate
{
    private let searchController: UISearchController = {
        let sc = UISearchController(searchResultsController: nil)
        sc.obscuresBackgroundDuringPresentation = false
        sc.searchBar.placeholder = "Search"
        sc.searchBar.autocapitalizationType = .allCharacters
        return sc
    }()
    
    private let tableView = UITableView()
    
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        // Just to show it's different from the first
        view.backgroundColor = .purple
        
        title = "Weather"
        
        setUpNavigationBar()
        setUpTableView()
    }
    
    private func setUpNavigationBar()
    {
        navigationItem.searchController = searchController
    }
    
    private func setUpTableView()
    {
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.register(CustomCell.self,
                           forCellReuseIdentifier: CustomCell.identifier)
        tableView.dataSource = self
        tableView.delegate = self
        tableView.backgroundColor = .clear
        view.addSubview(tableView)
        
        // Auto Layout
        tableView.leadingAnchor
            .constraint(equalTo: view.leadingAnchor,
                        constant: 0).isActive = true
        
        // This important, configure it to the top of the view
        // NOT the safe area margins to get the desired result
        tableView.topAnchor
            .constraint(equalTo: view.topAnchor,
                        constant: 0).isActive = true
        
        tableView.trailingAnchor
            .constraint(equalTo: view.trailingAnchor,
                        constant: 0).isActive = true
        
        tableView.bottomAnchor
            .constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor,
                        constant: 0).isActive = true
    }
}

您可以期待以下体验:

UITableView 搜索栏动画搜索控制器新闻app iOS swift

更新

这是基于您更新的代码,您错过了一个可能会影响您看到的结果的小细节,这是 UITableView 的最高约束。

您将约束添加到safeAreaLayoutGuide顶部锚点:

cityTableView.topAnchor
        .constraint(equalTo: view.safeAreaLayoutGuide.topAnchor,
                    constant: 0).isActive = true

如果您注意到,我从上面的代码中的建议是将其添加到view顶部约束

// This important, configure it to the top of the view
// NOT the safe area margins to get the desired result
cityTableView.topAnchor
    .constraint(equalTo: view.topAnchor,
                constant: 0).isActive = true

试一试,看看你是否接近得到你所期望的?

如果有帮助,这是我的实现的完整代码的链接:

于 2022-02-16T10:45:27.563 回答