UITableView reloadData自动调用resignFirstResponder
我有这个带有自定义单元格的 UITableView,只能获取预定义的值,因此我使用 UIPickerView 作为其 inputView。一切都非常好,直到我编辑字段并需要显示其更新值。
为了使事情更清晰、更易于维护,我将委托和数据源作为单独的类,并使用通知使它们与 tableView 交互。因此,从 UIPickerView 选择一个值后,tableView 的数据源会收到通知,并依次通知持有 tableView 引用的主 ViewController。从那里我打电话
[_tableView reloadData];
,一切似乎都正常,除了 UIPickerView 消失了,我想是因为单元格被重新生成,并且在某个地方调用了一些 resignFirstResponder ,或者类似的东西。 有没有其他方法可以使 tableView 更新其值,而不必在某个地方实现自定义方法,这会很丑陋?
I have this UITableView with custom cells that can get only predefined values, therefore I use a UIPickerView as their inputView. All is jolly good until I edit a field and need to show its updated value.
In order to make things clearer and easier to maintain, I made delegates and data sources as separate classes, and use notifications to make them interact with the tableView. So, after a value has been chosen from the UIPickerView, the tableView's data source gets notified, and in turn notifies the main ViewController that holds a reference to the tableView. From there I call
[_tableView reloadData];
and everything seems to work, except that the UIPickerView disappears, I think because the cells are regenerated and somewhere some resignFirstResponder is called, or something like that.
Is there any other way to make the tableView updating its values without having to implement a custom method somewhere that does it, which would be quite ugly?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
这读起来就像预期的行为 - 选择器属于特定的单元格,该单元格被重新加载并且不再是第一响应者。我猜想无论如何,人们都必须选择一个特定的元素才能显示选择器,即使其成为第一响应者。
因此,您要么需要在重新加载后使其再次成为第一响应者,要么直接更新特定的单元格。
This reads like expected behavior - the picker belongs to a particular cell, that cell gets reloaded and is not the first responder any more. I guess one had to select a specific element anyway for the picker to appear, i.e. to make it first responder.
So you either need to make it become first responder again after reloading, or update the specific cell directly.
添加:
在你的之后:
成功了
adding:
after your:
did the trick
我遇到了同样的问题,上面的答案都不能完美工作(我看到键盘上下弹跳等)。
解决了这个问题
在this SO post之后,我通过调用这对我有用 ,表格行得到更新,甚至扩展/收缩(如果您动态更改行高)并带有漂亮的动画,所有这些都无需放弃第一响应者,甚至无需启动键盘关闭。
这不会滚动您的表格视图以适合任何展开的行,因此我将上面的代码片段放在专用方法 fe 中:
I met the same problem, none of the answers above worked perfectly (I see the keyboard bouncing up and down, etc.).
Following this SO post I fixed the issue by calling
this worked for me, table rows get updates and even expand/shrink (if you are changing rows height dynamically) with a nice animation, all without resigning first responder or even starting keyboard dismiss.
This will not scroll your table view to fit any expanded row, so I put the snippet above in dedicated method, f.e.:
您可以遵循这种方法,虽然不是最好的,但它有效:
You can follow this approach, not the best, but it works:
我通过子类化 UITextView、覆盖 -(BOOL)resignFirstResponder 并添加 BOOL canResign 解决了这个问题。该变量在重新加载数据之前设置,并在不久后取消设置。
I solved this by subclassing UITextView, overriding -(BOOL)resignFirstResponder and by adding a BOOL canResign. this variable is set before reloading the data and unset a short time after.
自定义文本字段源自 UITextField。
.h
.m
确保您的自定义文本字段在表格视图重新加载时不会重新创建。
Custom text field is derived from UITextField.
.h
.m
Make sure that your custom text field is not recreated on table view reloading.
我将 UISearchBar 放在 UITableView 中自己的部分中。当启动搜索时,我确保只刷新不包含搜索栏的部分。
I put my UISearchBar in its own section in a UITableView. When firing off the search, I made sure to only refresh the sections which do not contain the search bar.
Swift 解决方案:
我们可以通过子类化 UITextfiled 来覆盖默认的 canResignFirstResponder ,
您需要在重新加载语句之前和之后设置 canResign 变量。
不要忘记将自定义类文本字段指定为 CustomField。
Swift solution:
we can override default canResignFirstResponder by subclassing UITextfiled
all you need to set canResign variable before and after reload statement.
don't forget to assign the custom class text field as CustomField.
这是我的解决方案。认为搜索文本字段位于索引 0 中。您需要更新或添加或删除下一行。
Here my solution. Think that search textfield is in index 0.. You need to update or add or remove next rows..
如果您在搜索栏时遇到此问题,以下内容在 iOS 6 中为我解决了:
If you are facing this issue with a search bar, the following did it for me in iOS 6:
正如@Eiko 提到的,这对我有用!
更新 UIPickerViewDelegate 的
pickerView:didSelectRow:inComponent:
方法中的单元格:As mentioned by @Eiko, this works for me!
Update the cell in UIPickerViewDelegate's
pickerView:didSelectRow:inComponent:
method:跟踪哪个单元格的键盘处于活动状态,然后通过
cellForRowAtIndexPath
获取该特定单元格并使 textView firstResponderTrack which cell's keyboard is active and then get that particular cell by
cellForRowAtIndexPath
and make textView firstResponder我使用 beginUpdate 和 endUpdate
结束更新后,获取包含已具有焦点的文本字段的单元格,然后使其成为第一响应者
I use beginUpdate and endUpdate
After end update, get the cell contains the textfield already has focus then make it first responder
所以我测试了很多方法,但看起来只有一种方法仍然看起来不错。
首先,我将回顾一下当前需要避免的 TableView 约束。
resignFirstResponder
。firstResponder
的单元格上调用 reload,这是一个可能的解决方案。reloadRows(at:with:)
或reloadSections
等 api。resignFirstResponder
最终解决方案
就在您
reloadData()
之前
通过
visibleCells
等API获取作为第一响应者的单元格将
UITextField
/UITextView
的hidden属性设置为正确
将
textView
移动到通过调用tableView.addSubview(cell.textField)
查看层次结构(我使用了 tableview),记住不要调用removeFromSuperview
在某处保留对此
textView
的引用,以便在下一步中使用。在
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
数据源方法中在相应单元格上设置 textView。
将隐藏设置为 false
So I have tested many ways but it looks like there is only one way that still looks good.
First I'll go over the current constraints you need to avoid of the TableView.
resignFirstResponder
on all cells.firstResponder
it is a possible solution.reloadRows(at:with:)
orreloadSections
.resignFirstResponder
Final Solution
Right before you
reloadData()
get the cell which is the first responder through API's such as
visibleCells
set the hidden property of the
UITextField
/UITextView
totrue
move the
textView
to a view in the view hierarchy(I used the tableview) by callingtableView.addSubview(cell.textField)
remember don't callremoveFromSuperview
keep a reference to this
textView
somewhere to be used in the next step.in
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
datasource methodSet the textView on the corresponding cell.
set hidden to false