我在tableview中有一个tableviewcell。单击复选框后,应显示/隐藏字段,并调整单元格高度以支持更改。
当前,一切正常,直到我重新加载电池以更改高度为止。不仅需要两次轻击才能工作,而且还删除了字段的输入值。好像它在两个不同的单元之间进行交换。
下面是显示问题的gif图片。这两个视图控制器的代码如下。
ViewController
import UIKit
class CheckoutViewController: UIViewController {
let cellSpacingHeight:CGFloat = 30.0
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .none
tableView.allowsSelection = false
tableView.keyboardDismissMode = .onDrag
NotificationCenter.default.addObserver(self, selector: #selector(CheckoutViewController.keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(CheckoutViewController.keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: Keyboard Notifications
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
}
}
@objc func keyboardWillHide(notification: NSNotification) {
UIView.animate(withDuration: 0.2, animations: {
// For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
})
}
func foo(){
}
}
// datasource
extension CheckoutViewController: UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return 6
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
// Set the spacing between sections
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return cellSpacingHeight
}
// Make the background color show through
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.backgroundColor = UIColor.clear
return headerView
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.section == 0){
let cellID = "CheckoutEmailTableViewCellReuseID"
let cell = tableView.dequeueReusableCell(withIdentifier: cellID) as! CheckoutEmailTableViewCell
cell.setUp()
return cell
}else if(indexPath.section == 1){
let cellID = "CheckoutAddressTableViewCellReuseID"
let cell = tableView.dequeueReusableCell(withIdentifier: cellID) as! CheckoutAddressTableViewCell
cell.setUp(setUpCase: .shipping)
cell.headerLabel.text = "SHIPPING INFORMATION"
return cell
}else if(indexPath.section == 2){
let cellID = "CheckoutAddressTableViewCellReuseID"
let cell = tableView.dequeueReusableCell(withIdentifier: cellID) as! CheckoutAddressTableViewCell
cell.setUp(setUpCase: .billing)
cell.headerLabel.text = "BILLING INFORMATION"
cell.onMyAction = {
print("cell.sameAsButtonIsChecked: \(cell.sameAsButtonIsChecked)")
if let indexPath = tableView.indexPath(for: cell) {
tableView.reloadRows(at: [indexPath], with: .automatic)
}
}
return cell
}else if(indexPath.section == 3){
let cellID = "CheckoutPaymentMethodTableViewCellReuseID"
let cell = tableView.dequeueReusableCell(withIdentifier: cellID) as! CheckoutPaymentMethodTableViewCell
cell.setUp()
return cell
}else if(indexPath.section == 4){
let cellID = "CheckoutTotalTableViewCellReuseID"
let cell = tableView.dequeueReusableCell(withIdentifier: cellID) as! CheckoutTotalTableViewCell
return cell
}else if(indexPath.section == 5){
let cellID = "CheckoutButtonTableViewCellReuseID"
let cell = tableView.dequeueReusableCell(withIdentifier: cellID) as! CheckoutButtonTableViewCell
return cell
}
return UITableViewCell()
}
}
// delegate
extension CheckoutViewController:UITableViewDelegate {}
TableViewCell
import Foundation
import UIKit
class CheckoutAddressTableViewCell: UITableViewCell {
let addressFieldsHeight:CGFloat = 330
typealias CellAction = () -> Void
var onMyAction: CellAction?
var initialized = false
var sameAsButtonIsChecked:Bool = true {
willSet{
print("will:sameAsButtonIsChecked: \(sameAsButtonIsChecked)")
}
didSet {
print("didStart:sameAsButtonIsChecked: \(sameAsButtonIsChecked)")
if sameAsButtonIsChecked {
print("if")
sameAsCheckboxImageView.image = #imageLiteral(resourceName: "iconCheckboxChecked")
addressFieldsView.isHidden = true
addressFieldsHeightConstraint.constant = 0
}else{
print("else")
sameAsCheckboxImageView.image = #imageLiteral(resourceName: "iconCheckbox")
addressFieldsView.isHidden = false
addressFieldsHeightConstraint.constant = addressFieldsHeight
}
print("didFinish:sameAsButtonIsChecked: \(sameAsButtonIsChecked)")
onMyAction?()
}
}
@IBOutlet weak var headerLabel: UILabel!
@IBOutlet weak var sameAsCheckboxView: UIView!
@IBOutlet weak var sameAsCheckboxImageView: UIImageView!
@IBOutlet weak var addressFieldsView: UIView!
@IBOutlet weak var nameTextField: UITextField!
@IBOutlet weak var addressOneTextField: UITextField!
@IBOutlet weak var addressTwoTextField: UITextField!
@IBOutlet weak var cityTextField: UITextField!
@IBOutlet weak var stateTextField: UITextField!
@IBOutlet weak var zipCodeTextField: UITextField!
@IBOutlet weak var countryTextField: UITextField!
@IBOutlet weak var phoneTextField: UITextField!
@IBOutlet weak var stateImageView: UIImageView!
@IBOutlet weak var countryImageView: UIImageView!
@IBOutlet weak var sameAsHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var addressFieldsHeightConstraint: NSLayoutConstraint!
enum SetUpCase {
case shipping
case billing
}
func setUp(setUpCase:SetUpCase) {
if(setUpCase == .shipping){
sameAsHeightConstraint.constant = 0
sameAsCheckboxView.isHidden = true
}else if(setUpCase == .billing){
if !initialized {
sameAsButtonIsChecked = true
}
}
setUpTextFields()
sameAsCheckboxView.addTapGesture(tapNumber: 1, target: self, action: #selector(sameAsTap))
stateImageView.addTapGesture(tapNumber: 1, target: self, action: #selector(focusStateTextField))
countryImageView.addTapGesture(tapNumber: 1, target: self, action: #selector(focusCountryTextField))
initialized = true;
}
private func setUpTextFields(){
nameTextField.delegate = self
addressOneTextField.delegate = self
addressTwoTextField.delegate = self
cityTextField.delegate = self
stateTextField.delegate = self
zipCodeTextField.delegate = self
countryTextField.delegate = self
phoneTextField.delegate = self
nameTextField.setBothPaddingPoints(10, 10)
addressOneTextField.setBothPaddingPoints(10, 10)
addressTwoTextField.setBothPaddingPoints(10, 10)
cityTextField.setBothPaddingPoints(10, 10)
stateTextField.setBothPaddingPoints(10, 10)
zipCodeTextField.setBothPaddingPoints(10, 10)
countryTextField.setBothPaddingPoints(10, 10)
phoneTextField.setBothPaddingPoints(10, 10)
}
@objc func sameAsTap(){
self.endEditing(true)
sameAsButtonIsChecked = !sameAsButtonIsChecked
}
@objc func focusStateTextField(){
stateTextField.becomeFirstResponder()
}
@objc func focusCountryTextField(){
countryTextField.becomeFirstResponder()
}
}
// Unfortunately we need to tell iOS explicitly where to go next and
// explicitly where to look after the return key
extension CheckoutAddressTableViewCell: UITextFieldDelegate{
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if(textField.returnKeyType == .next){
if(textField == stateTextField || textField == countryTextField){
textField.superview?.superview?.superview?.viewWithTag(textField.tag+1)?.becomeFirstResponder()
}else{
textField.superview?.superview?.viewWithTag(textField.tag+1)?.becomeFirstResponder()
}
}else{
textField.resignFirstResponder()
}
return true
}
func textFieldDidBeginEditing(_ textField: UITextField) {
// textField
}
}
偶尔出现错误消息(我认为这是一个单独的问题,因为它并不总是显示)
2018-09-03 09:52:48.642169+0900 nameOfApp[33568:2874030] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x60000029e910 UIView:0x7f9e36d33aa0.height == 40 (active)>",
"<NSLayoutConstraint:0x60000029f180 UIView:0x7f9e36dd5260.height == 63 (active)>",
"<NSLayoutConstraint:0x60000049d970 UIView:0x7f9e36dd5960.height == 0 (active)>",
"<NSLayoutConstraint:0x60000049e0f0 V:|-(0)-[UIView:0x7f9e36d33aa0] (active, names: '|':UIView:0x7f9e36d8f380 )>",
"<NSLayoutConstraint:0x60000049e230 V:[UIView:0x7f9e36d33aa0]-(0)-[UIView:0x7f9e36dd5260] (active)>",
"<NSLayoutConstraint:0x60000049e320 V:[UIView:0x7f9e36dd5260]-(0)-[UIView:0x7f9e36dd5960] (active)>",
"<NSLayoutConstraint:0x60000049e370 V:[UIView:0x7f9e36dd5960]-(0)-| (active, names: '|':UIView:0x7f9e36d8f380 )>",
"<NSLayoutConstraint:0x60000049e460 V:[UIView:0x7f9e36d8f380]-(0)-| (active, names: '|':UITableViewCellContentView:0x7f9e36d90ed0 )>",
"<NSLayoutConstraint:0x60000049e4b0 V:|-(0)-[UIView:0x7f9e36d8f380] (active, names: '|':UITableViewCellContentView:0x7f9e36d90ed0 )>",
"<NSLayoutConstraint:0x600000683480 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7f9e36d90ed0.height == 433 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x60000029f180 UIView:0x7f9e36dd5260.height == 63 (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
答案 0 :(得分:1)
您应通过以下方法添加textField.text = "text kept when hidden"
。
func setUp(setUpCase:SetUpCase) {
if(setUpCase == .shipping){
sameAsHeightConstraint.constant = 0
sameAsCheckboxView.isHidden = true
}else if(setUpCase == .billing){
if !initialized {
sameAsButtonIsChecked = true
}
}
setUpTextFields()
sameAsCheckboxView.addTapGesture(tapNumber: 1, target: self, action: #selector(sameAsTap))
stateImageView.addTapGesture(tapNumber: 1, target: self, action: #selector(focusStateTextField))
countryImageView.addTapGesture(tapNumber: 1, target: self, action: #selector(focusCountryTextField))
initialized = true;
}
sameAsCheckboxView.addTapGesture(tapNumber: 1, target: self, action: #selector(sameAsTap))
提取到awakeFromNib:
更好。
NSLayoutConstraint错误应使用xib文件调试。
因为UITableViewCell是可重用的。因此,您可以从该元素中隐藏该单元格的元素,然后再次显示它。
cell.onMyAction = {
print("cell.sameAsButtonIsChecked: \(cell.sameAsButtonIsChecked)")
if let indexPath = tableView.indexPath(for: cell) {
tableView.reloadRows(at: [indexPath], with: .automatic)
}
}
下面的代码称为
let cellID = "CheckoutAddressTableViewCellReuseID"
let cell = tableView.dequeueReusableCell(withIdentifier: cellID) as! CheckoutAddressTableViewCell
cell.setUp(setUpCase: .billing)
并且您没有保留textField的文本。因此,总是出现占位符。