IQKeyboardManager为什么不滚动UITableView以使自定义单元格的文本字段可见

问题描述

这是我目前得到的结果(不需要):https://vimeo.com/459984986

这是我使用一种解决方法几乎是我想要的)得到的结果:https://vimeo.com/459986233

我的问题的摘要如下:(1)我已经安装了“ IQKeyboardManagerSwift” cocoapod,(2) >我的UITableViewController中有一个自定义单元格,它是FolingCell(另一个cocoapod),并且包含一个文本字段(3),当我在文本字段中点击时,我希望视图自动向上滚动以使可见的文本字段(在键盘上方),应由 IQKeyboardManager 自动处理(是的,我在AppDelegate中添加了“启用”代码)。

如上面的“ 不需要的”结果视频所示,该视图似乎试图滚动,但最终最终只是在上下方向抖动,然后才结束键盘向上滑动并意外覆盖文本字段时的原始位置。

此外,我发现我不想解决的小“ 解决方法”是将以下行添加到文本字段的IBAction editDidEnd出口/操作函数中:“ sender.becomeFirstResponder()”。在运行和测试我的应用程序的iPhone上更新到XCode 12和iOS 14之前,我不必麻烦使用“ .becomeFirstResponder()”或“ .resignResponder()”,因为这就是 IQKeyboardManager em>自动执行。现在,添加上述代码行允许UITableViewController将视图移动到键盘上方。 但是,如果您仔细观察,它将位于键盘上方的文本字段,这显然不是 IQKeyboardManager 完成的,因为 IQKeyboardManager 具有认设置CGFloat(10)在文本字段和键盘间的偏移量。

我认为代码的相关部分是我的自定义单元格(称为“ SavedImageFoldingImageCell”),因为这是我创建相关文本字段和 UITableViewController的地方(称为“ SavedImageTableViewController”)。

请提供您的任何帮助,建议和建议,将为我提供帮助,并倍受赞赏。谢谢!

是的,我的代码看上去很恐怖,因为我没有进行编码方面的最佳实践或一般编码方面的适当培训。建议也将不胜感激!如果您发现我可以缩短和组织代码的方式,则一定要泄露您的秘密!

自定义单元格代码

import UIKit
import FoldingCell
import LGButton
import TextFieldEffects
import SCLAlertView

class SavedImageFoldingImageCell: FoldingCell,UITextFieldDelegate {

// CLOSED
@IBOutlet weak var enteraGreetingLabelClosed: UILabel!
@IBOutlet weak var savedImageView1Closed: UIImageView!
@IBOutlet weak var savedImageView2Closed: UIImageView!
@IBOutlet weak var openCellButton: LGButton!


// OPEN
@IBOutlet weak var confirmlabelOpen: UILabel!
@IBOutlet weak var englishLabelOpen: UILabel!
@IBOutlet weak var spanishLabelOpen: UILabel!
@IBOutlet weak var savedImageView1Open: UIImageView!
@IBOutlet weak var savedImageView2Open: UIImageView!
@IBOutlet weak var enteraGreetingLabelOpen: UILabel!
@IBOutlet weak var enteraGreetinTextFieldOpen: HoshiTextField!
@IBOutlet weak var barViewOpen: UIView!


// 'Continue' Button
@IBOutlet weak var continueButton: LGButton!

// Hamburger Button
@IBOutlet weak var hamburgerButton: UIButton!










// MARK: - Setting-up Labels


// CLOSED Labels
var enteraGreetingClosed: String = "" {
    didSet {
        enteraGreetingLabelClosed.text = String(enteraGreetingClosed)
    }
}


// OPEN Labels
var englishOpen: String = "" {
    didSet {
        englishLabelOpen.text = String(englishOpen)
    }
}

var spanishOpen: String = "" {
    didSet {
        spanishLabelOpen.text = String(spanishOpen)
    }
}

var enteraGreetingOpen: String = "" {
    didSet {
        enteraGreetingLabelOpen.text = String(enteraGreetingOpen)
    }
}

var confirmOpen: String = "" {
    didSet {
        confirmlabelOpen.text = String(confirmOpen)
    }
}










override func awakeFromNib() {
    barViewOpen.layer.maskedCorners = [.layerMaxXMinYCorner,.layerMinXMinYCorner] // Top right corner,Top left corner respectively
    barViewOpen.clipsToBounds = true
    
    foregroundView.layer.cornerRadius = 10
    foregroundView.layer.masksToBounds = true
    
    super.awakeFromNib()
    // Initialization code
    enteraGreetinTextFieldOpen.delegate = self
}

override func animationDuration(_ itemIndex: NSInteger,type: FoldingCell.AnimationType) -> TimeInterval {
    let durations = [0.26,0.2,0.2]
    return durations[itemIndex]
}










@IBAction func enteraGreetingTextFieldEditingDidBegin(_ sender: HoshiTextField) {
    print("@enteraGreetingTextFieldEditingDidBegin -> cell.swift: does nothing as of Now.")
}


@IBAction func enteraGreetingTextFieldEditingDidEnd(_ sender: HoshiTextField) {
    
    if sender.text!.isEmpty != true {
        // Activates and shows the 'Continue' button
        continueButton.isEnabled = true
        continueButton.alpha = 1
        
    print("enteraGreetingTextFieldEditingDidEnd@Cell -> cell.swift: activated 'Continue' button because textField contained text after editing ended.")
    } else if sender.text!.isEmpty == true {
        // Deactivates and hides the 'Continue' button
        continueButton.isEnabled = false
        continueButton.alpha = 0.5
        
        print("enteraGreetingTextFieldEditingDidEnd@Cell: deactivated 'Continue' button because textField was empty after editing ended.")
    }
}




// JUST FYI,THIS DOES NOT GET CALLED
private func textFieldShouldReturn(_ textField: HoshiTextField) -> Bool {
    let storyboard = UIStoryboard.init(name: "Main",bundle: nil)
    let savedImageTableVC = storyboard.instantiateViewController(withIdentifier: "SavedImageTableViewController") as! SavedImageTableViewController
    savedImageTableVC.loadViewIfNeeded()

                
        if textField.text?.isEmpty == false {
            savedImageTableVC.liveGreeting = textField.text!
            savedImageTableVC.savedImageTableView.reloadData()
            print(".CELL @textFieldShouldReturn() -> savedImageTableVC.savedImagesArray: \(savedImageTableVC.savedImagesArray).")
                            
            let indexPathRow = textField.tag
            StructOperation.globalVariable.tappedCellIndexRow = indexPathRow
            print(".CELL @textFieldShouldReturn() -> StructOperation.globalVariable.tappedCellIndexRow: \(StructOperation.globalVariable.tappedCellIndexRow).")

            savedImageTableVC.goToSend()
                        
            print("User entered a greeting in enteraGreetingTextField: \(savedImageTableVC.liveGreeting).")
        } else if textField.text?.isEmpty == true {
            savedImageTableVC.liveGreeting = ""
            SCLAlertView().showError("Error",subTitle: "To send an image,a greeting must also be specified.",closeButtonTitle: "Done",timeout: nil,colorStyle: SCLAlertViewStyle.error.defaultColorInt,colorTextButton: 0xFFFFFF,circleIconImage: nil,animationStyle: .topToBottom)
                            
            print("User did not enter a greeting in enteraGreetingTextField.")
        }
    return true
}

}










// MARK: - Actions ⚡️


extension SavedImageFoldingImageCell {

@IBAction func openCellButtonTapped() {
//        print("The open-cell button was tapped (just a downward arrow).")
}

@IBAction func enteraGreetingTextfieldOpenEditingDidEnd() {
//        print("'enteraGreetingTextField' finished editing.")
}

@IBAction func continueButtonTapped(_: AnyObject) {
//        print("The 'Continue' button was tapped.")
}

@IBAction func hamburgerButtonTapped(_: AnyObject) {
//        print("The hamburger button was tapped.")
}

}

UITableViewController的代码

import UIKit
import TextFieldEffects
import SCLAlertView
import MessageUI
import FoldingCell
import MLKitTranslate

class SavedImageTableViewController: UITableViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate,MFMessageComposeViewControllerDelegate,UITextFieldDelegate,UIContextMenuInteractionDelegate {

@IBOutlet var savedImageTableView: UITableView!


*** Omitted other irrelevant outlets,vars,& constants ***


override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(true)
    activityIndicator() // Omitted because nothing regarding the textfield is called here
    refresh() // Omitted ""
    
}

override func viewDidLoad() {
    super.viewDidLoad()
    setup() // Omitted ""; (assigned self to tableview's delegate and dataSource here)
    checkIfSavedImages() // Omitted ""
    getDeadlineInSeconds() // Omitted ""
    
    
    // For deadline countdown timer
    countdownTimer = Timer.scheduledTimer(timeInterval: 1,target: self,selector: #selector(updateCounter),userInfo: nil,repeats: true)
    
    
    // Stops loading spinner and hides view
    self.indicator.stopAnimating()
    self.indicator.hidesWhenStopped = true
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(true)
}



@IBAction func enteraGreetingTextFieldEditingDidEnd(_ sender: HoshiTextField) {
    let cell = savedImageTableView.dequeueReusableCell(withIdentifier: "SavedImageFoldingImageCell") as! SavedImageFoldingImageCell
    
    if sender.text?.isEmpty == true {
        sender.text =  ""
        cell.continueButton.isEnabled = false
        cell.continueButton.alpha = 0.5
//            sender.resignFirstResponder()
    } else if sender.text?.isEmpty == false {
        self.liveGreeting = sender.text!
        cell.continueButton.isEnabled = true
        cell.continueButton.alpha = 1
    }
}

@IBAction func enteraGreetingTextFieldEditingDidBegin(_ sender: HoshiTextField) {
    sender.becomeFirstResponder() // Fixes IQKeyboardManager (rather,allows UITableViewController to properly scroll)
    
    let indexPathRow = sender.tag
    StructOperation.globalVariable.tappedCellIndexRow = indexPathRow
    print("enteraGreetingTextFieldEditingDidEnd()@ViewController -> StructOperation.globalVariable.tappedCellIndexRow: \(StructOperation.globalVariable.tappedCellIndexRow).")
}




//MARK: - TableView Functions

override func tableView(_ tableView: UITableView,willdisplay cell: UITableViewCell,forRowAt indexPath: IndexPath) {
    guard case let cell as SavedImageFoldingImageCell = cell else {
        return
    }
    
    cell.enteraGreetingClosed = "Enter a Greeting"
    cell.enteraGreetingOpen = "Enter a Greeting"
    cell.englishOpen = "English"
    cell.spanishOpen = "Spanish"
    cell.confirmOpen = "Confirm"
    
    
    // Greeting TextField
    cell.enteraGreetinTextFieldOpen.delegate = self
    cell.enteraGreetinTextFieldOpen.tag = indexPath.row
    
    // Open-cell button (downward arrow)
    cell.openCellButton.tag = indexPath.row
    
    // 'Continue' button
    cell.continueButton.tag = indexPath.row
    cell.continueButton.isEnabled = false
    cell.continueButton.alpha = 0.5
    
    // Hamburger button
    cell.hamburgerButton.tag = indexPath.row
    
    
    // Closed/Open Images (English,Spanish)
    let calculatedindex = (indexPath.row * 2) + 1
    
    cell.savedImageView1Closed.image = savedImagesArray[calculatedindex - 1]
    cell.savedImageView2Closed.image = savedImagesArray[calculatedindex]
        
    cell.savedImageView1Open.image = savedImagesArray[calculatedindex - 1]
    cell.savedImageView2Open.image = savedImagesArray[calculatedindex]

    
    
    cell.backgroundColor = .clear
    
    
    
    if cellHeights[indexPath.row] == Constants.closeCellHeight {
        cell.unfold(false,animated: false,completion: nil)
    } else {
        cell.unfold(true,completion: nil)
    }
    
    
    
    // Allows recognition of tapping the 'Continue' button by connecting that button's outlet to a newly created function down below a little
    cell.continueButton.addTarget(self,action: #selector(SavedImageTableViewController.continueButtonTapped(_:)),for: .touchUpInside)
    // Allows recognition of tapping the 'open cell' button (just a downward arrow) by connecting that button's outlet to a newly created function down below a little
    cell.openCellButton.addTarget(self,action: #selector(openCellButtonTapped(_:)),for: .touchUpInside)
    // Allows recognition of tapping the 'hamburger' button (just three horizontal lines as a button) by connecting that button's outlet to a newly created function down below a little
    cell.hamburgerButton.addTarget(self,action: #selector(hamburgerButtonTapped(_:)),for: .touchUpInside)
}

override func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = savedImageTableView.dequeueReusableCell(withIdentifier: "SavedImageFoldingImageCell",for: indexPath) as! FoldingCell
    let durations: [TimeInterval] = [0.26,0.2]
    cell.durationsForExpandedState = durations
    cell.durationsForCollapsedState = durations
    
    
    return cell
}

override func tableView(_ tableView: UITableView,didSelectRowAt indexPath: IndexPath) {
    guard case let cell as FoldingCell = tableView.cellForRow(at: indexPath) else {
        return
    }
    
    if cell.isAnimating() {
        return
    }
    
    var duration = 0.0
    let cellIsCollapsed = cellHeights[indexPath.row] == Constants.closeCellHeight
    if cellIsCollapsed {
        cellHeights[indexPath.row] = Constants.openCellHeight
        cell.unfold(true,animated: true,completion: nil)
        duration = 0.5
    } else {
        cellHeights[indexPath.row] = Constants.closeCellHeight
        cell.unfold(false,completion: nil)
        duration = 0.8
    }

    UIView.animate(withDuration: duration,delay: 0,options: .curveEaSEOut,animations: {
        tableView.beginUpdates()
        tableView.endUpdates()
        
        
        // fix https://github.com/Ramotion/folding-cell/issues/169
        if cell.frame.maxY > tableView.frame.maxY {
            tableView.scrollToRow(at: indexPath,at: UITableView.ScrollPosition.bottom,animated: true)
        }
    },completion: nil)
    
    // Provide haptic Feedback of success
    let generator = UINotificationFeedbackGenerator()
    generator.notificationOccurred(.success)
}

***Rest is Omitted because I think its irrelevant to the problem***

解决方法

我通过简单地从 UITableViewController-> UIViewController 切换类来解决了自己的问题。我在 IQKeyboardManager的 Github页面上浏览了已解决的问题,发现由于Apple的UITableViewController自动处理视图和键盘的移动,因此 IQKeyboardManager的开发人员选择忽略文本字段。在UITableViewController中。因此,必须将类更改为UIViewController或其他受支持的类,以使文本字段被 IQKeyboardManager 识别。