iOS Tutorial TableView with custom items

iTableView v1.20 adds support for custom items.

Each TableCell includes a CustomView property. You can set a Panel with views to this property and the panel will be added to the cell.

upload_2015-2-26_13-18-54.png


It is quite similar to CustomListView class. However TableView is more powerful.
Do note that when you create custom views your TableView will be limited to about 1000 items as each cell holds its own custom views (the standard cells are reused and therefore support any number of cells).

The attached example adds cells based on a designer layout file:
B4X:
For i = 1 To 50
     Dim tc As TableCell = tv.AddSingleLine("")
     tc.ShowSelection = False
     tc.CustomView = CreateItem
Next

Private Sub CreateItem As Panel
   Dim p As Panel
   p.Initialize("")
   p.Width = 100%x
   p.Height = tv.RowHeight
   p.LoadLayout("1")
   Return p
End Sub

You will usually want to explicitly set the RowHeight property before creating the items. The default value of this property is not useful for custom items.

The table cells are resized in the Page_Resize event. The TextField is anchored to both sides so it will fill the entire space when you rotate the device.
 

Attachments

  • TableViewWithCustomItems.zip
    4.2 KB · Views: 1,574

imbault

Well-Known Member
Licensed User
Longtime User
iTableView v1.20 adds support for custom items.

Each TableCell includes a CustomView property. You can set a Panel with views to this property and the panel will be added to the cell.

View attachment 32518

It is quite similar to CustomListView class. However TableView is more powerful.
Do note that when you create custom views your TableView will be limited to about 1000 items as each cell holds its own custom views (the standard cells are reused and therefore support any number of cells).

The attached example adds cells based on a designer layout file:
B4X:
For i = 1 To 50
     Dim tc As TableCell = tv.AddSingleLine("")
     tc.ShowSelection = False
     tc.CustomView = CreateItem
Next

Private Sub CreateItem As Panel
   Dim p As Panel
   p.Initialize("")
   p.Width = 100%x
   p.Height = tv.RowHeight
   p.LoadLayout("1")
   Return p
End Sub

You will usually want to explicitly set the RowHeight property before creating the items. The default value of this property is not useful for custom items.

The table cells are resized in the Page_Resize event. The TextField is anchored to both sides so it will fill the entire space when you rotate the device.

@Erel , this is very very usefull, I use it a lot, but how to scroll up the tableview to the right place in order to see the textfield when you are curently editing which is at the bottom (cause it's hidden by the keyboard), then scroll back at the original position?

Thx
Patrick
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
See this example:
B4X:
Sub Process_Globals
   Public App As Application
   Public NavControl As NavigationController
   Private Page1 As Page
   Private tv As TableView
   Private TextField1 As TextField
End Sub

Private Sub Application_Start (Nav As NavigationController)
   NavControl = Nav
   Page1.Initialize("Page1")
   Page1.RootPanel.LoadLayout("Main")
   NavControl.ShowPage(Page1)
   tv.Initialize("tv", False)
   Page1.RootPanel.AddView(tv, 0, 0, 100%x, 100%y)
   tv.RowHeight = 100 'must set RowHeight before adding custom views.
   For i = 1 To 50
     Dim tc As TableCell = tv.AddSingleLine("")
     tc.ShowSelection = False
     tc.CustomView = CreateItem (i - 1)
   Next
End Sub

Private Sub CreateItem (index As Int) As Panel
   Dim p As Panel
   p.Initialize("")
   p.Width = 100%x
   p.Height = tv.RowHeight
   p.LoadLayout("1")
   'TextField1 is a reference to the last text field loaded
   TextField1.Tag = index
   Return p
End Sub

Private Sub Page1_Resize(Width As Int, Height As Int)
   tv.SetLayoutAnimated(400, 0.5, 0, 0, 100%x, 100%y)
   For Each tc As TableCell In tv.GetItems(0)
     tc.CustomView.Width = 100%x
   Next
End Sub

Private Sub Page1_KeyboardStateChanged (Height As Float)
   
End Sub

Sub TextField1_BeginEdit
   Dim tf As TextField = Sender
   tv.ScrollTo(0, tf.Tag, tv.SCROLL_TOP)
End Sub

Sub btnClick_Click
   Dim btn As Button = Sender
   Dim no As NativeObject = btn
   Dim Parent As Panel = no.GetField("superview") 'get the button's parent
   Dim tf As TextField = Parent.GetView(1) 'this is the text field index (based on the order in the layout file).
   Dim sw As Switch = Parent.GetView(2)
   Msgbox("Switch value: " & sw.Value, "Name = " & tf.Text)
End Sub



Sub Page1_BarButtonClick (Tag As String)
   If Tag = "PrintAll" Then
     For Each tc As TableCell In tv.GetItems(0)
       Dim parent As Panel = tc.CustomView
       Dim tf As TextField = parent.GetView(1)
       Dim sw As Switch = parent.GetView(2)
       Log("Name = " & tf.Text)
       Log("Switch: " & sw.Value)
     Next
   End If
End Sub

It will scroll the text field to the top.
 

imbault

Well-Known Member
Licensed User
Longtime User
Looks good to me, I'm gonna try that.

Thx Erel
 
Last edited:

imbault

Well-Known Member
Licensed User
Longtime User
See this example:
B4X:
Sub Process_Globals
   Public App As Application
   Public NavControl As NavigationController
   Private Page1 As Page
   Private tv As TableView
   Private TextField1 As TextField
End Sub

Private Sub Application_Start (Nav As NavigationController)
   NavControl = Nav
   Page1.Initialize("Page1")
   Page1.RootPanel.LoadLayout("Main")
   NavControl.ShowPage(Page1)
   tv.Initialize("tv", False)
   Page1.RootPanel.AddView(tv, 0, 0, 100%x, 100%y)
   tv.RowHeight = 100 'must set RowHeight before adding custom views.
   For i = 1 To 50
     Dim tc As TableCell = tv.AddSingleLine("")
     tc.ShowSelection = False
     tc.CustomView = CreateItem (i - 1)
   Next
End Sub

Private Sub CreateItem (index As Int) As Panel
   Dim p As Panel
   p.Initialize("")
   p.Width = 100%x
   p.Height = tv.RowHeight
   p.LoadLayout("1")
   'TextField1 is a reference to the last text field loaded
   TextField1.Tag = index
   Return p
End Sub

Private Sub Page1_Resize(Width As Int, Height As Int)
   tv.SetLayoutAnimated(400, 0.5, 0, 0, 100%x, 100%y)
   For Each tc As TableCell In tv.GetItems(0)
     tc.CustomView.Width = 100%x
   Next
End Sub

Private Sub Page1_KeyboardStateChanged (Height As Float)
  
End Sub

Sub TextField1_BeginEdit
   Dim tf As TextField = Sender
   tv.ScrollTo(0, tf.Tag, tv.SCROLL_TOP)
End Sub

Sub btnClick_Click
   Dim btn As Button = Sender
   Dim no As NativeObject = btn
   Dim Parent As Panel = no.GetField("superview") 'get the button's parent
   Dim tf As TextField = Parent.GetView(1) 'this is the text field index (based on the order in the layout file).
   Dim sw As Switch = Parent.GetView(2)
   Msgbox("Switch value: " & sw.Value, "Name = " & tf.Text)
End Sub



Sub Page1_BarButtonClick (Tag As String)
   If Tag = "PrintAll" Then
     For Each tc As TableCell In tv.GetItems(0)
       Dim parent As Panel = tc.CustomView
       Dim tf As TextField = parent.GetView(1)
       Dim sw As Switch = parent.GetView(2)
       Log("Name = " & tf.Text)
       Log("Switch: " & sw.Value)
     Next
   End If
End Sub

It will scroll the text field to the top.

@Erel, Thx it works, one more thing, how to put the tableview back in its original state after editing
 

imbault

Well-Known Member
Licensed User
Longtime User
I mean the original position of the tableview, before the scroll_to in the :

B4X:
Sub TextField1_BeginEdit
   Dim tf As TextField = Sender
   tv.ScrollTo(0, tf.Tag, tv.SCROLL_TOP)
End Sub

In fact, saving the tableview scroll position in order to put it back after editing
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
You can use this code to find the first visible item:
B4X:
Sub GetTopItem(Table As TableView) As Int()
   Dim no As NativeObject = Table
   no = no.RunMethod("indexPathsForVisibleRows", Null).RunMethod("objectAtIndex:", Array(0))
   Return Array As Int(no.GetField("section").AsNumber, no.GetField("row").AsNumber)
End Sub

Dim top() As Int = GetTopItem(tv)
Log("Section = " & top(0) & ", Item = " & top(1))

With this information you can store the current visible item and later scroll back to this item.
 

imbault

Well-Known Member
Licensed User
Longtime User
You can use this code to find the first visible item:
B4X:
Sub GetTopItem(Table As TableView) As Int()
   Dim no As NativeObject = Table
   no = no.RunMethod("indexPathsForVisibleRows", Null).RunMethod("objectAtIndex:", Array(0))
   Return Array As Int(no.GetField("section").AsNumber, no.GetField("row").AsNumber)
End Sub

Dim top() As Int = GetTopItem(tv)
Log("Section = " & top(0) & ", Item = " & top(1))

With this information you can store the current visible item and later scroll back to this item.

Thx @Erel, but is there a property in tableview, to get it's scrolling position?
 

imbault

Well-Known Member
Licensed User
Longtime User
Not exactly. GetTopItem returns you the available information which is the top item. Later you can scroll to this item. The result will be the same.
ok @Erel , but there must be a way to detect the scrolling event of the tableview, I mean when the user scrolls down or up the view, in order to keep the current scroll position, to put it back after programmatically changing it to show the field when the keyboard appears, else, this is a mess...

Patrick
 

imbault

Well-Known Member
Licensed User
Longtime User
I'm sorry @Erel , but I do not understand where to put
B4X:
Dim top() As Int = GetTopItem(tv)
, here is my code, TextResult is one of the field of the tv ;

B4X:
Sub TextResultat_BeginEdit
   Dim tf As TextField = Sender
   Tv.ScrollTo(0, tf.Tag, Tv.SCROLL_TOP)
End Sub
Sub TextResultat_EndEdit
    Dim tf As TextField = Sender
    Dim no As NativeObject = tf
    updateRes_cmt(no)
    tf.ResignFocus
  
End Sub

Thank you Erel
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
I've tried it with this code and it works:
B4X:
Sub TextField1_BeginEdit
  Dim tf As TextField = Sender
  Dim topItem() As Int = GetTopItem(tv)
  currentTopItem = topItem(1)
  tv.ScrollTo(0, tf.Tag, tv.SCROLL_TOP)
End Sub

Sub TextField1_EndEdit
   If currentTopItem > 0 Then
     tv.ScrollTo(0, currentTopItem, tv.SCROLL_TOP)
   End If
End Sub
currentTopItem is a global int.
 

imbault

Well-Known Member
Licensed User
Longtime User
I'm enable to fire a TextField LongClick event on an element in a custom item...
bug or something else

Thanks
 

imbault

Well-Known Member
Licensed User
Longtime User
iTableView v1.20 adds support for custom items.

Each TableCell includes a CustomView property. You can set a Panel with views to this property and the panel will be added to the cell.

View attachment 32518

It is quite similar to CustomListView class. However TableView is more powerful.
Do note that when you create custom views your TableView will be limited to about 1000 items as each cell holds its own custom views (the standard cells are reused and therefore support any number of cells).

The attached example adds cells based on a designer layout file:
B4X:
For i = 1 To 50
     Dim tc As TableCell = tv.AddSingleLine("")
     tc.ShowSelection = False
     tc.CustomView = CreateItem
Next

Private Sub CreateItem As Panel
   Dim p As Panel
   p.Initialize("")
   p.Width = 100%x
   p.Height = tv.RowHeight
   p.LoadLayout("1")
   Return p
End Sub

You will usually want to explicitly set the RowHeight property before creating the items. The default value of this property is not useful for custom items.

The table cells are resized in the Page_Resize event. The TextField is anchored to both sides so it will fill the entire space when you rotate the device.
@Erel , so you think we can dynamically change the height of a select cell, like the calendar app of the iphone, when yo click on the beg on appointment, it changes the bellow cell height to put a Picker, after you select your stuff, the cell goes back to it's initial height

IMG_2398.PNG IMG_2399.PNG
 
Last edited:
Top