corneliusdavid 214 Posted September 10, 2021 I've got a very simple cross-platform app with a TListView on the main form and when you click on an item, it should fire an event which takes the user to the next tab and displays details about the item that was clicked. I want to use OnItemClick so that it updates the current record of a memory table it's hooked to via LiveBindings. For the Windows platforms, this works perfectly as expected. On iOS, there is no OnItemClick event fired. On Mac, I can use the arrow key, then the space bar to activate it but not the mouse. I tried this a couple of days ago with Delphi 10.4.2, found a reported issue that was supposedly fixed in 10.4.1 (I can't find the issue now), and just tried it again today in Delphi 11 but I still have the same problem. Does TListView's click events behave differently on mobile devices? Is there a separate event I can use if I want to use the Accessory Button instead? I've found lots of information to configure viewing data in a TListView but not much in responding to events. Any clues would be most appreciated. Share this post Link to post
Guest Posted September 11, 2021 7 hours ago, corneliusdavid said: Any clues would be most appreciated. I don't have an answer for this per se, but i have a workaround for completely different problem that might give you an insight or be a food for thought to solve this. I love one particular feature in Listbox (VCL) which is the sliding feature when you hold the left mouse button down and move it over items, but it doesn't support or trigger any item selection event or changes until the mouse button up, so i use this to trigger/simulate item select in this case. procedure TForm1.ListBox1Click(Sender: TObject); begin //Memo1.Lines.Add('Clicked '+IntToStr(ListBox1.ItemIndex)); end; var LastItem: Integer = -1; procedure TForm1.ListBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var CurrentItem: Integer; ListBox: TListBox absolute Sender; begin CurrentItem := ListBox.ItemIndex; if (CurrentItem > -1) and (CurrentItem <> LastItem) then begin // Trigger/Simulate ItemSelect here for CurrentItem Memo1.Lines.Add('Selected ' + ListBox.Items[CurrentItem]); LastItem := CurrentItem; end; end; I don't know about ListView behaviour on iOS if it will handle mouse movement in way allowing such usage, but i think you got the idea, also not a fan of LiveBindings but might be easier to use a similar approach then trigger an event accordingly. Share this post Link to post
corneliusdavid 214 Posted September 12, 2021 Thanks for this suggestion. There is an ItemClickEx event I can hook into that does work the same on all platforms and gives me the ItemIndex to the list view items. I guess I need to figure out how to get at the properties of the item. It's not a simple Text field but a variable list of objects and object types. I was hoping to be able to use something simpler. Share this post Link to post
Serge_G 87 Posted September 13, 2021 On 9/10/2021 at 11:22 PM, corneliusdavid said: For the Windows platforms, this works perfectly as expected. On iOS, there is no OnItemClick event fired. On Mac, I can use the arrow key, then the space bar to activate it but not the mouse. I don't have any Apple devices but on Androïd OnItemClick works fine. for IOS : what about onTap or Gesture management 1 Share this post Link to post
corneliusdavid 214 Posted September 13, 2021 I tried OnTap but it doesn't indicate which item was clicked. I was playing around and enabled a property that got OnItemClick to work on Mac/iOS! Tomorrow, I'll have to go back carefully and hunt down which property did the trick. Share this post Link to post
Rollo62 536 Posted September 13, 2021 29 minutes ago, corneliusdavid said: I tried OnTap but it doesn't indicate which item was clicked. I rely on ItemClickEx only, for all purposes, this works best IMHO. Share this post Link to post
skyzoframe[hun] 4 Posted September 13, 2021 (edited) Here what I use.: by the way.. I don't know, if it works on iOS. Android was fine for me. unit ListViewTap; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls, FMX.ListView.Types, FMX.ListView.Appearances, FMX.ListView.Adapters.Base, FMX.ListView, FMX.Objects, FMX.TabControl, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.IB, FireDAC.Phys.IBDef, FireDAC.FMXUI.Wait, Data.DB, FireDAC.Comp.Client; type TForm1 = class(TForm) ListView01: TListView; lbError: TLabel; sbtExit01 : TSpeedButton; sbtShowAll: TSpeedButton; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } public procedure MainSetup; {$IFDEF ANDROID} procedure SetupGestures_ListView01; procedure Gestures_ListView01(Sender: TObject; const EventInfo: TGestureEventInfo; var Handled: Boolean); {$ELSE} {$IFDEF MSWINDOWS} procedure ListView01Click(Sender: TObject); {$ENDIF} {$ENDIF} end; var Form1: TForm1; implementation {$R *.fmx} {$R *.LgXhdpiPh.fmx ANDROID} {$R *.Surface.fmx MSWINDOWS} //uses SharedGlobals, CRUDL_Work20; {$region 'FormCreate & FormDestroy'} procedure TForm1.FormCreate(Sender: TObject); begin MainSetup; {$IFDEF ANDROID} lbError.Text := 'Android'; ListView01.OnGesture := Self.Gestures_ListView01; {$ELSE} {$IFDEF MSWINDOWS} lbError.Text := 'MSWindows'; ListView01.OnClick := Self.ListView01Click; {$ENDIF} {$ENDIF} end; procedure TForm1.FormDestroy(Sender: TObject); begin // do something end; procedure TForm1.sbtExit01Click(Sender: TObject); begin {$IFDEF ANDROID} Application.Terminate; {$ENDIF} {$IFDEF MSWINDOWS} // mtWarning -> Warns the user about a potential issue. // mtError -> Informs the user of an error that occurred. // mtInformation -> Provides information to the user. // mtConfirmation -> Ask the user for confirmation. // mtCustom -> None of the above. if MessageDlg('Realy exit?', TMsgDlgType.mtConfirmation, [TMsgDlgBtn.mbYes,TMsgDlgBtn.mbNo], 0) = mrYes then begin Application.Terminate; end; {$ENDIF} end; procedure TForm1.MainSetup; begin {$IFDEF ANDROID} sbtShowAll.TintColor := TAlphaColors.Aqua; {$ENDIF} {$IFDEF MSWINDOWS} sbtShowAll.IsPressed := Boolean(1); {$ENDIF} end; {$region 'Android_Setup'} {$IFDEF ANDROID} procedure TForm1.SetupGestures_ListView01; begin ListView01.Touch.InteractiveGestures := [TInteractiveGesture.DoubleTap, //Similar to a double-click. One of the basic survival rules in ZombieLand. //TInteractiveGesture.TwoFingerTap, // The "Two Finger Tap" gesture; requires two fingers. //TInteractiveGesture.PressAndTap, // The "Press And Tap" gesture; requires two fingers, one to hold pressed and one to tap. TInteractiveGesture.LongTap]; // The "Long Tap" gesture (also known as "Tap and hold", "Long Press" or "Press"); requires just one finger. Elicits a command such as Copy (for a picture), text editing commands or the TMagnifierGlass (for TMemo). end; procedure TForm1.Gesture_ListView01(Sender: TObject; const EventInfo: TGestureEventInfo; var Handled: Boolean); begin if ListView01.Selected <> nil then begin case EventInfo.GestureID of igiLongTap : begin lbError.Text := ('Long Tap: ' + ListView01.Selected.Index.ToString); //do something end; igiDoubleTap: begin lbError.Text := ('Double Tap: ' + ListView01.Selected.Index.ToString); //do something end; end; end; end; {$ENDIF} {$endregion} {$region 'MSWindows_setup'} {$IFDEF MSWINDOWS} procedure TForm1.ListView01Click(Sender: TObject); begin lbError.Text := 'Click'; end; {$ENDIF} {$endregion} end. Edited September 13, 2021 by skyzoframe[hun] Share this post Link to post
Rollo62 536 Posted September 13, 2021 (edited) 51 minutes ago, skyzoframe[hun] said: I don't know, if it works on iOS. Android was fine for me. In ancient past versions I had some issues from time to time, on various platforms, not sure what the root cause of them was. Anyway, I only can say that since I moved completely to ItemClickEx I had no more issues. Maybe everything is OK now, in the last Delphi versions. Edited September 13, 2021 by Rollo62 Share this post Link to post
corneliusdavid 214 Posted September 13, 2021 I checked the difference in my form and no properties changed from what works now and what didn't the other day. I'm wondering if simply changing a property, compiling, then changing it back activated something in the compilation that should've been enabled in the first place. I've seen this once before in a different component (I don't remember which). I still want to learn more about the sub-properties of the TListItemDrawable item returned in the OnItemClickEx event but for now, ItemClick is working--and simpler to use. Share this post Link to post
Rollo62 536 Posted September 14, 2021 Simpler, yes, but the "Ex" receives also more information Especially the ItemObject is quite handy, to select the right sub-component in the TListItem, which you are interested in. Share this post Link to post
skyzoframe[hun] 4 Posted September 14, 2021 I think everything goes wrong, when you want to use "ListView1.SearchVisible :=True" properities. ListView indexes are then unusable. If the ListView Index must be the same as the database index, then I use the tag properties. item := ListView1.Items.Add; item.Index := YourDatabaseIndex; // (After the search, it will be changed!) item.Tag := YourDatabaseIndex; //integer // or item.Objects.FindObjectT<TListItemText>('INDEX').Text := YourDatabaseIndex.ToString; //and if you search, and wanted the selected item database indexes procedure TForm2.ListView1ItemClickEx(const Sender: TObject; ItemIndex: Integer; const LocalClickPos: TPointF; const ItemObject: TListItemDrawable); begin Label1.text := Itemindex.ToString; (After the search, it will be changed!) Label2.Text := Listview1.Selected.Tag.ToString; end; Share this post Link to post
Rollo62 536 Posted September 14, 2021 Why, it looks OK to me. The index shows the entries from 0 ... nn, the Tag determines what item you have. If you filter, then the index might change, I think that is correct. Share this post Link to post
corneliusdavid 214 Posted September 14, 2021 4 hours ago, Rollo62 said: Simpler, yes, but the "Ex" receives also more information True, but digging through the sub-properties to get what I want is so much more work than simply grabbing the value from the memory table to which it's attached. There might be times when this is necessary but I'd much rather use LiveBindings get the original value from the table. By the way, the working project is on GitHub under the name, AppPaths. 1 Share this post Link to post
Rollo62 536 Posted September 15, 2021 (edited) I think you could bind the Tag property too, with LiveBindings. For me the whole LB thing is also still very much unclear, whats it's BestPractices are, to get best results out of it. Until now: "Handle with care" Edited September 15, 2021 by Rollo62 1 Share this post Link to post