Skip to content

Commit c9e8f19

Browse files
committed
improve TFMXImageSlider with Mikkao's change
1 parent b3c5dd8 commit c9e8f19

File tree

6 files changed

+215
-82
lines changed

6 files changed

+215
-82
lines changed

ComponentsSource/FMX.ImageSlider.pas

+120-57
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
// 4. add TimerInterval to control AutoSlider interval
2020
// 5. use ActivePage property move page, ex)ActivePage := 1
2121
// 6. add Datas property, can set tagstring on each page
22+
// 2018-03-21, v0.4.0.0 : merged with Mikkao's change 2018-03-01
23+
// 1. change OnPageChange event to TPageChangeEvent
24+
// 2. add OnPageAnimationFinish event
25+
// 3. add OnCanDragBegin event
2226

2327
unit FMX.ImageSlider;
2428

@@ -38,26 +42,35 @@ interface
3842
FMX.ComponentsCommon;
3943

4044
type
45+
TPageChangeEvent = procedure(Sender: TObject; NewPage, OldPage: Integer) of object;
46+
TPageAnimationFinishEvent = procedure(Sender: TObject; NewPage, OldPage: Integer) of object;
47+
TCanBeginDragEvent = procedure(Sender: TObject; var CanBegin: Boolean) of object;
4148

4249
[ComponentPlatformsAttribute(TFMXPlatforms)]
4350
TFMXImageSlider = class(TLayout)
4451
private
45-
FIsTimer : Boolean;
46-
FAutoSlider : Boolean;
47-
FTimer : TTimer;
48-
FContainer : TLayout;
49-
FPages : TList<TLayout>;
50-
FActivePage : Integer;
51-
FIsMove : Boolean;
52-
FStartDrag : Boolean;
53-
FDownPos : TPointF;
54-
FDownIndex : Integer;
55-
FAnimation : TFloatAnimation;
56-
FOnItemTap : TTapEvent;
57-
FOnItemClick : TNotifyEvent;
58-
FOnPageChanged: TNotifyEvent;
52+
FIsTimer: Boolean;
53+
FAutoSlider: Boolean;
54+
FTimer: TTimer;
55+
FContainer: TLayout;
56+
FPages: TList<TLayout>;
57+
FActivePage: Integer;
58+
FIsMove: Boolean;
59+
FStartDrag: Boolean;
60+
FBeforeDrag: Boolean;
61+
FDownPos: TPointF;
62+
FDownIndex: Integer;
63+
FPreviousPage: Integer;
64+
FAnimation: TFloatAnimation;
65+
FOnPageAnimationFinish: TPageAnimationFinishEvent;
66+
FOnCanDragBegin: TCanBeginDragEvent;
67+
FOnItemTap: TTapEvent;
68+
FOnItemClick: TNotifyEvent;
69+
FOnPageChange: TPageChangeEvent;
70+
procedure DoPageChange(NewPage, OldPage: Integer);
5971
procedure MoveToActivePage(IsIn: Boolean = True);
6072
procedure OnTimer(Sender: TObject);
73+
procedure AnimationFinished(Sender:TObject);
6174
function GetDatas(Index: Integer): string;
6275
function GetPageCount: Integer;
6376
function GetTimerInterval: Integer;
@@ -66,6 +79,7 @@ TFMXImageSlider = class(TLayout)
6679
procedure SetAutoSlider(const Value: Boolean);
6780
procedure SetPageCount(const Value: Integer);
6881
procedure SetDatas(Index: Integer; const Value: string);
82+
function SetDragBegin: Boolean;
6983
protected
7084
procedure SetTimerInterval(const Value: Integer);
7185
procedure Resize; override;
@@ -89,13 +103,15 @@ TFMXImageSlider = class(TLayout)
89103
property Height;
90104
property Position;
91105
property Width;
92-
property ActivePage : Integer read FActivePage write SetActivePage; //page move
93-
property AutoSlider : Boolean read FAutoSlider write SetAutoSlider; //auto slider property
94-
property PageCount : Integer read GetPageCount write SetPageCount;
95-
property TimerInterval : Integer read GetTimerInterval write SetTimerInterval; //auto slider timer
96-
property OnPageChanged : TNotifyEvent read FOnPageChanged write FOnPageChanged;
97-
property OnItemClick : TNotifyEvent read FOnItemClick write FOnItemClick; //page click event(use Desktop)
98-
property OnItemTap : TTapEvent read FOnItemTap write FOnItemTap; //page tab event(use Mobile, Pad)
106+
property ActivePage: Integer read FActivePage write SetActivePage; //page move
107+
property AutoSlider: Boolean read FAutoSlider write SetAutoSlider; //auto slider property
108+
property PageCount: Integer read GetPageCount write SetPageCount;
109+
property TimerInterval: Integer read GetTimerInterval write SetTimerInterval; //auto slider timer
110+
property OnCanDragBegin: TCanBeginDragEvent read FOnCanDragBegin write FOnCanDragBegin;
111+
property OnItemClick: TNotifyEvent read FOnItemClick write FOnItemClick; //page click event(use Desktop)
112+
property OnItemTap: TTapEvent read FOnItemTap write FOnItemTap; //page tab event(use Mobile, Pad)
113+
property OnPageChange: TPageChangeEvent read FOnPageChange write FOnPageChange;
114+
property OnPageAnimationFinish: TPageAnimationFinishEvent read FOnPageAnimationFinish write FOnPageAnimationFinish;
99115
end;
100116

101117
implementation
@@ -118,15 +134,14 @@ procedure TFMXImageSlider.Add(Value: String; Bitmap: TBitmap);
118134
Item.Height := Self.Height;
119135
Item.Stored := False;
120136
Item.Position.X := FPages.Count * Width;
121-
Item.Index := FPages.Add(Item);
137+
Item.Tag := FPages.Add(Item);
122138
Item.OnTap := DoTab;
123139
Img := TImage.Create(Item);
124140
Img.Parent := Item;
125141
Img.HitTest := False;
126142
Img.Align := TAlignLayout.Client;
127143
Img.Bitmap.Assign(Bitmap);
128144
Item.TagString := Value;
129-
//ActivePage := 0;
130145
FContainer.Width := FPages.Count * Width;
131146
FContainer.Position.X := 0;
132147
if FActivePage = -1 then
@@ -144,15 +159,14 @@ procedure TFMXImageSlider.Add(Value: String; Bitmap: TStream);
144159
Item.Height := Self.Height;
145160
Item.Stored := False;
146161
Item.Position.X := FPages.Count * Width;
147-
Item.Index := FPages.Add(Item);
162+
Item.Tag := FPages.Add(Item);
148163
Item.OnTap := DoTab;
149164
Img := TImage.Create(Item);
150165
Img.Parent := Item;
151166
Img.HitTest := False;
152167
Img.Align := TAlignLayout.Client;
153168
Img.Bitmap.LoadFromStream(Bitmap);
154169
Item.TagString := Value;
155-
//ActivePage := 0;
156170
FContainer.Width := FPages.Count * Width;
157171
FContainer.Position.X := 0;
158172
if FActivePage = -1 then
@@ -189,11 +203,13 @@ constructor TFMXImageSlider.Create(AOwner: TComponent);
189203
FAnimation.PropertyName := 'Position.X';
190204
FAnimation.Parent := FContainer;
191205
FAnimation.Duration := 0.1;
192-
FPages := TList<TLayout>.Create;
193-
HitTest := True;
194-
ActivePage := -1;
195-
FStartDrag := False;
196-
AutoCapture := True;
206+
FAnimation.OnFinish := AnimationFinished;
207+
FPages := TList<TLayout>.Create;
208+
HitTest := True;
209+
ActivePage := -1;
210+
FPreviousPage := -1;
211+
FStartDrag := False;
212+
AutoCapture := True;
197213
end;
198214

199215
destructor TFMXImageSlider.Destroy;
@@ -202,6 +218,12 @@ destructor TFMXImageSlider.Destroy;
202218
inherited;
203219
end;
204220

221+
procedure TFMXImageSlider.DoPageChange(NewPage, OldPage: Integer);
222+
begin
223+
if Assigned(FOnPageChange) then
224+
FOnPageChange(Self, NewPage, OldPage);
225+
end;
226+
205227
procedure TFMXImageSlider.DoTab(Sender: TObject; const Point: TPointF);
206228
begin
207229
if Assigned(FOnItemTap) then FOnItemTap(Sender, Point);
@@ -225,12 +247,14 @@ function TFMXImageSlider.GetTimerInterval: Integer;
225247
procedure TFMXImageSlider.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
226248
begin
227249
inherited;
228-
FIsTimer := FTimer.Enabled;
229-
if FIsTimer then FTimer.Enabled := False;
230-
FIsMove := False;
250+
FIsTimer := FTimer.Enabled;
251+
if FIsTimer then
252+
FTimer.Enabled := False;
253+
FIsMove := False;
231254
if (PageCount > 0) and (Button = TMouseButton.mbLeft) then
232255
begin
233256
FStartDrag := True;
257+
FBeforeDrag := True;
234258
FDownPos := PointF(X, Y);
235259
FDownIndex := FActivePage;
236260
end;
@@ -243,7 +267,10 @@ procedure TFMXImageSlider.MouseMove(Shift: TShiftState; X, Y: Single);
243267
inherited;
244268
if FStartDrag then
245269
begin
246-
if Abs(FDownPos.X - X) > 5 then FIsMove := True;
270+
if FBeforeDrag and not SetDragBegin then
271+
exit;
272+
if Abs(FDownPos.X - X) > 5 then
273+
FIsMove := True;
247274
DeltaX := X - FDownPos.X;
248275
NewX := -FDownIndex * Width + DeltaX;
249276
FContainer.Position.X := NewX;
@@ -257,29 +284,43 @@ procedure TFMXImageSlider.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y
257284
inherited;
258285
if (not FIsMove) and FStartDrag then
259286
begin
260-
if FIsTimer then FTimer.Enabled := True;
287+
if FIsTimer then
288+
FTimer.Enabled := True;
261289
FStartDrag := False;
262-
if Assigned(FOnItemClick) then FOnItemClick(FPages[Self.ActivePage]);
263-
if Assigned(FOnItemTap) then FOnItemTap(FPages[Self.ActivePage], PointF(X, Y));
290+
if Assigned(FOnItemClick) then
291+
FOnItemClick(FPages[Self.ActivePage]);
292+
if Assigned(FOnItemTap) then
293+
FOnItemTap(FPages[Self.ActivePage], PointF(X, Y));
264294
Exit;
265295
end;
266296
if FStartDrag then
267297
begin
268298
FStartDrag := False;
269299
DeltaX := X - FDownPos.X;
270-
if (DeltaX > Width * 0.4) then
271-
begin
272-
if FActivePage > 0 then
273-
FActivePage := FActivePage - 1;
274-
end
275-
else if DeltaX < (-Width * 0.4) then
300+
if Abs(DeltaX) > Width * 0.4 then
276301
begin
277-
if FActivePage < PageCount - 1 then
278-
FActivePage := FActivePage + 1;
302+
if (DeltaX > 0) then
303+
begin
304+
if FActivePage > 0 then
305+
begin
306+
FPreviousPage := FActivePage;
307+
FActivePage := FActivePage - 1;
308+
DoPageChange(FActivePage, FPreviousPage);
309+
end;
310+
end
311+
else if (DeltaX < 0) then
312+
begin
313+
if FActivePage < PageCount - 1 then
314+
begin
315+
FPreviousPage := FActivePage;
316+
FActivePage := FActivePage + 1;
317+
DoPageChange(FActivePage, FPreviousPage);
318+
end;
319+
end;
279320
end;
280321
MoveToActivePage(DeltaX < 0);
281-
if FIsTimer then FTimer.Enabled := True;
282-
if Assigned(FOnPageChanged) then Self.FOnPageChanged(Self);
322+
if FIsTimer then
323+
FTimer.Enabled := True;
283324
end;
284325
end;
285326

@@ -298,9 +339,10 @@ procedure TFMXImageSlider.MoveToActivePage(IsIn: Boolean);
298339
procedure TFMXImageSlider.Next;
299340
begin
300341
if FActivePage = FPages.Count - 1 then Exit;
342+
FPreviousPage := FActivePage;
301343
FActivePage := FActivePage + 1;
344+
DoPageChange(FActivePage, FPreviousPage);
302345
MoveToActivePage(True);
303-
if Assigned(FOnPageChanged) then Self.FOnPageChanged(Self);
304346
end;
305347

306348
procedure TFMXImageSlider.OnTimer(Sender: TObject);
@@ -312,9 +354,10 @@ procedure TFMXImageSlider.OnTimer(Sender: TObject);
312354
procedure TFMXImageSlider.Prev;
313355
begin
314356
if FActivePage = 0 then Exit;
357+
FPreviousPage := FActivePage;
315358
FActivePage := FActivePage - 1;
359+
DoPageChange(FActivePage, FPreviousPage);
316360
MoveToActivePage(False);
317-
if Assigned(FOnPageChanged) then Self.FOnPageChanged(Self);
318361
end;
319362

320363
procedure TFMXImageSlider.Resize;
@@ -331,23 +374,43 @@ procedure TFMXImageSlider.Resize;
331374
FPages[I].Width := Width;
332375
FPages[I].Height := Height;
333376
FPages[I].Position.X := I * Width;
334-
FPages[i].RecalcSize;
377+
FPages[I].RecalcSize;
335378
end;
336379
end;
337380

338381
procedure TFMXImageSlider.SetActivePage(const Value: Integer);
339382
var
340383
IsIn: Boolean;
341384
begin
385+
if (Value < 0) or (Value > FPages.Count - 1) then // check if value valid
386+
exit;
342387
if FActivePage <> Value then
343388
begin
344-
if FActivePage = -1 then FContainer.Position.X := 0
345-
else
346-
begin
347-
IsIn := FActivePage < Value;
348-
FActivePage := Value;
349-
MoveToActivePage(IsIn);
350-
end;
389+
IsIn := FActivePage < Value;
390+
FPreviousPage := FActivePage;
391+
FActivePage := Value; // set FActivePage
392+
DoPageChange(FActivePage, FPreviousPage);
393+
MoveToActivePage(IsIn);
394+
end;
395+
end;
396+
397+
procedure TFMXImageSlider.AnimationFinished(Sender: TObject);
398+
begin
399+
If Assigned(FOnPageAnimationFinish) then
400+
FOnPageAnimationFinish(Self, FActivePage, FPreviousPage);
401+
FBeforeDrag := True;
402+
end;
403+
404+
function TFMXImageSlider.SetDragBegin: Boolean;
405+
var
406+
CanBeginDrag: Boolean;
407+
begin
408+
Result := True;
409+
if Assigned(FOnCanDragBegin) then
410+
begin
411+
FBeforeDrag := False;
412+
FOnCanDragBegin(Self, CanBeginDrag);
413+
Result := CanBeginDrag;
351414
end;
352415
end;
353416

Demo/ImageSliderDemo/frmMainU.fmx

+28
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,32 @@ object frmMain: TfrmMain
163163
Text = 'Auto Slider'
164164
OnChange = IsAutoChange
165165
end
166+
object Memo1: TMemo
167+
Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
168+
DataDetectorTypes = []
169+
Align = Client
170+
Size.Width = 338.000000000000000000
171+
Size.Height = 159.000000000000000000
172+
Size.PlatformDefault = False
173+
TabOrder = 8
174+
Viewport.Width = 334.000000000000000000
175+
Viewport.Height = 155.000000000000000000
176+
end
177+
object ImgSlider: TFMXImageSlider
178+
Align = Top
179+
HitTest = True
180+
Size.Width = 338.000000000000000000
181+
Size.Height = 161.000000000000000000
182+
Size.PlatformDefault = False
183+
TabOrder = 10
184+
ActivePage = 0
185+
AutoSlider = False
186+
PageCount = 0
187+
TimerInterval = 5000
188+
OnCanDragBegin = ImgSliderCanDragBegin
189+
OnItemClick = ImgSliderItemClick
190+
OnItemTap = ImgSliderItemTap
191+
OnPageChange = ImgSliderPageChange
192+
OnPageAnimationFinish = ImgSliderPageAnimationFinish
193+
end
166194
end

0 commit comments

Comments
 (0)