How could I keep keyboard up when tableview cells are tapped? - swift

I am a beginner learning Swift and trying to build a search page with Swift. In my search page of the app, I have added two Views in my storyboard with one View above the other.
The upper View contains a Collection View where I have two prototypes of collection view cells. The first type of the cells has Label. The second type of the cells has TextField.
The other View on the bottom half of the screen contains a dynamic Table View where I have a list of items that can be selected. Each row of the table view cells has a selection item.
So, when I tap on a table view cell, the selection item will appear in the collection view. If I type a keyword in the TextField in the collection view, table view reloads and shows all the selection items that has the keyword, so I can tap and add an item to the collection view.
I would like to keep adding by typing a keyword after I tap on a searched item in the table view. So, I made the first cell showing selected items with labels and the second cell that has the TextField separated into two sections of the collection view. So, I only reload the first section (without TextField) for each selection. But somehow the keyboard automatically resign whenever I tap on the table view cell to add an item to the collection view.
Is there any way I can keep the keyboard up even when I tap on the tableview cells?
The keyboard also resigns when I tap the collection view cells.
I would appreciate your advice. Thanks.

I hope you are having a good day.
You can try calling this method on the UITextField you would like to show the keyboard for (maybe call it after the user taps on the UITableViewCell):
textField.becomeFirstResponder()
where "textField" is the variable name of your UITextField.
Please let me know if this fixed your issue.
Edit #1
Hello! Since my previous solution did not achieve your intended behavior. There is another solution in my mind, however I have not tried it before.
As an introduction to the concept of delegation, there is a method created by Apple called "textFieldShouldEndEditing" which is called by Apple whenever any keyboard will disappear on any text field.
This method is created by Apple, but you can override it (i.e. customize it) to suit your needs and tailor its behavior.
To override this method you have to assign your class as the delegate of UITextField by adding UITextFieldDelegate to your class definition as follows:
class YourClassName: UIViewController, UITextFieldDelegate { }
Now you have to set your class as the delegate by saying textField.delegate = self For every UITextField you create in your collection views
You then can re-create the method we discussed earlier in your class:
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
//let's implement it the next steps, but for now, let's return true.
return true
}
Now instead of Apple calling their version of the method, they will call yours.
You then can create a variable in the top level of your class (I will let you know where this will be helpful later), and "maybe" name it as:
var isCellBeingClicked = false
Now upon clicking on a cell, make this variable true, I believe you are using the method didSelectRowAt (but you could be using any other method which is fine):
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
[...]
isCellBeingClicked = true
[...]
}
Now back to our customized method textFieldShouldEndEditing mentioned in step 3. You can add this implementation:
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
//If a cell is being clicked right now, please do not dismiss the keyboard.
if isCellBeingClicked {
isCellBeingClicked = false //reset the value otherwise the keyboard will always be there
return false
}
else { return true }
}
Please let me know if this fixes your issue.
Best regards

Related

Is it possible use different instance of UIMenuController for UITextField in Swift?

According to link we should use a singleton UIMenuController instance which is referred to the editing menu.
The problem is I want to show extra items in different situations. For instance, I want to just show "copy" item when keyboard is up. and show "copy" and "reply" when tapping on a tableview row.
When I add "reply" to the UIMenuController instance it is shown when tapping on UITextField too. therefore, I added these codes:
func textViewDidBeginEditing(_ textView: UITextView) {
var nonReplyMenuItems: [UIMenuItem] = []
if let allMenuItems = UIMenuController.shared.menuItems {
for menuItem in allMenuItems {
if menuItem.title != "reply".localized {
nonReplyMenuItems.append(menuItem)
}
}
}
UIMenuController.shared.menuItems = nonReplyMenuItems
UIMenuController.shared.setMenuVisible(true, animated: true)
}
It fixed the problem in most situations, but not all.
when keyboard is up and tapping on a row in tableview "reply" will be added. Then when I tap on UITextView the reply will be shown there too.
It seems your scenario is like it:
tap on textfield ----> shows copy
tap on tableview ---> shows copy and reply
tab on textfield ----> shows copy and reply (you want only copy shows)
As I know the textViewDidBeginEditing calls when your text filed is not editing and you tap on that; So if you have two textfileds by switching on that method calls every time but when you are switching between a text filed and another action base object your text field is editing and its state has not changed.
When you touch on tableview you must call textfield.resignFirstResponder() so when you tap on text field again the textViewDidBeginEditing calls again, the problem of this is hiding keyboard; The better way I preferÙˆ is adding function to touch down of text field or on gesture to do what you write on textViewDidBeginEditing method

Transitioning from uitableview to new viewcontroller

I'm working on the "settings" portion of my app. When one of the cells is clicked, I need to transition to a new View Controller depending on which cell was clicked.
I have found a ton of answers, but they all seem to not go far enough. I understand how to set up a segue to a new view controller and I understand how to use didSelectRowAt Indexpath to show which cell was clicked. I can figure out the transition, but I can't figure out many different transitions based on which cell was clicked.
Is there a way to do this with dynamic cells or should I be using static?
If you have fixed amount of cells, I'd go for static cells. However if you want to use dynamic cells, you can create something like enum with cases that store row index.
fileprivate enum Row: Int {
case volume = 0
case notification = 1
}
Then in didSelectRowAt delegate method:
let row = Row(rawValue: indexPath.row)!
switch row {
case .volume:
// Navigate somewhere
case .notification:
// Navigate somewhere
}

Table with static cells won't scroll when I set delaysContentTouches = false

The problem: HIGHLIGHT vs SCROLLING
My buttons inside the cell where not getting highlighted when I lightly tap on them. I had to tap hard and for a long time to be able to see the tap state of the button.
So I did this in order to set the delaysContentTouches to false (I didn't manage other way to do it) inside viewDidLoad():
for index in tableView.subviews {
if (index.isKindOfClass(UIScrollView)) {
let scrollViewFound = index as! UIScrollView
scrollViewFound.delegate = self
scrollViewFound.delaysContentTouches = false
scrollViewFound.canCancelContentTouches = true
scrollViewFound.scrollEnabled = true
}
}
This way the buttons highlight correctly but then I cannot scroll the table up or down, unless I start dragging from one of the empty cells --> userInteractionEnable = false in the empty cells
What I need:
To be able to highlight the buttons but also to scroll the table.
Is it even possible to have both, scrollable view and highlighted buttons?
What I have tried
I tried calling this function:
func touchesShouldCancelInContentView(view: UIView) -> Bool {
print("touchesShouldCancelInContentView happening---------")
return true
}
Which never gets called. I tried overriding But it gives an error:
Method does not override any method from its superclass
Which is weird, because UITableViewController inherits from UIScrollView. I also tried adding UIScrollViewDelegate to the class definition, but of course it gives another error that this is redundant.
Extra Information
The class is declared like this:
class Settings: UITableViewController, UITextFieldDelegate { ...
The tableView is made of Static Cells
The cells:
Some are empty: where UserInteractionEnable = false
Some have buttons with text field: I want these buttons to get highlighted. UserInteractionEnable = true. The button action is called by .TouchUpInside
Some have labels and a check image: Their action gets called in didSelectRowAtIndexPath which will change the labels colour and check images
Maybe it is relevant to say that when user clicks on any cell didSelectRowAtIndexPath it will
call a function to dismiss the keyboard.
You tried to subclass the wrong class, that's why it doesn't work. You have to subclass the UITableView class itself, and not the UITableViewController.
Can you try the following ?
- First
Subclass the TableView class in order to override the touchesShouldCancelInContentView function.
class UIDraggableTableView: UITableView {
override func touchesShouldCancelInContentView(view: UIView) -> Bool {
if (view.isKindOfClass(UIButton)) {
return true
}
return super.touchesShouldCancelInContentView(view)
}
}
- Second
In your TableViewController class, when viewDidLoad() is called, append the following right after super.viewDidLoad():
self.tableView = DraggableTableView()
This should solve your issue.
Part of this answer was taken from this StackOverflow post.

NSCollectionView selection handling in Swift

Learning with Swift and I've been at this all day with little progress:
Need to know when an item in NSCollectionView is selected. The end goal is to get the item to highlight and to be able to delete it from the collection with the delete key. My NSCollectionView is bound to an ArrayController to get content and send the selection indexes, so looks like I need to be watching the ArrayController for a selection change, but don't see any helpful delegate methods there. The prototype view has a single textfield.
I was following the obj-c examples here and elsewhere (found none in Swift), but a Swift NSCollectionViewItem doesn't have the setSelected method to override. It has a selected property.
How to get informed when an NSCollectionViewItem gets selected in Swift?
The most simple solution is to override the selected property and react for example whenever it is set:
class CollectionSonaViewItem: NSCollectionViewItem {
override var isSelected: Bool {
didSet {
// set background color to indicate selection
self.view.layer?.backgroundColor = (isSelected ? NSColor.blue.cgColor : NSColor.clear.cgColor)
// do more stuff
}
}
From there on you can send a notification or call a function in your collection view class, its delegate or whatever required.

How to determine which cell is being viewed or clicked in a collection view

I want to be able to edit records that are displayed in a collection view.
I've added an "Edit" button to the collection view. What is the best way to determine which cell is to be edited?
I thought of doing something like so:
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
visibleCell = collectionView.visibleCells().first as MessageCell
}
I didn't want to add the edit button to the xib itself as I don't want the button to scroll when the cell scrolls
One possibility is to have a variable in your ViewController called something like isEditing. This will be set to true when the edit button is clicked.
Then, set your collection view's delegate to self.
Implement this method: func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath), A UICollectionViewDelegate method.
In the method, write something like:
if isEditing{
// What happens when selected and editing
} else{
// What happens when selected and not editing
}