UICollectionView - When the keyboard appears the e

2020-05-03 02:09发布

问题:

This isn't my desired effect. This only happens when the collection view is set to horizontal flow layout. I've seen a few other posts regarding this very same issue but none of the provided answers have worked. Has anyone found a solution?

I've provided two screenshots showing a UITextField before the keyboard is triggered and after. As you can see the UITextField along with the entire collection view (which can't be seen) is pushed up along with the keyboard. Usually the keyboard is overlayed having no effect on the views.

Before

After

Update Code provided. The method I used to implement doesn't involve a Storyboard.

class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    window = UIWindow()
    window?.makeKeyAndVisible()

    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .horizontal
    let rvc = ViewController(collectionViewLayout: layout)
    window?.rootViewController = rvc

    return true
}

// .... other boilerplate code provided by Apple when you make a new App
}

ViewController.swift

class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout, UITextFieldDelegate {
    let homeCellId = "homeCellId"
    let worldCellId = "worldCellId"

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.white
        collectionView?.register(HomeCell.self, forCellWithReuseIdentifier: homeCellId)
        collectionView?.register(WorldCell.self, forCellWithReuseIdentifier: worldCellId)
collectionView?.isPagingEnabled = true
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 2
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: view.frame.width, height: view.frame.height)
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        print(indexPath.item)
        let identifier: String
        if indexPath.item == 0 {
            identifier = homeCellId
        } else if indexPath.item == 1 {
            identifier = worldCellId
        }
        else {
            identifier = homeCellId
        }

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
        cell.backgroundColor = UIColor.blue
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
}

MyCell.swift

class MyCell: UICollectionViewCell {

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.setupView()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setupView() {

    }


}

HomeCell.swift

class HomeCell: MyCell {
    let weightField: UITextField = UITextField(frame: .zero)
    override func setupView() {
        super.setupView()
        print("HomeCell")
        weightField.backgroundColor = UIColor.white
        weightField.translatesAutoresizingMaskIntoConstraints = false
        weightField.keyboardType = UIKeyboardType.default
        self.addSubview(weightField)

        weightField.topAnchor.constraint(equalTo: self.topAnchor, constant: 200).isActive = true
        weightField.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 50).isActive = true
    }


}

WorldCell.swift

// same as HomeCell

class WorldCell: MyCell {

    override func setupView() {
        super.setupView()
        print("worldcell")
    }


}

回答1:

Okay so I've found a solution to this problem. I came across this in a couple of other threads on stackoverflow regarding a similar incident, in one case the Answer had no votes attributed to it and a comment left to the answer said it didn't work..

Though after all this I'm still not crystal clear on why the other implementation causes the collection view to shift up. Though there is some correlation between the window, root view controller and it's subviews along with the keyboard. Why this happens I don't know.

Now on to the code and fix..

The main different between the method in the question above and here is the way the collection view is initialised. I'll only post what I changed because the rest is just the same.

AppDelegate.swift

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        let rvc = ViewController()

        window? = UIWindow()
        window?.makeKeyAndVisible()
        window?.rootViewController = rvc
        return true
    }
}

The striking difference here is the root view controller is no longer initialised with the Collection View Controller. We use a standard View Controller.

ViewController.swift

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

    lazy var collView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        let view = UICollectionView(frame: .zero, collectionViewLayout: layout)
        view.dataSource = self
        view.delegate = self
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.backgroundColor = UIColor.darkGray
        collView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cellId")
        collView.register(HomeCell.self, forCellWithReuseIdentifier: "homeCellId")
        self.view.addSubview(collView)
        collView.backgroundColor = UIColor.blue
        collView.translatesAutoresizingMaskIntoConstraints = false
        collView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
        collView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
        collView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
        collView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
        collView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 1)
        // Do any additional setup after loading the view, typically from a nib.
    }
}

We initialise the View Controller with a collectionview as a subview and apply the same code we would normally to the cells