have an UITableView with index and when I scroll to bottom load more cell from server,the problem is that when I try to add more cells shows "assertion failed" error, this is how I was trying to add cells.
Note: Table view source its modified and without adding more cell works fine
List<ICContactTableItem>items,itemsAdd;
Dictionary<string, List<ICContactTableItem>> indexedTableItems;//parameter in tableviewsource
string[] keys;//parameter in tableviewsource
UITableView tableContact;
public void addContacts(){
InvokeOnMainThread (delegate {
try{
tableContact.BeginUpdates();
int count=items.Count;
List<NSIndexPath> tmpArray = new List<NSIndexPath>();
foreach(ICContactTableItem item in itemsAdd){
if(item.firstName.Length>0){
if (indexedTableItems.ContainsKey (item.firstName[0].ToString ())) {
indexedTableItems [item.firstName [0].ToString ()].Add (item);
NSIndexPath tmpIndexPath = NSIndexPath.FromRowSection(
indexedTableItems[item.firstName [0].ToString ()].Count-1,
getIndex(item.firstName [0].ToString ()));
tmpArray.Add(tmpIndexPath);
} else {
indexedTableItems.Add (item.firstName [0].ToString (), new List<ICContactTableItem> () { item });
tableContact.InsertSections(NSIndexSet.FromIndex(getIndex(item.firstName [0].ToString ()))
,UITableViewRowAnimation.None);
NSIndexPath tmpIndexPath = NSIndexPath.FromRowSection(
indexedTableItems[item.firstName [0].ToString ()].Count-1,
getIndex(item.firstName [0].ToString ()));
tmpArray.Add(tmpIndexPath);
}
}else{
if (indexedTableItems.ContainsKey (" ")) {
indexedTableItems [" "].Add (item);
NSIndexPath tmpIndexPath = NSIndexPath.FromRowSection(
indexedTableItems[" "].Count,
getIndex(" "));
tmpArray.Add(tmpIndexPath);
} else {
indexedTableItems.Add (" ", new List<ICContactTableItem> () { item });
indexedTableItems [" "].Add (item);
tableContact.InsertSections(NSIndexSet.FromIndex(getIndex(" "))
,UITableViewRowAnimation.None);
NSIndexPath tmpIndexPath = NSIndexPath.FromRowSection(
indexedTableItems[" "].Count,
getIndex(" "));
tmpArray.Add(tmpIndexPath);
}
}
}
keys=indexedTableItems.Keys.ToArray();
items.AddRange(itemsAdd);
tableContact.InsertRows(tmpArray.ToArray(),UITableViewRowAnimation.None);
tableContact.EndUpdates();
tableContact.ReloadData();
tableContact.SetNeedsLayout();
}catch(Exception e){
Console.WriteLine(e.StackTrace);
}
ICLayoutMgr.Get().SetBusy(false);
});
}
int getIndex (string str)
{
string[] keysOrdered = indexedTableItems.Keys.ToArray();
int res = 0;
for (int i = 0; i < keysOrdered.Length; i++) {
if (keysOrdered [i] == str) {
res = i;
}
}
return res;
}
Before you make any calls to tell the table to add or remove any rows, you must update your data source with by adding or removing data. The table will check how many sections and rows there are before and after your add/remove rows. The number of sections and rows after the change must properly reflect how much data you add/remove with how many rows you add/remove.
And of course you must implement the NumberOfRowsInSection method.
Related
I already have a dataprovider method to read data - i.e it will loop through the excel using two for loops and put that into an object array.
Now I want to simplify it instead of using for loops.
I have tried the following, but dont know how to put that into an object array.
New code:
data = new String[rowCount][columnCount];
DataFormatter format = new DataFormatter();
// loop through the rows
sheet.forEach(row -> {
row.forEach(cell -> {
String cellValue = format.formatCellValue(cell);
});
old code:
// loop through the rows
for(int i=1; i <rowCount+1; i++){
try {
XSSFRow row = sheet.getRow(i);
for(int j=0; j <columnCount; j++){ // loop through the columns
try {
String cellValue = "";
try{
Cell cel = row.getCell(j);
cellValue = format.formatCellValue(cel);
}
catch(NullPointerException e){
}
data[i-1][j] = cellValue; // add to the data array
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
I used the monotouch.dialog to develop one PrivateMsg talk screen. But when I reload the cell , the cell flicker, how to avoid it ?
add new pm msg accross 2 step: 1. append a element cell: State.Insert(msg is sending)=> 2. reload the element cell status: State.Updated(msg send sucessced)
Pls find the attachment:screen recording file and the source code:
void HandleOnPMChanged(object sender, PMChangedEventArgs e)
{
if (e.PMSID != this.mPMSession.PMSID)
return;
this.BeginInvokeOnMainThread(() =>
{
if (e. State == State.Insert) //step1
{
element = this.GetNewPMElement(itemData);
pmSection.Add(element);
this.ScrollToBottomRow();
} else if (e.State == State.Update && e.PM != null) //step2
{
var element = FindElement(e.PM.Guid.GetHashCode());
if (element != null)
{
var indexPaths = new NSIndexPath [] { element.IndexPath };
this.TableView.ReloadRows(indexPaths, UITableViewRowAnimation.None); //this line will flicker
//remark: this.ScrollToBottomRow();
}
}
else if (e. State == State.Insert)
{
element = this.GetNewPMElement(itemData);
pmSection.Add(element);
this.ScrollToBottomRow(); //step1
}
});
}
public void ScrollToBottomRow()
{
try
{
if (pmSection.Count < 1)
return;
NSIndexPath ndxPath = pmSection[pmSection.Count - 1].IndexPath;
if (ndxPath != null)
this.TableView.ScrollToRow(ndxPath, UITableViewScrollPosition.Bottom, false); //Bottom, false);
}
catch (Exception ex)
{
Util.ReportMsg("PMDVC ScrollToBottomRow Exception:", ex.Message);
}
}
issue has been fixed.
EstimatedHeight return bigger than actual value.
I'm hoping to get a little bit of insight on show / hide functionality in gmaps4rails.
example functionality
// == shows all markers of a particular category, and ensures the checkbox is checked ==
function show(category) {
for (var i=0; i<gmarkers.length; i++) {
if (gmarkers[i].mycategory == category) {
gmarkers[i].setVisible(true);
}
}
// == check the checkbox ==
document.getElementById(category+"box").checked = true;
}
// == hides all markers of a particular category, and ensures the checkbox is cleared ==
function hide(category) {
for (var i=0; i<gmarkers.length; i++) {
if (gmarkers[i].mycategory == category) {
gmarkers[i].setVisible(false);
}
}
// == clear the checkbox ==
document.getElementById(category+"box").checked = false;
// == close the info window, in case its open on a marker that we just hid
infowindow.close();
}
// == a checkbox has been clicked ==
function boxclick(box,category) {
if (box.checked) {
show(category);
} else {
hide(category);
}
// == rebuild the side bar
makeSidebar();
}
function myclick(i) {
google.maps.event.trigger(gmarkers[i],"click");
}
// == rebuilds the sidebar to match the markers currently displayed ==
function makeSidebar() {
var html = "";
for (var i=0; i<gmarkers.length; i++) {
if (gmarkers[i].getVisible()) {
html += '<a href="javascript:myclick(' + i + ')">' + gmarkers[i].myname + '<\/a><br>';
}
}
document.getElementById("side_bar").innerHTML = html;
}
So, in my controller, I'm building a list of markers, and including their categories as json.
#markersLoc = #locSearch.to_gmaps4rails do |loc, marker|
letter.next!
marker_image = "http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=#{letter}|82ABDD|000000"
marker.infowindow render_to_string(partial: '/events/info',
locals: {object: loc})
marker.picture({picture: marker_image,
width: 32,
height: 32,
marker_anchor: [11,30],
shadow_picture: "http://chart.apis.google.com/chart?chst=d_map_pin_shadow",
shadow_width: 110,
shadow_height: 110,
shadow_anchor: [12,34]})
marker.title loc.what
marker.sidebar render_to_string(partial: '/events/sidebar',
locals: {object: loc, letter: marker_image})
marker.json({cat: loc.category})
end
I'm kind of stuck, here. I know the :cat string is available (ex: 1,3,4), but I'm not sure how to use it to achieve what I'm after.
Was able to pretty much use what was there, with some modification. This gave me functionality to have 9 categories (could be more or less), and only view what I want. Awesome.
// == shows all markers of a particular category, and ensures the checkbox is checked ==
function show(category) {
var regEx = new RegExp("[" + category + "]")
for (var i=0; i<Gmaps.map.markers.length; i++) {
if (Gmaps.map.markers[i].cat) {
if (Gmaps.map.markers[i].cat.match(regEx)) {
Gmaps.map.showMarker(Gmaps.map.markers[i]);
}
}
}
// == check the checkbox ==
document.getElementById(category+"box").checked = true;
}
// == hides all markers of a particular category, and ensures the checkbox is cleared ==
function hide(category) {
var regEx = new RegExp("[" + category + "]")
for (var i=0; i<Gmaps.map.markers.length; i++) {
if (Gmaps.map.markers[i].cat) {
if (Gmaps.map.markers[i].cat.match(regEx)) {
Gmaps.map.hideMarker(Gmaps.map.markers[i]);
}
}
}
// == clear the checkbox ==
document.getElementById(category+"box").checked = false;
// == close the info window, in case its open on a marker that we just hid
// Gmaps.map.infowindow.close();
}
// == a checkbox has been clicked ==
function boxclick(box,category) {
if (box.checked) {
show(category);
} else {
hide(category);
}
}
I'm trying to write a test script using automation in xcode 4.5.
I have a UICollectionView and I want to click on some cell not currently visible.
Per documentation, I should expect cells to return all cells in the collection view, and visibleCells to return only the currently visible ones.
Instead what I'm seeing is that cells returns only the currently visible cells, and calling visibleCells stops the script on 'undefined' is not a function (evaluating 'collection.visibleCells()')
var target = UIATarget.localTarget();
var collection = target.frontMostApp().mainWindow().collectionViews()[0];
UIALogger.logMessage("Looking in collection: " + collection);
UIALogger.logMessage("Cells: " + collection.cells() + " length " + collection.cells().length);
UIALogger.logMessage("Visible cells: " + collection.visibleCells());
The code above returns the right UICollectionView, second log line prints:
Cells: [object UIAElementArray] length 12
although I have 100 items in the collection view, and third log line crashes script.
Is this a documentation/UIACollectionView bug?
Any ideas how can I tell the automation to scroll until it sees a cell with the name "My cell"?
I've tried using someCell.scrollToVisible, but I need to have the cell to do that, and I don't since I can't get it from cells.
EDIT:
As suggested by Jonathan I've implemented a scroll-till-found function.
it's a bit implementation specific, so you'll probably need to tweak isCellWithName.
I'm also looking to add a break in case we didn't find the needed cell in the while loop, if anyone has ideas, feel free to edit this.
function isCellWithName(cell, name) {
return (cell.staticTexts()[0].name() == name);
}
function getCellWithName(array, name) {
for (var i = 0; i < array.length; i++) {
if (isCellWithName(array[i], name)) {
return array[i];
}
}
return false;
}
function scrollToName(collection, name) {
var found = getCellWithName(collection.cells(), name);
while (found === false) {
collection.dragInsideWithOptions({startOffset:{x:0.2, y:0.99}, endOffset:{x:0.2, y:0},duration:1.0});
found = getCellWithName(collection.cells(), name);
}
return found;
}
The documentation is apparently incorrect. There is no visibleCells() method on UIACollectionView. I figured this out by looping over all the collection view elements properties and printing out their names:
var target = UIATarget.localTarget();
var window = target.frontMostApp().mainWindow();
var collectionView = window.collectionViews()[0];
for (var i in collectionView) {
UIALogger.logMessage(i);
}
Table view elements, on the other hand, do list all the cells with the cells() method. I'm wondering if they choose not to do this because of the much more complicated nature of collection views. It could be very expensive to actually fetch all the collection view cells, build their representations and frames, and return the elements if you had a lot of them. That's what UI Automation does when it asks table views for all the cells. They have to all be instantiated and calculated in order to get the element representations.
But, to answer your larger question, how to scroll to a specific cell. Can you consistently scroll it into view with a swipe gesture? It's not the most convenient way to do it and we're "spoiled" by the ability to scroll to non-visible elements with table views. But from a user behavior testing standpoint, swiping a certain amount is what the user would have to do anyway. Could the test be structured to reflect this and would it address your need?
I couldn't get the the #marmor dragInsideWithOptions() bit to work in a generic fashion. Instead, I'm using the collectionView's value() function to get an index of the current page vs. last page, as in "page 3 of 11". Then I use collectionView's scrollUp() and scrollDown() methods to walk through the pages until we find what we're after. I wrote an extension for TuneUp's uiautomation-ext.js that seem to do the trick, and more:
function animationDelay() {
UIATarget.localTarget().delay(.2);
}
extend(UIACollectionView.prototype, {
/**
* Apple's bug in UIACollectionView.cells() -- only returns *visible* cells
*/
pageCount: function() {
var pageStatus = this.value();
var words = pageStatus.split(" ");
var lastPage = words[3];
return lastPage;
},
currentPage: function() {
var pageStatus = this.value();
var words = pageStatus.split(" ");
var currentPage = words[1];
//var lastPage = words[3];
return currentPage;
},
scrollToTop: function() {
var current = this.currentPage();
while (current != 1) {
this.scrollUp();
animationDelay();
current = this.currentPage();
}
},
scrollToBottom: function() {
var current = this.currentPage();
var lastPage = this.pageCount();
while (current != lastPage) {
this.scrollDown();
animationDelay();
current = this.currentPage();
}
},
cellCount: function() {
this.scrollToTop();
var current = this.currentPage();
var lastPage = this.pageCount();
var cellCount = this.cells().length;
while (current != lastPage) {
this.scrollDown();
animationDelay();
current = this.currentPage();
cellCount += this.cells().length;
}
return cellCount;
},
currentPageCellNamed: function(name) {
var array = this.cells();
for (var i = 0; i < array.length; i++) {
var cell = array[i];
if (cell.name() == name) {
return cell;
}
}
return false;
},
cellNamed: function(name) {
// for performance, look on the current page first
var foundCell = this.currentPageCellNamed(name);
if (foundCell != false) {
return foundCell;
}
if (this.currentPage() != 1) {
// scroll up and check out the first page before we iterate
this.scrollToTop();
foundCell = this.currentPageCellNamed(name);
if (foundCell != false) {
return foundCell;
}
}
var current = this.currentPage();
var lastPage = this.pageCount();
while (current != lastPage) {
this.scrollDown();
animationDelay();
current = this.currentPage();
foundCell = this.currentPageCellNamed(name);
if (foundCell != false) {
return foundCell;
}
}
return false;
},
/**
* Asserts that this collection view has a cell with the name (accessibility identifier)
* matching the given +name+ argument.
*/
assertCellNamed: function(name) {
assertNotNull(this.cellNamed(name), "No collection cell found named '" + name + "'");
}
});
I have a jqGrid in an ASP.NET MVC View with the option multiselect:true. There are over 200 records displayed in the grid, so I have paging enabled. This works great, but when I navigate from page to page, the selections are lost when I navigate.
Is there a good, clean way to persist the selections so that they are maintained while paging?
Managed it with some javascript trickery:
var pages = [];
onSelectRow: function(rowid, status) {
var pageId = $('#grdApplications').getGridParam('page');
var selRows = [];
if (status) {
//item selected, add index to array
if (pages[pageId] == null) {
pages[pageId] = [];
}
selRows = pages[pageId];
if (selRows.indexOf(rowid) == -1)
{ selRows.push(rowid); }
}
else {
//item deselected, remove from array
selRows = pages[pageId];
var index = selRows.indexOf(rowid)
if (index != -1) {
pages[pageId].splice(index, 1);
}
}
},
loadComplete: function() {
if (pages[$('#grdApplications').getGridParam('page')] != null) {
var selRows = pages[$('#grdApplications').getGridParam('page')];
var i;
var limit = selRows.length;
for (i = 0; i < limit; i++) {
$('#grdApplications').setSelection(selRows[i], true);
}
}
},
user279248 (I know it's an old post, but it's a good question) - all of the row ids are being stored in the selRows arrays in the pages array, so just iterate through them, ie
for (j=0;j<pages.length;j++) {
var selRow = pages[j];
for (k=0;k<selRow.length;k++) {
alert('RowID:'+selRow[k]);
}
}
Hope this helps someone.
Dave - your solution is still going strong two years later! Thanks for the code. My only tweak is elevating the code into functions - useful to apply to multiple grids on the same page.
function maint_chkbxs_oSR(obj_ref, rowid, status, pages) {
var pageId = $(obj_ref).jqGrid('getGridParam','page');
var selRows = [];
if (status) {
//item selected, add index to array
if (pages[pageId] == null) {
pages[pageId] = [];
}
selRows = pages[pageId];
//if (selRows.indexOf(rowid) == -1)
if ($.inArray(""+rowid,selRows) == -1)
{ selRows.push(rowid); }
}
else {
//item deselected, remove from array
selRows = pages[pageId];
var index = $.inArray(""+rowid,selRows);
if (index != -1) {
pages[pageId].splice(index, 1);
}
}
}
function maint_ckbxs_lC(obj_ref, pages) {
if (pages[$(obj_ref).jqGrid('getGridParam','page')] != null) {
var selRows = pages[$(obj_ref).jqGrid('getGridParam','page')];
var i;
var limit = selRows.length;
for (i = 0; i < limit; i++) {
//$('#grid_bucket').setSelection(selRows[i], true);
$(obj_ref).jqGrid('setSelection',selRows[i],true);
}
}
}
You just have to remember to create a dedicated page array for each grid.