Hiding objects within UITableViewCell iOS 8 (Swift) - ios

I have a UITableViewCell that on touch, expands (dropdown). The user is then presented with a selection of options. When the user touches one of the options I want to briefly hide all the options, show an activity indicator spinning, display a confirmation message (on success) and then collapse the cell back to normal.
I'm having trouble hiding any object within the custom cell. The following simple code doesn't work (this is the correct superview corresponding to the cell):
var customCell: MyCustomCell = icon.superview.superview.superview as MyCustomCell
customCell.myLabel.hidden = false
I have tried hiding/showing a variety of different objects but nothing works. I've even popped it inside dispatch_async to ensure it runs on the main thread.
Additionally, Xcode 6 beta tells me that myLabel.hidden is read only. This also happens for other objects. Is this no longer the correct way to hide something?
I've had a search around but had no luck in finding an answer. If someone could help me out I'd be grateful! Thanks.

The usual way of doing something like this would be to implement the UITableViewDelegate method -tableView:didSelectRowAtIndexPath: to let you know when a row is tapped.
Then you can easily get and modify the cell
var customCell = self.tableView.cellForRowAtIndexPath(indexPath) as MyCustomCell
customCell.myLabel.hidden = false
I consider the line icon.superview.superview.superview to be a code smell. The multiple superview calls makes makes your code fragile and likely to break if you ever change the view hierarchy in your cell.

Related

Xcode7.3 UITest of Disclosure Indicator in a custom TableViewCell

(Xcode 7.3.1, iOS9.3, Swift)
I'm struggling with setting up an UI Test in my assignment for what would seem to be a fairly standard and common use case.
I have a sub-classed UITableViewCell which contains a textField that does not fill the entire cell and has the Disclosure Indicator set. The user is able to type the data into textField by tapping on it, but if they tap outside the textField, but still in the cell, my app segues to another view. The project works fine and the child view receives the correct data from the cell's textField.
My Master-Detail app has UITableViews on both the Master and Detail views. My UI Test selects the first cell in the Master View, waits a little for the DV and then selects the second cell in the detail view, which is configured in accordance to my earlier description.
I am simulating a tap on the second cell using
tablesQuery.cells.elementBoundByIndex(1).tap()
However, the simulator interprets it as a tap in the textField, so no segue occurs. I have read SwiftyCruz's question and the given answers but his use case is a little different, as I'm not using a Detail Disclosure, also the accepted answer doesn't translate to my situation. In following ferunandu explanation, I have tried setting the Accessibility Label and Identifier on the Cell as well as a different string for the accessoryView?.accessibilityIdentifier. Though UI Test still doesn't work, ferunandu's snippet does change the disclosure indicator from > to a blue box.
Using a breakpoint, I've been querying the app object in the debug window trying to find the right control, but to no avail. I am able to find the textField using indices as well as the identifier, but nothing I've tried has returned .exists true for the accessoryView.
Am I trying to access the cell incorrectly? Or, is it actually not possible to do what I'm attempting?
The code for my test is:
XCUIDevice.sharedDevice().orientation = .Portrait
let app = XCUIApplication()
wait()
let tablesQuery = app.tables
tablesQuery.cells.elementBoundByIndex(0).tap()
wait()
tablesQuery.cells.elementBoundByIndex(1).tap()
What am I not understanding properly here? Any advice would be greatly appreciated.
(I know I could have used a standard UITableViewCell with the data entry done on the child view, but I prefer not to change the design of my app to accommodate XCTest's, seems a bit backwards.)
I have a sub-classed UITableViewCell which contains a textField that does not fill the entire cell...
I am simulating a tap on the second cell using
tablesQuery.cells.elementBoundByIndex(1).tap()
However, the simulator interprets it as a tap in the textField, so no segue occurs.
It sounds like your tap on the table view cell is being intercepted by the text field. When UI tests tap on a table view cell, the tap will be at the centre of the UI element's frame.
To offset the tap location from the centre of the cell, use coordinate(withNormalizedOffset:) and tap the coordinate instead of the element directly.
let cell = app.tables.cells.elementBoundByIndex(0)
// Retrieves coordinate that is 50% of the way along the cell
// and 20% of the way down the cell - adjust these values to
// find the right values to avoid tapping the text field area
// of the cell
let cellCoordinateForTap = cell.coordinateWithNormalizedOffset(CGVector(dx: 0.5, dy: 0.2))
cellCoordinateForTap.tap()

How to have DidSelectRow activate keyboard?

Goal
I want to have a keyboard (custom) to show when I click on a cell in my tableview and have said keyboard edit a label in the selected cell.
What I have read and tried
Stack overflow and other searched threads/tutorials
A Swift example of Custom Views for Data Input (custom in-app keyboard)
How to make custom keyboard only for my app in Swift?
iOS 8: Creating a Custom Keyboard in Swift
Along with other results and searches (also the recommended readings within these threads), these were great for me getting the keyboard the way I want it (which is app-specific, I don't want to have the user install the keyboard to use the app), however, none explain how I could "activate" the keyboard without a textfield.
My thought process is this: I will have a keyboard with a textfield in place in order to receive the input from the keys pressed. This input would then be sent to the label that is in the selected cell. The problem is in the keyboard showing without anything to call it...
Why I don't want a textfield in the cell: Because I think it is more smart/elegant to have the tableview cell activate the keyboard. I have seen this in other apps and I can't figure out how it is done.
Any help on this matter is much appreciated. I am completely new to programming, am using Swift (so have no clue Obj-C or the like).
Thank you!
Well after a lot of discussions around other websites, it is a shame to say it but what I wanted was actually impossible (like stated by Duncan). For some reason I thought that in programming that word did not exist, but alas it is there. Well, the way that I did work around this limitation was as replied here in the comments as well as from the resource materials I already read:
I have 2 views:
tableView - this will have the list of items that I would like to edit a value. Has multiple labels where one of them would be edited by the user.
keyboardView - custom keyboard that would allow user input.
For the keyboard I used the delegate method as described in "A Swift example of Custom Views for Data Input". This worked perfectly and would send the data over to the tableView under the keyWasTapped function.
Next was the tableView. I had 3 labels in the custom cell, where one was called valueLabel. I had to add a textField to my storyboard hidden behind the tableview with which the user will interact and in the didselectrow I included the command to summon the keyboard:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
textField.becomeFirstResponder()
}
From there I would grab the text from the textfield and update the UILabels in my custom cell. At least this way I can select a cell and not the textfield. So considering that the answer that would fit what I wanted is combination of the replies, I thought it would be best to say it here.
Thanks to Sandeep and Larme for their time.
TVDN,
Have a textField in cell not the label :) Create a custom cell create an IBOutlet to that class ffrom textField in cellForRowAtIndexPath
let tableCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! myCell
tableCell.yourTextField.resignFirstResponder()
and in didSelectRowAtIndexPath
let tableCell = self.tableView.cellForRowAtIndexPath(indexPath)
self.tableView.dequeueReusableCellWithIdentifier("cell") as! myCell
tableCell.yourTextField.becomeFirstResponder()

Can't update text of UITextView in a custom UITableViewCell

I've been running into an issue that seems to keep coming up on the web, but have been unable to resolve the issue... I'm trying to set the text of a UITextView that's inside of a custom UITableViewCell in a load function that's called on the cell when it's contents are being rendered in its table view.
These are my current settings on my textview that's inside my custom tableviewcell. Note that UserInteraction is NOT enabled, but Editable and Selectable ARE.
This is the controller for my custom UITableViewCell, which contains the function 'loadCell'
This is the cellForRowAtIndexPath that puts the custom tableViewCell into the tableView, and it calls the loadCell() function when it's initialized.
This is the result, with the textView obviously not being updated correctly.
Another note I'd like to add is that if I update the textView during the awakeFromNib function in the custom UITableViewCell controller, it successfully is able to change the text in the textField.
If anyone can help me out, that would be super duper awesome, as I'd love to be able to use textViews instead of labels :) Thanks!
So, it turns out that the problem was in the cellForRowAtIndexPath function, in which I was attempting to dequeueReusableCell twice (once at the functions start, and once if the index was 0). I'm not entirely sure why this is causing a problem, though I can make an assumption that it was attempting to dequeue the same cell twice, and was causing problems.
Either way, getting rid of
let cell = tableView.dequeueReusableCellWithIdentifier("MenuItemDescriptionCell")
did the trick.
Hope this helps someone in the future! Happy coding :)

Custom table cell without dequeueReusableCellWithIdentifier in Swift

I have an averagely sized table which is working perfectly, except for the row insertion animation (withRowAnimation). I've overriden it (with the help of stack community) to have a longer duration than the original system animation and it works just fine, but ...
Because i'm using custom cells as reusable cells - each time i scroll this effect is getting wiped out.
So the only solution i see is to stop the reuse.
I know this will interfere with the memory, but in this case its the only scenario left (of which i know).
My general question is how do i load a custom cell nib without using dequeueReusableCellWithIdentifier so that the reuse wouldn't happen.
Thank you.
You should use dequeueReusableCellWithIdentifier, not using it is a recipe for disaster.
Take a look into your code and when you dequeue a cell (reused or not, most of the time it'll be reused), the first thing you should do is set all elements in that cell back to the original state, so that that reused cell behaves like a non reused cell.
I don't know what you animation/implementation is about but here an example from a project I wrote with custom cells :
In each cell I added buttons, this could be 1, 2, 3,... buttons. If I did nothing in a reused cell I would have more buttons than expected because the old buttons would still be there...
So in my code the first thing I did after dequeing the cell would be to remove all the buttons.
let cell = tableView.dequeueReusableCellWithIdentifier("RelatedCell") as! RelatedCell
cell.removeAllActionButtons()
where my removeAllActionButtons (a method in my custom cell) method would be something like:
for button in actionButtons {
button.removeFromSuperview()
}
actionButtons is an Array containing all that buttons added to that custom cell

UICollectionview with IBOutlet-UIButtons not working

I have a two-days-brain-breaking-question to all of you:
I integrated a menu in my application by using a UICollectionView (one line, horizontal scrolling, fixed number of 9 items). Every cell has an own tag and uses an own prototype cell with own identifier. During the cellForItemAtIndexPath I assign a prototype cell to every cell (the prototype cell contains the specific UIButton in the storyboard). If you click a cell (respective the UIButton) a popover should open (this is working quite well, because the popover is anchored to the collection view not to the cell - otherwise Xcode will give an error, because of an outlet bind to repeating content.). Now to the questions:
Dependently from the chosen value in the popover, the name (titleLable.text) of the button should change. I think, an IBOutlet is needed, but not usable, because of the possible (but not happened) multiple (re)use of the cell.
Some other action in the APP could happened randomly, that changes the label of the button. Therefore an IBOutlet is needed too, I think.
I tried to give the prototypes a specific tag, but this (in my opinion) could not be used, because I cannot assign the tags to an UIButton, during loading, because not all of the cells are visible and therefore not reachable in viedDidAppear...
Any help is appreciated. This is a new try for an old problem and the collectionView till yesterday looked quite promising. Any ideas to help? Thanks a lot. I canĀ“t give code, because 90% of the work are done in IB.
you can use NSNotificationCenter to send message from your UIPopoverController to a UICollectionViewCell.
Send and receive messages through NSNotificationCenter in Objective-C?
Just subclass UICollectionViewCell to MyCollectionViewCell and use your subclass in your UICollectionView.
At the -(void)initWithFrame:(CGRect)frame method of MyCollectionViewCell you should subscribe as an observer to NSNotificationCenter, and unsubscribe in dealloc.
Than all your cells may receive notification and react to it.
This is not an optimal way of receiving callbacks, but maybe the simplest.

Resources