UICollectionView header/footer reference size crash - ios6

I am struggling with the following issue. I have a UICollectionView that has its layout's header and footer reference sizes set to a value (say 40.0). When I remove/insert cell and the collection view is at a position such that the header and footer are not onscreen everything is fine. However, when they are onscreen upon doing the same actions my code crashes with the following error:
2012-12-17 16:05:05.042 BambooV2Demo[37770:907] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** setObjectForKey: object cannot be nil (key: <_UICollectionViewItemKey: 0x1e04cf70> Type = SV Kind = UICollectionElementKindSectionHeader IndexPath = <NSIndexPath 0x1e04fe90> 2 indexes [0, 0])'
On the other hand if I set the header and footer sizes to be 0.0 everything is perfectly fine again. Does anyone have an idea for the reasons for the crash when the header/footer size is different from zero and they are visible on screen?

I was having this issue when I had set a header size, but without specifying a view for the header. Instead, I used the section insets and set the header size back to zero.

You should return YES in the Method below in your Layout Subclass or via the delegate, which will cause a rearranging of the CollectionView Items to your layout.
- (BOOL) shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}

Related

Extracting tableViewCell Widths in an Array?

I woukld like to form an Array which contains the widths of each label inside the customTableCell. As illustrated in the attached image, I managed to extract all the widths I am interested in but they are not all in the same array. Any idea how can I extrac t all the widths in ONE array?
#BrunoPastre is correct, but appending is also not the way to assign the values in the array. This function will be run many times for some cells, as you scroll up and down. You will end up with the same widths listed many times at different places in the array.
You should create the array with the right dimension, then assign them as cellsWidthsArray[indexPath.row] = cell.cellTextLabel.frame.size.width.
You should create your array only once, not every time tableView(_: UITableView, cellForRowAt: IndexPath) -> UITableViewCell is called. This can be achieved by moving the declaration of your array, on line 83, to somewhere outside of the function scope, but inside the class scope, like line 92. When you do that, cellsWitdhsArray will become a class variable, or an attribute, that can be accessed from anywhere inside the class
That method is called once per cell, if you declare a local variable cellsWidthArray its not going to persist across multiple calls of that function.
What you need is to "save" this array somewhere that isn't a local, temporary scope. The best way to do this is to save it as a property on the class.
I can see in your code you already have another array thats a property: tableViewRowsInsideSectionsArray. Scroll up to (hopefully) the very top of the class declaration in the same scope add your own cellsWidthArray.
It should look something like
class MyViewController {
...
private var cellsWidthArray: [CGFloat] = []
...
That way that local array isn't lost every time the function ends - it's owned by the view controller and is available anywhere within that class as long as that class exists.
HOWEVER, it may not work as you expect because another issue with that method (tableView(cellForRowAt:) is that it's only called when a cell is being displayed (visible on the screen). And it will be called multiple times if you scroll a cell off and back on the screen.
You can solve potential duplication by creating a dictionary where the key is something uniquely identifying the cell (it seems like its just going to be the text here) and the value is the width. Something like:
class MyViewController {
...
private var cellsWidthDictionary: [String: CGFloat] = [:]
...
func tableView(cellForRowAt:) { // I didn't feel like typing it all out
...
cellsWidthDictionary[theTextYouAreUsing] = width
But you now have another issue, the way you are getting the width, accessing the frame of the label just after you set the text, might not actually be correct. This function just prepares the cell, auto layout and frame adjustments might happen later.
A simple one line solution one might be tempted to do is to force a layout on the cell, after setting the text on the label, something like:
cell.cellTextLabel.sizeToFit() or cell.layoutIfNeeded()
that will just adjust the frame of the label to perfectly wrap the existing content.. but a much better solution would be to actually calculate it..
You could use https://developer.apple.com/documentation/foundation/nsstring/1531844-size
something like
let labelSize = (label.text?.size(attributes: [NSFontAttributeName: UIFont(name: label.font.fontName , size: label.font.pointSize)!]))
then accessing labelSize.width
You're still left with the problem of only having that function called when a cell is about to be displayed on the screen. You can either manually scroll through every cell to build that table if you're using it for debugging/testing/informative purposes. But otherwise you would need to do something else...
Fortunately, Swift has a function that calculates the size a string would take - you just have to make sure you specify the text/font/size/any other styling elements. I pointed it out above... you can just iterate through all the strings that you're feeding into the cells and generate the dictionary right then and there as soon as you get the data.
Keep in mind this assumes a single line, if you have a max width for the label or other constraints that would cause the text to be cut off you would need to be even more explicit - I encourage you to google how to calculate the size of a label based off your needs if so.

How does isDisplayed() in protractor/webDriver work?

All of a sudden in our testing for our organization, the use of isDisplayed() just stopped being consistent.
Now it could be something that our Devs changed. But my question is what is isDisplayed() doing under the hood? What does it look for exactly? How does it work?
isDisplayed looks for the if the element is displyed in the browser screen. The display property tests whether any part of the element drawn is inside viewport. This is determined by the algorithm. In selenium it implemented as following.
/**
* Test whether this element is currently displayed.
*
* #return {!Promise<boolean>} A promise that will be
* resolved with whether this element is currently visible on the page.
*/
isDisplayed() {
return this.execute_(
new command.Command(command.Name.IS_ELEMENT_DISPLAYED));
}
IS_ELEMENT_DISPLAYED is itself an ENUM defined in the webdriver.CommandName.
The command is passed (IS_ELEMENT_DISPLAYED) uses the JsonWireProtocol to get the displayed property using the following get method:
session/:sessionId/element/:id/displayed
GET /session/:sessionId/element/:id/displayed
Determine if an element is currently displayed.
URL Parameters:
:sessionId - ID of the session to route the command to.
:id - ID of the element to route the command to.
Returns:
{boolean} Whether the element is displayed.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
From the W3C and JsonWireProtocol which is implemented by selenium. I have quoted it down. [https://w3c.github.io/webdriver/#element-displayedness]
"The approach recommended to implementors to ascertain an element's
visibility was originally developed by the Selenium project, and is
based on crude approximations about an element's nature and
relationship in the tree. An element is in general to be considered
visible if any part of it is drawn on the canvas within the boundaries
of the viewport.
The element displayed algorithm is a boolean state where true
signifies that the element is displayed and false signifies that the
element is not displayed. To compute the state on element, invoke the
Call(bot.dom.isShown, null, element). If doing so does not produce an
error, return the return value from this function call. Otherwise
return an error with error code unknown error."
Simple words as I learned:
If the element is not present in the DOM tree, call isDisplayed() will report NoSuchElementException, this is why protractor has isPresent() API.
If the element size is zero, selenium will treat it as not dispalyed even
set dispaly: block CSS on the element
element or its parent/ancestors' CSS value of display set to none (display: none), the element is not displayed.

Coded UI - How do we find if something exists when IsVisible, Exists, TryGetClickablePoint etc all return true when I can't see the control?

I am testing a WPF application and am not privy to it's exact workings but I am finding many instances where I need to find if a control is shown. All the traditional answers on this on Stack Overflow and MS forums etc say to use one of the following ...
IsVisible,
Exists,
TryGetClickablePoint,
State (e.g. OffScreen
The problem is that for this system, many controls return true for all of those even when the control cannot be seen! They also return a point with co-ordinates (-1, -1, -1, -1) whether the control is visible or not.
The only thing I have had any success with is using a try catch finally. I try to click on the control and if that fails, I go in to the catch block. That takes 60 seconds to time out though and I am getting intermittent issues with tests that run 9 times out of 10. Maybe the constant use of try catch is causing performance issues.
Is there an approach that actually works when all the standard approaches fail? I have noticed lots of other people asking these question are also testing WPF. Is there something WPF developers are doing to hide controls that makes CodedUI think they are still present and visible etc. Are they just behind something?
Many thanks in advance.
The solution was two-fold. Firstly I had to find the element and this was not working properly with my recorded steps. The element was buried too deeply in the system under test which is WPF (XAML). Secondly I had to prove I had found the element and for this I can't use TryGetClickablePoint, Exists, Top or Width. None of them seemed to work properly at all for my element. I had to use State.
public void Assert_MyElementShown()
{
#region Variable Declarations
WpfCustom uISurfaceCustom = this.UISysUnderTestClientShWindow.UIItemCustom1.UISurfaceCustom;
WpfCustom uIYAxisLabelsCustom = new WpfCustom();
#endregion
//Find the Element using it's Container and SearchProperties
uIYAxisLabelsCustom.Container = uISurfaceCustom;
uIYAxisLabelsCustom.SearchProperties[WpfControl.PropertyNames.ClassName] = "Uia.AxisLabelControl";
uIYAxisLabelsCustom.SearchProperties[WpfControl.PropertyNames.AutomationId] = "YAxisLabels";
//Use the State to find if it's on screen or not
var state = uIYAxisLabelsCustom.State;
if (state == Microsoft.VisualStudio.TestTools.UITest.Extension.ControlStates.Default)
{
//Element is visible, do stuff here!
}
else if (state == Microsoft.VisualStudio.TestTools.UITest.Extension.ControlStates.Offscreen)
{
//The control may exist, it may have location on screen and may even
//appear to be clickable according to coded ui framework but is is NOT
//shown on the screen.
}
}
You can try this approach for your application..if control properties are showing true for viable than we can go for height and width.Means if control is not visible in UI and but still all properties are showing true than check control height and width must be in -ve number.Than we can keep a assertion like
If control.height<0
Not visible in UI

Corona SDK: Display text object has text and is visible, but width is nil

I am trying to create a text display, but for some reason the width of the object is nil, despite the fact that it has text. Here is my code:
File1.lua:
local myTextDisplay = display.newText("2", display.contentWidth / 2, display.contentHeight / 2, native.systemFontBold)
File2.lua:
local myTextDisplay = File1:getTextDisplay() --function in File1.lua that returns myTextDisplay
print("Displayed text: " .. myTextDisplay.text)
if myTextDisplay.isVisible then print("Text display is visible") end
print("Text display width: " .. myTextDisplay.width)
The first time I open the File2 scene, this works fine, and prints:
Displayed text: 2
Text display is visible
Text display width: 10.6599...
However, when I open the same scene a second time (it is not recycled), the last print statement causes a runtime error:
Displayed text: 2
Text display is visible
Runtime error
C:\....myGame.lua:20: attempt to concatenate field 'width' (a nil value)
How can this be? If the display object contains text, how can it possibly have a nil width? Does it have something to do with the fact that I am getting the same display object each time I open the non-recycled File2 scene? Any advice appreciated!
I haven't been able to fix the original issue, but I think that there may be some problems inherent in passing display objects between scenes, especially when one scene is recycled.
Instead, I found the best workaround to be simply having two display objects, one in each scene. Then I pass the text and other properties of the object from the first scene to the second scene, and create the second display object to be identical to the first.
Passing data between scenes seems to work much more smoothly than passing display objects.

Expand specific rows in Angular-ui-grid

I'm using angular-ui-grid 3.0.5 with the treeview extension to display a tree. The data loads normally, everything works as expected, except that expandRow fails silently.
My use case is this: suppose we have a path like a > b > c and I need c shown to the user as preselected. I know the selection is correctly done because when I manually expand the parent rows, the child row is indeed selected.
Should I call expandAllRows, all rows would be expanded. However, calling expandRow with references on rows a and b taken from gridOptions.data leads to nothing happening: all rows will remain collapsed.
Is there any precaution to be taken that I have maybe overlooked, or is this a bug?
There's one mention in a closed issue that may be related to this but problem I'm having, but I'm not even sure it's related, given how dry the comment/solution was.
There's no example of using expandRow in the documentation but it's in both the API and the source code.
The gridRow objects mentioned in the documentation http://ui-grid.info/docs/#/api/ui.grid.treeBase.api:PublicApi are not the elements you put into the data array (though this seems to be not explained anywhere).
What the function expects is an object that the grid creates when building the tree, you can access them by looping through the grids treeBase.tree array. This will only be valid when the grid has built the tree, it seems, so it is not directly available when filling in the data, that's why registering a DataChangeCallback helps here https://github.com/angular-ui/ui-grid/issues/3051
// expand the top-level rows
// https://github.com/angular-ui/ui-grid/issues/3051
ctrl.gridApi.grid.registerDataChangeCallback(function() {
if (ctrl.gridApi.grid.treeBase.tree instanceof Array) {
angular.forEach(ctrl.gridApi.grid.treeBase.tree, function(node) {
if (node.row.treeLevel == 0) {
ctrl.gridApi.treeBase.expandRow(node.row);
}
});
}
});
self.onContentReady = function (e) {
e.component.expandRow(e.component.getKeyByRowIndex(0));
e.component.expandRow(e.component.getKeyByRowIndex(1));
};
selec which row you wanna expand

Resources