UIRefreshControl

I have a table-heavy app and my internal test users keep wanting to pull down on the table to “pull-to-refresh”. This seems to require a UIRefreshControl to do properly and, of course, we don’t have one in Xojo yet.

Have any of the declares gurus considered creating a UIRefreshControl that can be linked to an iOSTable to enable pull-to-refresh?

(I have created a Feedback case for this control to be added to a future version: <https://xojo.com/issue/37898>)

Well, I tried to implement this, and successfully created the class, however it cannot be added to the iOSTable as it is currently implemented because, to my surprise, Xojo does not use the native view controller for the iOSTable. Without the native view controller (UITableViewController) a UIRefreshControl cannot be added to the UITableView. Your feedback case is the best bet for now.

Edit: If you still want me to post the project even though it doesn’t work then let me know and I will add a link.

[quote=162622:@Jason King]Well, I tried to implement this, and successfully created the class, however it cannot be added to the iOSTable as it is currently implemented because, to my surprise, Xojo does not use the native view controller for the iOSTable. Without the native view controller (UITableViewController) a UIRefreshControl cannot be added to the UITableView. Your feedback case is the best bet for now.

Edit: If you still want me to post the project even though it doesn’t work then let me know and I will add a link.[/quote]

Are you sure it is not the native one ? Richard Berglund has created methods using setSeparatorColor and setSeparatorStyle that seem to work fine.

There was a problem with the ViewHandle of some classes mistakenly returning the handle of the object instead. If you install a ViewPtr via Declare, it should work.

The iOSTable IS native and is a UITableView, which is why Richard’s declares work properly.

To add the UIRefreshControl, you need an instance of UITableViewController. The view controller that manages the iOSTable is a XOJViewController with a superclass of UIViewController, not UITableViewController, so there is no way to add a UIRefreshControl at this time. Technically the XOJViewController is native, however it is not the native view controller that is generally used to manage a UITableView, and that is the problem here.

[quote=162640:@Jason King]The iOSTable IS native and is a UITableView, which is why Richard’s declares work properly.

To add the UIRefreshControl, you need an instance of UITableViewController. The view controller that manages the iOSTable is a XOJViewController with a superclass of UIViewController, not UITableViewController, so there is no way to add a UIRefreshControl at this time. Technically the XOJViewController is native, however it is not the native view controller that is generally used to

From what I understand the UIRefreshControl thing reloads data. Would that not be done by ReloadDataInSection ? Now the trick is to be able to detect the “Pull down” gesture described in the OP. Jason Tait, what is it exactly ?

Yes Michel, the issue isn’t reloading the data in the iOSTable, it is creating the “pull-to-refresh” effect found in so many apps.

The UIRefreshControl doesn’t actually reload any data, it just fires an event when pulled down to refresh. You use this event to do the physical reloading of data. The purpose of the UIRefreshControl is only to detect that gesture and then fire the corresponding event - I don’t think you will be able to capture it in any other way.

You/we will have to wait for Xojo to do something about this and implement the correct native view controller before it can be added, unfortunately. Maybe you can add a button to refresh for now, and then when Xojo fixes it you will only have to copy your code to the event handler of the UIRefreshControl?

If you want to look at what I tried, here it is:
https://www.dropbox.com/s/9lqhefuolth0kii/UIRefreshControll.xojo_binary_project?dl=0

Thank you Jason. I appreciate your efforts. I currently have some logic around activating the tab and the time since the last refresh that executes a refresh in a thread and I will consider whether a refresh button would also look OK.

If we had access to the scroll state of the table, we might be able to see when scroll gets negative ?

At any rate, ScrollPosition and ScrollTo are sorely missing in iOSTable.

37917 - iOSTable needs ScrollPosition and maybe ScrollTo
Status: Needs Review Rank: Not Ranked Product: Xojo Category: Compiler

Michel Bujardet Today at 1:00 AM
iOSTable needs a way to know the position at which the user has scrolled.

And, possibly, a way to set it as well through ScrollTo.

Please expose
Table View Scroll Position
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/#//apple_ref/c/tdef/UITableViewScrollPosition

and
ScrollToRowAtIndexPath
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/#//apple_ref/occ/instm/UITableView/scrollToRowAtIndexPath:atScrollPosition:animated:

<https://xojo.com/issue/37917>

Sorry, I was confused by Apple terminology. Their notion of ScrollPosition is not the Xojo one.

I believe what we need is VisibleCells
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/#//apple_ref/occ/instm/UITableView/visibleCells

Which allows finding out which is the currently first row visible to the user.

Just a thought…

  • scroll the topmost TableCell out of sight, so it is invisible. (must be done by declares)
  • scroll up: (this makes the top cell visible.)
  • change the text of this cell to “refreshing…”
  • do some refreshing stuff
  • when done loading:
  • change the text of the topmost cell to “done
  • scroll the list back to the 2nd visible cell.

This might mimic the pull-down-to-reload functionality.

I haven’t tested this. This was just a thought.
You may want to subclass the iosTableList to add event definitions and custom methods and stuff like that.

I stumbled into this old post and tried the project shared by Jason.

The code now works if you use:

[code] //get the view controller
declare function isKindOfClass lib UIKitLib selector “isKindOfClass:” (obj_id as ptr, cls as ptr) as Boolean
declare function nextResponder lib UIKitLib selector “nextResponder” (obj_id as ptr) as ptr
dim responder as ptr = aTable.Handle

	declare sub setRefreshControl_ lib UIKitLib selector "setRefreshControl:" (obj_id as ptr, refreshControl as ptr)
	setRefreshControl_(responder, self)[/code]

In UIRefreshControl.EmbedIn

And there is absolutely no need to monitor the Table’s scroll position (contentOffset in obj-c).

Works like a charm! Thank you @JrmieLeroy and @JasonKing ! It’s been a long road but we got there in the end. This is going to make the updated UI in the new version of my app just that little bit sweeter. :slight_smile:

This is odd. The UIRefreshControl in my app has been working fine in the iOSSimulator and on my iPhone 6s but it’s now in alpha (using TestFlight) and, while it works fine for all of my iPhone and iPad test users, when one my of testers tries it on her iPod Touch (5th generation), it crashes out on startup and the crashlog reports that the crash occurs when calling the EmbedIn method as @JrmieLeroy posted above. It doesn’t make sense that this would just fail on an iPod Touch, does it?

Update: Also confirmed to crash at the same point on a second iPod Touch

Thank you Jean-Paul. I’ve never been any good at declares. I’ve tried to use addSubView like this (below) and now my app no longer crashes but the Table is empty so I’m guessing that I’m adding the refresh control in the wrong way. Any tips? :slight_smile:

//Different behaviour for iOS < 10
If SystemVersion < 10 Then
  Declare Sub addSubview Lib "foundation" selector "addSubview:" (id As Ptr, aView As Ptr)
  addSubview(Self, responder)
Else
  Declare Sub setRefreshControl_ Lib UIKitLib selector "setRefreshControl:" (obj_id As ptr, refreshControl As ptr)
  setRefreshControl_(responder, Self)
End

I’m confused about how to add this to a project. It seems like this should be straight forward.
I must be missing something.
I tried putting it in the open event of a iOSTable but it complains about the last “self”, and I’m not sure which handle it’s expecting.

Suggestions?

This seems to be promising for next xojo release
<https://xojo.com/issue/37898>

Can it be implemented as stated above or is there something broken?

Are you using iOSKit ?

If yes, then you need to drag a UIRefreshControl onto the iOSView.
In the RefreshControl open event add this code

UIRefreshControl1.EmbedIn(iOSTable1)

And make sure that UIRefreshControl class has this method:

[code]Public Sub EmbedIn(aTable as iOSTable)
//get the view controller
declare function isKindOfClass lib UIKitLib selector “isKindOfClass:” (obj_id as ptr, cls as ptr) as Boolean
declare function nextResponder lib UIKitLib selector “nextResponder” (obj_id as ptr) as ptr
dim responder as ptr = aTable.Handle

declare sub setRefreshControl_ lib UIKitLib selector “setRefreshControl:” (obj_id as ptr, refreshControl as ptr)
setRefreshControl_(responder, self)
End Sub
[/code]