On Gesture
When building a mobile app in FMX, I had an issue getting pinch-to-zoom working.
A common approach to mobile development in FMX is to use a single form with multiple views implemented as frames. These views can be docked in and out as required, and the approach works very well.
However, no matter what I tried, I couldn't get pinch-to-zoom working. In the end, the solution was simple and should have been obvious to me. I had to hook into the actual Form's OnGesture event.
Hooking into the Form
When a view is docked, I register the gesture handler:
procedure TPictureView.Docked(const aFileName, aTitle: string);
begin
// preserve the main form configuration
fOnGesture := Form.OnGesture;
fGestures := Form.Touch.InteractiveGestures;
// take control of zoom
Form.Touch.InteractiveGestures :=
Form.Touch.InteractiveGestures + [TInteractiveGesture.Zoom];
Form.OnGesture := OnFormGesture;
end;
When the view is undocked, the gesture handler is unregistered:
procedure TPictureView.Undocked;
begin
// restore the main form configuration
Form.OnGesture := fOnGesture;
Form.Touch.InteractiveGestures := fGestures;
end;
Pinch and Zoom Handler
Next, the code in the view's OnFormGesture method handles the pinch-to-zoom gesture.
We intercept the zoom gesture and delegate the remaining gestures to the form's original handler:
procedure TPictureView.OnFormGesture(
Sender: TObject;
const EventInfo: TGestureEventInfo;
var Handled: Boolean);
begin
// handle pinch-to-zoom
if EventInfo.GestureID = igiZoom then
begin
if (not (TInteractiveGestureFlag.gfBegin in EventInfo.Flags)) and
(not (TInteractiveGestureFlag.gfEnd in EventInfo.Flags)) then
begin
var img := imgPicture;
var center := img.Position.Point + PointF(img.Width / 2, img.Height / 2);
img.Width := Max(img.Width + (EventInfo.Distance - fLastDistance), 10);
img.Height := Max(img.Height + (EventInfo.Distance - fLastDistance), 10);
img.Position.X := center.X - img.Width / 2;
img.Position.Y := center.Y - img.Height / 2;
end;
// remember the distance for the next zoom event
fLastDistance := EventInfo.Distance;
Handled := true;
exit;
end;
// delegate other gestures to the form's original handler
if Assigned(fOnGesture) then
fOnGesture(Sender, EventInfo, Handled);
end;
Sample Project
Delphi ships with a sample project called ImageZoom:
# Delphi 13.1 Samples folder
C:\Users\Public\Documents\Embarcadero\Studio\37.0\Samples\
# The ImageZoom example can be found in this subdirectory
Object Pascal\Mobile Snippets\InteractiveGestures\ImageZoom