KIF cannot tap UIButton inside UITableViewCell if it's its UITableView's only one - ios

I am having trouble automating tapping on an UIButton that is embedded inside a UITableViewCell if that cell is the table's only one. This is in the context of UI automation with KIF.
Here my relavant call:
[tester tapViewWithAccessibilityLabel: #"LABEL"
traits: UIAccessibilityTraitButton];
// trait only specified for 2nd case below
Here is what I am observing:
If I put the accessibility label on the UITableViewCell KIF's KIFUITestActor - waitForAccessibilityElement:view:withLabel:traits:tappable: returns the UITableView, not the cell. Somehow the table seems to inherit its only child's accessibility label and lets KIF encounter it first during its recursive search.
If I put the accessibility label on the UIButton instead, KIF finds it but determines that is is not tappable (i.e. UIView-KIFAdditions -tappablePointInRect: returns NO), presumably because its mainly transparent between the thin font lines for the button's label (the tap goes to a UITableViewCellContentView instead).
A workaround might be tapping on the row by it's NSIndexPath but maybe there is still a better way to overcome the described hurdles I am facing. So how could I instruct KIF to tap a button like this with a call to tapView...?

If you are making cell in code, make sure your button is added to cell.contentView.
If you are loading cell from xib, try to send contentView to back of view hierarchy (I have not found any downsides yet for doing it) with:
[self sendSubviewToBack:self.contentView];

This is just to confirm that this workaround is applicable:
[tester tapRowAtIndexPath: [NSIndexPath indexPathForRow: 0 inSection: 0]
inTableViewWithAccessibilityIdentifier: #"IDENTIFIER"];

The "good" solution should be something like this:
UITableViewCell *cell = [tester waitForCellAtIndexPath:indexPath inTableViewWithAccessibilityIdentifier:tableAccessibilityIdentifier];
UIAccessibilityElement *element = [cell accessibilityElementWithLabel:accessibilityLabel traits:UIAccessibilityTraitButton];
[tester tapAccessibilityElement:element inView:cell];
Unfortunately it doesn't work as expected. Sometimes the element is a UIAccessibilityElementMockView and tapping it in step 3 leads means just tapping the underlying cell. Naturally the results will not be as expected.
I've managed to finally work around that by doing something more along the lines of:
MyCustomCellClass *cell = (MyCustomCellClass *)[self waitForCellAtIndexPath:indexPath inTableViewWithAccessibilityIdentifier:tableAccessibilityIdentifier];
[cell.buttonOutlet sendActionsForControlEvents:UIControlEventTouchUpInside];
Note that this means
relying less on UI interaction
having a custom class
having an outlet to the button
But hey, KIF isn't supported by Apple so it sometimes, you know, breaks :)

Related

Customizing selection behavior of UITableViewCell

I'm implementing custom visual effects when the user selects a row in a UITableView. I've overridden UITableViewCell.setSelected(), but I call it in my subclass, it does some tweaking of the appearance of the content view before adding the selectedBackgroundView to the hierarchy, like setting opacity to false. I don't want the content view and it's subviews to be !opaque, so I thought I could avoid calling super.setSelected when overriding it, but then that breaks the select/deselect behavior.
Is there a way to avoid the default UI changes of UITableViewCell.setSelected() without breaking cell selection/deselection? It is surprising to me that built in UI changes for selecting/deselecting cells is so intertwined with the logic/state tracking to make selection/deselection work at all inside setSelected()
More generally, are there any debugging tips or tracing I can use to see what exactly goes on, in terms of what updates are happening to views, when calling something like UITableViewCell.setSelected(), so I can mimic it without calling the base class method (I understand this is likely to break with new versions of iOS)
Thank you,
Neal
Instead of using the cell selection method you can try using the highlight method.
Step 1: Make the table view cell selection to none
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
Step 2: Override the cell's set highlighted method to customize the cell selection
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
if (highlighted)
{
}
else
{
}
}

iOS UITest : How to find UITableViewCell's AccessoryView?

Hello I'm learning UITests now
I have a question
how can detect accessoryView's tap on the tableViewCell?? in UITest
below is my tableViewCell
I want detect detail closure accesorry view's tap
like this
app.tables.cells.buttons["FTCellAccesoryIdentifier"].tap()
but accesorry is a subclass of UIView
so i allocate accisibility identifier key in cellForRows function
cell.accessoryView?.accessibilityIdentifier ="FTCellAccesoryIdentifier"
and my test function is
i try
app.tables.cells.elementBoundByIndex(lastCellIndex).otherElements.elementMatchingType(.Any, identifier: "FTCellAccesoryIdentifier").tap()
but not work
is possible to tap cell's accesoryView in UITests?
TL;DR
Regarding...
is possible to tap cell's accesoryView in UITests?
... Yes.
But you have to use the default accessibility identifier for that.
For example, for a cell like this one:
Tapping the Detail Disclosure button during a UI test ("More Info" is the key here):
XCUIApplication().tables.buttons["More Info, Title"].tap()
Tapping the cell itself during a UI test:
XCUIApplication().tables.staticTexts["Title"].tap()
Long story:
There is no way to change the default accessibility identifier of the Detail Disclosure. From Apple:
Note: If your table cells contain any of the standard table-view elements, such as the disclosure indicator, detail disclosure button,
or delete control, you do not have to do anything to make these
elements accessible. If, however, your table cells include other types
of controls, such as a switch or a slider, you need to make sure that
these elements are appropriately accessible.
At the time you try to set the accessibility identifier/label of the Detail Disclosure in cellForRow, cell.accessoryView is nil. Why? Again, from Apple:
accessoryView
Discussion
If the value of this property is not nil, the UITableViewCell class
uses the given view for the accessory view in the table view’s normal
(default) state; it ignores the value of the accessoryType property.
The provided accessory view can be a framework-provided control or
label or a custom view. The accessory view appears in the the right
side of the cell.
The accessory view will be nil until you define them. :/
You would need to provide your "own" Detail Disclosure (e.g.: a customized UIView) if you really want to set a custom identifier for it. For example (to illustrate):
cell.accessoryView = UIView(frame: CGRectMake(0, 0, 20, 20))
cell.accessoryView?.backgroundColor = UIColor.blueColor()
cell.accessoryView?.accessibilityIdentifier = "FTCellAccesoryIdentifier"
You should use accessoryButtonTappedForRowWithIndexPath delegate method to handle click on accessoryView.
Then by indexPath parameter of method you can know which cell it is!
Hope this will help :)

Button in custom UITableViewCell not responding in iOS 7

This is more or less a continuation of this post: Button in UITableViewCell not responding under ios 7
I am having the same exact issue and have tried every suggestion in the thread. Obviously I don't own that question so I can't edit it to give more info, and thus why I am posting this question now!
Problem:
I have VC nib that I load up that has a tableview in it that I resize based on how many rows are in it. Each row is made from a custom uitableviewcell subclass using a nib file. That class/nib has 4 buttons in it. I can load this code up in iOS 6 or iOS 8 right now and it works perfectly. I don't have a iOS 7 device so I'm bound to the simulator which is at 7.1 (which is the version I'm guess the user that reported this issue was using as well given it was today). Now in the simulator, and the user's phone, I can touch/click everything else on that VC except any of the buttons in the cells. It's as if they had UserInteractionEnabled set to NO, but they don't and neither are any of their parent views (as I'll soon get into).
Tried solutions:
-Completely recreating the nib from scratch both using and not using autolayout
-Calling [self.contentView addSubview:button] in the awakeFromNib of the cell class
-Tried re-adding the buttons to the contentView at runtime with [self.contentView addSubView:button]
-Have ensured four times over that every view in the hierarchy I can find that leads to these buttons have userInteractionEnabled set to YES. (including but not limited to the tableview itself, the cell, the contentView and when I added a "parent view" to the buttons that it was set as well)
-Tried raising all the buttons with a parent view that contains nothing but the buttons
-All buttons are at the top(visually bottom) of the event stack(add and remove are the other two buttons):
-Have set the table cell selection from single to none.
-I am not overriding layoutSubviews in my cell class
-I can not move any views outside of the Content View as Interface Builder takes them completely out of the cell if I do that.
-I have tried disabling the userInteractionEnabled on just the ContentView at runtime with no change
-I tried putting in the cell creation code of the tableview [cell bringSubviewToFront:cell.button]; for the different buttons to the same result.
Hopefully Helpful Facts:
-I tried setting all of the background colors of all of the views in the hierarchy to different colors so I could visually debug it at runtime... it looked exactly as expected. No overlaps or coverings. (This was limited to only views in the cell)
-Here is all of the settings for the TableView:
-I tried to load this in the new XCode 6 to use the visual debugger but the 7.1 simulator included with it actually ran the code perfectly so I could debug it...
-Here is the dequeueing code in the VC:
NiTGroupTimeCell* cell = (NiTGroupTimeCell*)[tableView dequeueReusableCellWithIdentifier:ident forIndexPath:indexPath];
-Here is the code in the viewDidLoad of the VC to set up the cell nib with the table(it's 2 because this is the from scratch one):
[self.timesTable registerNib:[UINib nibWithNibName:#"NiTGroupTimeCell2" bundle:nil] forCellReuseIdentifier:#"GroupTime"];
-All connections were made via IB. These are all using IBAction or IBOutlet.
-I have NSLog statements in all button methods to test if they are actually called, but I have also tested with breakpoints. All are never triggered in testing.
-The only TableView delegate or datasource methods implemented are as follows:
-(int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
-As per suggestion I took Revel to it and found that a mystery UILabel and UIImageView were in the view.... but as you can see their frames are all zeros so they shouldn't be getting in the way of anything so back to where we were I'm afraid:
UILabel frame:
UIImageView frame:
IIRC I counted this off as a Simulator bug before, but since it's happening on the user's device it must be an actual issue and it's holding up my pipeline so help would be GREATLY appreciated! Thanks in advance!
PS I'm happy to post whatever, but because of all the shifting in debugging I didn't know exactly what people would want to see and I didn't want to overload this post because I knew it was going to be long with everything else.
So apparently the issue was these lines of code(in diff format from my git diff output):
--(int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
+-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
and
--(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
+-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
so yeah... seems that in iOS7+ if you have the "old" output types for these datasource methods it'll look fine but bork your tableview functionally... good times, but hey it's fixed now^^ hopefully this helps others.
I would suspect that there's an issue with your custom UITableViewCell subclass, NiTGroupTimeCell, or with the IBAction connections from the nib to the tableViewCell subclass.
I also wonder about the extra empty UILabel and UIImageView. They sound like the default properties declared in UITableViewCell.h, UIImageView *imageView and UILabel *textLabel. The fact that they're getting instantiated (and aren't nil) could be a clue as to the weird, unexpected behavior you're seeing.
Do you have IBOutlets to the UIButtons? What about changing properties (in code) for the buttons (such as background color) to make sure you actually are retaining them in the NiTGroupTimeCell.
You're saying that you tried [self.contentView addSubview:button] but your button in your first image is inside a view inside contentView. Try linking an IBOutlet to that view, then try [nameOfView addSubview];
Throwing a wild guess as it looks like you have covered pretty much everything else.
You said:
I load up that has a tableview in it that I resize based on how many rows are in it
And you posted a screen shot saying the clip subviews is off on the UITableView
Are you setting the frame of the tableview incorrectly but its showing the cells anyway due the the subviews not being clipped?
Load up reveal again and check the height of the UITableView
Not sure if it is the case here. But if you name the custom cell outlets imageView, textLabel or any of the "built-in" UITableViewCell's properties you will get weird results and behavior.
You need to check couple of things:
Make sure all the parent views of the button have User Interaction enabled.
Check AutoSizing in the size inspector and make sure the button lies inside the view so it could receive touch events otherwise touch events will get ignore. You can verify it by changing the colour of the view. Changing colour or NSLog the frame of button and parent views will help you to troubleshoot if this is the problem.
Try to make things simpler and don't addSubView programmatically, if designing from IB.
Make sure some component is not overlapping the button with a clearColor background color.
What worked for me is this:
self.contentView.userInteractionEnabled = NO;
I called this after loading my custom cell from nib / storyboard. Without the userinteractionEnabled set to NO, my buttons haven't been responding to touches somehow. My contentView has received all touches and did not forward them to my buttons.
I've seen code where
[cell bringSubviewToFront:button]
has been used as a workaround, for me it did not solve the issue.
I had a simillar issue, while adding Custom Acions based on Guestures.
I was adding Action Button on runtime in Inherited class of UITableViewCell
The bahaviour was if I add buttons outside the visible rect, after animating buttons inside, I was unable to click / tap. But in My Case I was able to Tap / Click if buttons were added in visible rect.
What Worked for me, I added those buttons in View instead of ContentView of UITableViewCell, then animated only Content View. You may try somthing simillar
-- Vishal
You've said that there are no TouchRecognizers(TapRecognizers?), but I think you should double-check that, and look not only for touch recognizers but for any recognizers in controller that uses that cell,even added to self.view/tableView.
I was recently trying to find out why cells don't select(delegate method wasn't called) only to find out that I've added 2 gesture recognizers(in code, those were necessary for other things, but I had to do that in other way) that would prevent cell selection.
Also the sign of it may be that if you hold button long enough(put breakpoint there so you can make it easier), action will fire.

iOS development Animating Table view custom cell content

I am working on new application and i would like to have custom table view. I need to have cell that have 2 labels 1 check box and 2 buttons. The problem i have is that 2 buttons need to be shown only if user press edit button on top. I made all this to work but i have some problem with reusable cells or something like that.
I made custom cell class so i can assign data to it.
First state is: First state on img
Then when user press edit button on top i need everyting to animate and come to right place.
I want text to animate to right to make space for button, delete button needs to come animated from left side and edit butom to come in animated from right side.
This is what i want to get after animations are done: Second state on img
I made all this to work but now i have problem that first 2 cells that will come on screen after i scroll down are not effected by my code :(
This is what i get: Third state on img
i will post my project code here and if some1 can help me with it i would be more then thrilled. I point me to right way to do this.
Code downoald: https://www.mediafire.com/?g1g6d7h33mpkyt7
and i will post some code here that i think is crucial to my problem:
for animations i use:
[cell.infoView setFrame:CGRectMake(20, CGRectGetMinY(cell.infoView.frame), CGRectGetWidth(cell.infoView.frame), CGRectGetHeight(cell.infoView.frame))];
[UIView animateWithDuration:0.4
delay:0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
[cell.infoView setFrame:CGRectMake(70, CGRectGetMinY(cell.infoView.frame), CGRectGetWidth(cell.infoView.frame), CGRectGetHeight(cell.infoView.frame))];
}
completion:nil];
for cell init i use:
CICustomCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:CellTableIdentifier];
if(cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"HCICustomCell" owner:nil options:nil];
cell = [nib objectAtIndex:0];
}
cell.itemName = [dwarves objectAtIndex:indexPath.row];
cell.quantity = 25.99;
for table init i use:
UITableView *tableView = (id)[self.view viewWithTag:1];
tableView.rowHeight = 60;
UINib *nib = [UINib nibWithNibName:#"HCICustomCell"
bundle:nil];
[tableView registerNib:nib forCellReuseIdentifier:CellTableIdentifier];
img: http://i270.photobucket.com/albums/jj109/lazardj/scsimg.jpg~original
EDIT:
I also tried something now. If i start my activity then scroll down a bit so i get some new cells i dont have this problem. So it must be something with creating cells or reusability of cells or something like that. I am new to ios development so i cant figure this out on my own :( so please help :) Thanks
In your cellForRow function in your tableview delegate you need to deal with the location of your labels. So every time you request a new (or reused) cell you need to check whether you are in edit mode and then set the labels frames accordingly.
It appears as you are already doing this for the buttons, as they show up in the proper place, but the labels are being re-used at their initial locations (when they were released by the tableview).
I've had a look at your project, and the problem appears to stem from using AutoLayout. The automatic constraints appear to be interfering with your view layouts. If you go to your HCICustomCell.xib file and click on the file inspector tab, you'll see a checkbox for "Use Autolayout". Uncheck this and then set the auto-resizing constraints manually for each view in the Size Inspector tab. I've uploaded a revised version of your project here.
SOLUTION:
I done some more work on this. Tried solutions you provided me but there are still times when it gets bugged so i came with my own one. I figured out that the problem is that you cant move view in cell on first init but you can show hide them. So i decided to try to make same info view on place where it needs to be when enable is on. When enable is off its hidden and when enable is on it shows up. This is what fixed my problem :) I know its not the smartest way to do things but i managed to do what i wanted and its not messing performances of application.
This is project with fixed bugs. If any1 want can use it :)
Thanks for all your time and suggestions.
Project: https://www.mediafire.com/?uhatbh8c20xu49v

Issue with overlapping text: iOS7

I normally post source code and examples of UI but I think its more related to an iOS7 change and I cant see it being a code bug (yet). I would have to post so much code and UI that it would be counter productive. So here is my best non-visual description:
Since upgrading a project to iOS7 I am finding that if I put call to change a UILabel or calling setText of a UIButton in a ViewDidAppear or ViewWillAppear it puts the new text right on top of the old text.
Since developing for iOS I have never had to do anything different. If I do this:
lblMyHours.text = #"12";
It shouldnt just throw that on top of my existing label.
This especially happens inside of a UITableView where I have created an iVar for a UILabel thats in a UITableViewCell. If a user makes an adjustment to a value after clicking on a cell (it takes them to a detail screen to edit), when I pop back I have it recalculate in ViewDidAppear. In that recalculating I am resetting a label like the above. But it doesnt clear out the old.
You might be adding a new label every time you return a new cell.
You should just replace the text of the current label instead.
There are two way to achieve this, one you are already doing and as #Guilherme rightly pointed out. The other way is to create a custom tableview cell and put the UILabel property in there. As for the viewDidAppear scenario, you can create a uilabel in ther .h file (in the #interface declaration) and then initialize it in ViewDidLoad method and simple use in ViewDidAppear method without having to declare it again.
I would suggest that you follow the way I described for ViewDidAppear issue, and for the UITableView issue, search for UILabels in subview of the cell everytime cellForRowAtIndex method is called and remove it from the subview, something like this before adding a new label
for(UIView *view in cell.subviews)
{
if([view isKindOfClass:[UILabel class]])
{
[view removeFromSuperview];
}
}
Hope this helps.

Resources