I have this (now working) code based on bits I picked up various places:

procedure TFormMain.imgMapsGesture(Sender: TObject;
  const EventInfo: TGestureEventInfo; var Handled: Boolean);
var
  LObj: IControl;
  LImage: TImage;
  W: Single;
  H: Single;
begin
  LImage := nil;
  LObj := Self.ObjectAtPoint(ClientToScreen(EventInfo.Location));
  if (LObj is TImage) and (LObj.Visible) then
    begin
      LImage := TImage(LObj.GetObject);
      if (LImage <> imgMaps) then
        LImage := nil
      ;
    end
  ;
  if LImage = nil then
    Exit
  ;
  if LImage.Bitmap = nil then
    Exit
  ;
  case EventInfo.GestureID of
    igiZoom:
      begin
        if (EventInfo.Distance < 1) then
          Exit
        ;
        if
          (not(TInteractiveGestureFlag.gfBegin in EventInfo.Flags))
          and
          (not(TInteractiveGestureFlag.gfEnd in EventInfo.Flags))
        then
          begin
            W := LImage.Width + 2 * ((EventInfo.Distance - FLastDistanceZoom) / 3);
            H := LImage.Height + 2 * ((EventInfo.Distance - FLastDistanceZoom) / 3);
            if
              (W < layoutMapsContent.Width)
            or
              (H < layoutMapsContent.Height)
            then
              begin
                W := layoutMapsContent.Width;
                H := layoutMapsContent.Height;
              end
            ;
            LImage.Width := W;
            LImage.Height := H;
            FLastDistanceZoom := EventInfo.Distance;
          end
        ;
      end
    ;
igiPan:
  begin
    if
      (not(TInteractiveGestureFlag.gfEnd in EventInfo.Flags))
    then
      begin
        if (not(TInteractiveGestureFlag.gfBegin in EventInfo.Flags)) then
          begin
            LImage.Position.X := LImage.Position.X + (EventInfo.Location.X - FMapsLastPositionPan.X);
            LImage.Position.Y := LImage.Position.Y + (EventInfo.Location.Y - FMapsLastPositionPan.Y);
          end
        ;
        FMapsLastPositionPan.X := EventInfo.Location.X;
        FMapsLastPositionPan.Y := EventInfo.Location.Y;
      end
    ;
  end
;

I got zoom working fairly well (not in simulator though, but on iOS iPhone), however panning is not working at all. When panning in simulator I can see eventdisance is always 0. I have enabled pan + zoom geatures on the TImage.

有帮助吗?

解决方案

I doubt the code you picked up in various places actually works:

The documentation on TGestureInfo clearly states that

[...] Distance is only set for the zoom and two finger tap gestures (TInteractiveGesture = igZoom or igTwoFingerTap). [...]

That means that you will have to keep track of the position the finger was registered in the previous call of onGesture. You can then do something regarding the difference of EventInfo.Location then and EventInfo.Location now. Of course, this is only going to work if gfBegin is not in GestureEvent.Flags because you won't have a valid value for a previous position but you already know that.

Additionally, you might have a look at EventInfo.InertiaVector for "stuff continues moving for a bit when you lift your finger". But that's entirely optional.

Also, if you're handling a gesture (no matter if interactive or standard gesture), you should set Handled to True. This way, you don't risk another component trying to handle the gesture. But to be honest, I'm not exactly sure if this is also the case with FireMonkey. With Vcl, it is. Compare the documentation for FMX.Types.TInteractiveGestures with Vcl.Controls.TInteractiveGestureOption. Better safe than sorry.

其他提示

Hi I have been developing a custom fmx listbox with a scroll bar. I found that the pan interactive gesture event is handled differently between windows and ios. In ios TInteractiveGestureFlag.gfInertia flag isn't set for an inertia event the absence of the gfBegin and gfEnd flags indicate an inertia pan event is taking place.

fvscroll is a standard scroll bar component.

scmfx,scmfy are private class variables TopItem sets the topitem of my custom listbox ItemHeight is the height of a listbox item

procedure TFCListBox.FlickScroll(const Ev: TGestureEventInfo);
var
N:TDateTime;
dy,dx,dz,rad:single;
begin

if TInteractiveGestureFlag.gfBegin in ev.flags then
begin
  PanStartTime := N;
  PanStartEv := Ev;
  scrollstart := fvscroll.value;
  rad := DegToRad(RotationAngle);
  scmfx := sin(rad);
  scmfy := cos(rad);
end;
if (TInteractiveGestureFlag.gfInertia in ev.Flags) or (ev.Flags = []) then
begin
  dy := (Ev.Location.Y - PanStartEv.Location.y) *scmfy;
  dx := (Ev.Location.X - PanStartEv.Location.X) *scmfx;
  dz := dx - dy;
  fvscroll.Value := scrollstart + dz;
end;
if TInteractiveGestureFlag.gfEnd in ev.Flags then
begin
TopItem := Round(fvScroll.Value/ItemHeight);}

end;
end;

I hope this is helpful

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top