Skip to content

Commit ca5e335

Browse files
committed
Add swipe to images and set as default method
1 parent 4dd9773 commit ca5e335

File tree

5 files changed

+177
-110
lines changed

5 files changed

+177
-110
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ npm install nativescript-ng2-carousel --save
4242

4343
3. To use the CarouselDirective, create a template that applies the directive as an attribute to a paragraph GridLayout element:
4444
<pre>
45-
&lt;GridLayout [carousel]="images" carouselLabelOverlay="true" carouselSpeed="2000"&gt;
45+
&lt;GridLayout [carousel]="images"
46+
carouselLabelOverlay="true"
47+
carouselSpeed="2000"
48+
(selectedImageChange)="select($event)"&gt;
4649

4750
&lt;/GridLayout&gt;
4851
</pre>
@@ -133,8 +136,11 @@ Currently directive supported attributes:
133136
* **carousel** list of images as JSON or CarouselSlide class, accepted parameters (title?, url?, file?)
134137
* **carouselSpeed** _(optional)_ defines the interval (number in ms) to wait before the next slide is shown
135138
* **carouselAnimationSpeed** _(optional)_ defines the animation speed (number in ms)
139+
* **arrowsEnabled** _(optional)_ Show arrows to navigate the carousel (default false since swipe it's preferred)
136140
* **carouselArrows** _(optional)_ arrow type, accepted values _none_, _small_, _normal_, _bold_ or _narrow_ (default _normal_)
137141
* **carouselLabelOverlay** _(optional)_ silde title over image, accepted values _true_ or _false_ (default false)
142+
* **selectedImageChange** _(optional)_ get the title of the selected image (key)
143+
* **currentElementHiglhtColor** _(recommended)_ background color to apply to the current element
138144

139145
## Changelog
140146

nativescript-ng2-carousel.ts renamed to nativescript-ng2-carousel-swipeable.ts

Lines changed: 114 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
1-
import {Directive, ElementRef, AfterViewInit, Input} from '@angular/core';
2-
import {AnimationCurve} from "ui/enums";
1+
import {AfterViewInit, Directive, ElementRef, EventEmitter, Input, Output} from '@angular/core';
32
import {Image} from "ui/image";
43
import {StackLayout} from "ui/layouts/stack-layout";
54
import {GridLayout, ItemSpec} from "ui/layouts/grid-layout";
6-
import {GridUnitType} from "ui/layouts/grid-layout";
7-
import {HorizontalAlignment} from "ui/enums";
85
import {Label} from "ui/label";
9-
import {GestureTypes} from "ui/gestures";
6+
import {GestureTypes, SwipeGestureEventData} from "ui/gestures";
107
import {View} from "ui/core/view";
11-
import {Visibility} from "ui/enums";
12-
import {fromFile} from "image-source";
13-
import {fromResource} from "image-source";
8+
import {fromFile, fromResource} from "image-source";
149

1510
@Directive({selector: '[carousel]'})
1611
export class CarouselDirective implements AfterViewInit {
1712

13+
private static TRANSPARENT: string = "#FFFFFF";
14+
1815
private static animationSpeedDefault: number = 400; // in ms
1916
private static autoPlaySpeedDefault: number = 0; // in ms
2017

@@ -27,18 +24,23 @@ export class CarouselDirective implements AfterViewInit {
2724

2825
// Private control attributes
2926
private direction: CarouselDirections = null;
30-
private currentImage: number = 0;
3127
private movingImages: boolean = false;
32-
private indexMoveLeft: number = null;
33-
private indexMoveRight: number = null;
34-
private indexMoveCenter: number = null;
28+
29+
// My pointers
30+
private currentImage: number = 0;
31+
private nextImage: number = null;
32+
private nextNextImage: number = null;
3533

3634
// Options
3735
@Input() carousel: any;
3836
@Input() carouselSpeed: number; // autoplay speed (ms)
3937
@Input() carouselArrows: string; // arrows type
38+
@Input() arrowsEnabled: boolean = false; // enable arrows [default to false]
4039
@Input() carouselLabelOverlay: boolean; // title over image (bool)
4140
@Input() carouselAnimationSpeed: number; // animation speed
41+
@Input() currentElementHiglhtColor: string;
42+
43+
@Output() selectedImageChange: EventEmitter<string> = new EventEmitter<string>();
4244

4345
constructor(private elem: ElementRef) {
4446
this.container = elem.nativeElement;
@@ -49,8 +51,12 @@ export class CarouselDirective implements AfterViewInit {
4951
this.initContainer();
5052
this.initImagesLayout();
5153
this.initSlides();
52-
this.initControls();
54+
// Prefer swipe over arrows tap
55+
if (this.arrowsEnabled === true) {
56+
this.initControls();
57+
}
5358
this.initAutoPlay();
59+
console.log(`${this.currentElementHiglhtColor}`)
5460
}
5561

5662
/**
@@ -100,10 +106,8 @@ export class CarouselDirective implements AfterViewInit {
100106
* Init carousel layout
101107
*/
102108
private initContainer() {
103-
this.container.horizontalAlignment = "center";
109+
this.container.horizontalAlignment = "left";
104110
this.container.addRow(new ItemSpec(1, "auto"));
105-
this.container.addColumn(new ItemSpec(1, "star"));
106-
this.container.addColumn(new ItemSpec(1, "star"));
107111
}
108112

109113
/**
@@ -112,10 +116,30 @@ export class CarouselDirective implements AfterViewInit {
112116
private initImagesLayout() {
113117
this.totalItems = this.carousel.length;
114118
this.carouselSlides = new GridLayout();
115-
GridLayout.setColumnSpan(this.carouselSlides, 2);
119+
GridLayout.setColumnSpan(this.carouselSlides, 3);
120+
this.carouselSlides.addColumn(new ItemSpec(1, 'auto'));
121+
this.carouselSlides.addColumn(new ItemSpec(1, 'auto'));
122+
this.carouselSlides.addColumn(new ItemSpec(1, 'auto'));
116123
this.container.addChild(this.carouselSlides);
117124
}
118125

126+
private initVisibility(index: number) {
127+
return index === 0 || index === 1 || index === 2 ? "visible" : "collapse";
128+
}
129+
130+
private getInitColPos(index: number) {
131+
switch (index) {
132+
case 0:
133+
return 0;
134+
case 1:
135+
return 1;
136+
case 2:
137+
return 2; // could be any value between 0-2 since would be collapse
138+
139+
}
140+
}
141+
142+
119143
/**
120144
* Init carousel sliders provided in "carousel" directive attribute
121145
*/
@@ -124,23 +148,59 @@ export class CarouselDirective implements AfterViewInit {
124148

125149
let gridLayout = new GridLayout();
126150
gridLayout.addRow(new ItemSpec(1, "auto"));
127-
gridLayout.visibility = i == 0 ? "visible" : "collapse";
151+
gridLayout.visibility = this.initVisibility(i);
152+
153+
if (i === 0 ) {
154+
gridLayout.backgroundColor = this.currentElementHiglhtColor;
155+
}
128156

157+
let image: Image;
129158
if (slide.url) {
130-
let image: Image = CarouselDirective.generateImageSliderFromUrl(slide.url);
159+
image = CarouselDirective.generateImageSliderFromUrl(slide.url);
160+
image.on(GestureTypes.tap, () => {
161+
this.selectedImageChange.emit( slide.title );
162+
});
163+
image.on(GestureTypes.swipe, (args: SwipeGestureEventData) => {
164+
if (args.direction === 1) {
165+
this.swipe(CarouselDirections.DIRECTION_LEFT);
166+
} else if (args.direction === 2) {
167+
this.swipe(CarouselDirections.DIRECTION_RIGHT);
168+
}
169+
});
131170
gridLayout.addChild(image);
132171
}
133172

134173
if (slide.file && slide.file.indexOf('res://') !== 0) {
135-
let image: Image = CarouselDirective.generateImageSliderFromFile(slide.file);
174+
image = CarouselDirective.generateImageSliderFromFile(slide.file);
175+
image.on(GestureTypes.tap, () => {
176+
this.selectedImageChange.emit( slide.title );
177+
});
178+
image.on(GestureTypes.swipe, (args: SwipeGestureEventData) => {
179+
if (args.direction === 1) {
180+
this.swipe(CarouselDirections.DIRECTION_LEFT);
181+
} else if (args.direction === 2) {
182+
this.swipe(CarouselDirections.DIRECTION_RIGHT);
183+
}
184+
});
136185
gridLayout.addChild(image);
137186
}
138187

139188
if (slide.file && slide.file.indexOf('res://') === 0) {
140-
let image: Image = CarouselDirective.generateImageSliderFromResource(slide.file);
189+
image = CarouselDirective.generateImageSliderFromResource(slide.file);
190+
image.on(GestureTypes.tap, () => {
191+
this.selectedImageChange.emit( slide.title );
192+
});
193+
image.on(GestureTypes.swipe, (args: SwipeGestureEventData) => {
194+
if (args.direction === 1) {
195+
this.swipe(CarouselDirections.DIRECTION_LEFT);
196+
} else if (args.direction === 2) {
197+
this.swipe(CarouselDirections.DIRECTION_RIGHT);
198+
}
199+
});
141200
gridLayout.addChild(image);
142201
}
143202

203+
144204
if (slide.title) {
145205
let title: Label = CarouselDirective.generateTitleSlider(slide.title);
146206
if (this.carouselLabelOverlay) {
@@ -149,7 +209,11 @@ export class CarouselDirective implements AfterViewInit {
149209
}
150210
gridLayout.addChild(title);
151211
}
212+
152213
this.carouselSlides.addChild(gridLayout);
214+
if (gridLayout.visibility === 'visible') {
215+
GridLayout.setColumn(gridLayout, this.getInitColPos(i));
216+
}
153217
});
154218
}
155219

@@ -252,6 +316,7 @@ export class CarouselDirective implements AfterViewInit {
252316
private initAutoPlay() {
253317
if (this.carouselSpeed && CarouselDirective.isNumeric(this.carouselSpeed)) {
254318
clearInterval(this.autoPlayIntervalId);
319+
// @ts-ignore
255320
this.autoPlayIntervalId = setInterval(() => {
256321
this.swipe(CarouselDirections.DIRECTION_RIGHT);
257322
}, this.carouselSpeed + this.carouselAnimationSpeed);
@@ -265,6 +330,7 @@ export class CarouselDirective implements AfterViewInit {
265330
if (this.autoPlayIntervalId) {
266331
clearTimeout(this.autoPlayTimeoutId);
267332
clearInterval(this.autoPlayIntervalId);
333+
// @ts-ignore
268334
this.autoPlayTimeoutId = setTimeout(() => {
269335
this.swipe(CarouselDirections.DIRECTION_RIGHT);
270336
this.initAutoPlay();
@@ -305,81 +371,29 @@ export class CarouselDirective implements AfterViewInit {
305371

306372
// Get element width + image visibility
307373
let elementWidth = this.elem.nativeElement.getActualSize().width;
308-
view.visibility = [this.indexMoveCenter, this.indexMoveLeft, this.indexMoveRight].indexOf(i) > -1 ? "visible" : "collapse";
374+
view.visibility = [this.currentImage, this.nextImage, this.nextNextImage].indexOf(i) > -1 ? "visible" : "collapse";
309375

310-
// Perfrom animation
311-
this.checkCL(view, i, elementWidth);
312-
this.checkCR(view, i, elementWidth);
313-
this.checkRC(view, i, elementWidth);
314-
this.checkLC(view, i, elementWidth);
315-
}
316-
}
317-
318-
/**
319-
* Move image center -> left
320-
* @param view
321-
* @param index
322-
* @param elementWidth
323-
*/
324-
private checkCL(view: View, index: number, elementWidth: number) {
325-
if (this.indexMoveLeft == index) {
326-
view.translateX = 0;
327-
view.animate({
328-
translate: {x: elementWidth, y: 0},
329-
duration: this.carouselAnimationSpeed,
330-
curve: AnimationCurve.easeIn
331-
});
332-
}
333-
}
334-
335-
/**
336-
* Move image right -> center
337-
* @param view
338-
* @param index
339-
* @param elementWidth
340-
*/
341-
private checkRC(view: View, index: number, elementWidth: number) {
342-
if (this.indexMoveCenter == index && this.direction == CarouselDirections.DIRECTION_LEFT) {
343-
view.translateX = -elementWidth;
344-
view.animate({
345-
translate: {x: 0, y: 0},
346-
duration: this.carouselAnimationSpeed,
347-
curve: AnimationCurve.easeOut
348-
});
349-
}
350-
}
351-
352-
/**
353-
* Move image center -> right
354-
* @param view
355-
* @param index
356-
* @param elementWidth
357-
*/
358-
private checkCR(view: View, index: number, elementWidth: number) {
359-
if (this.indexMoveRight == index) {
360-
view.translateX = 0;
361-
view.animate({
362-
translate: {x: -elementWidth, y: 0},
363-
duration: this.carouselAnimationSpeed,
364-
curve: AnimationCurve.easeIn
365-
});
376+
// Perfrom translation
377+
if (view.visibility === 'visible'){
378+
this.applySwipe(view, i, elementWidth);
379+
}
366380
}
367381
}
368382

369-
/**
370-
* Move image left -> center
371-
* @param view
372-
* @param index
373-
* @param elementWidth
374-
*/
375-
private checkLC(view: View, index: number, elementWidth: number) {
376-
if (this.indexMoveCenter == index && this.direction == CarouselDirections.DIRECTION_RIGHT) {
377-
view.translateX = elementWidth;
378-
view.animate({
379-
translate: {x: 0, y: 0},
380-
duration: this.carouselAnimationSpeed,
381-
curve: AnimationCurve.easeOut
382-
});
383+
private applySwipe (view: View, index: number, elementWidth: number) {
384+
switch (index) {
385+
case this.currentImage:
386+
view.backgroundColor = this.currentElementHiglhtColor;
387+
GridLayout.setColumn(view, 0);
388+
break;
389+
case this.nextImage:
390+
view.backgroundColor = CarouselDirective.TRANSPARENT;
391+
GridLayout.setColumn(view, 1);
392+
break;
393+
case this.nextNextImage:
394+
view.backgroundColor = CarouselDirective.TRANSPARENT;
395+
GridLayout.setColumn(view, 2);
396+
break;
383397
}
384398
}
385399

@@ -391,16 +405,16 @@ export class CarouselDirective implements AfterViewInit {
391405

392406
// right to left
393407
case CarouselDirections.DIRECTION_LEFT:
394-
this.indexMoveLeft = this.currentImage;
395-
this.currentImage = ((this.currentImage == 0 ? this.totalItems : this.currentImage) - 1) % this.totalItems;
396-
this.indexMoveCenter = this.currentImage;
408+
this.currentImage = ((this.currentImage === 0 ? this.totalItems : this.currentImage) - 1) % this.totalItems;
409+
this.nextImage = ((this.currentImage === 0 ? this.totalItems : this.currentImage) - 1) % this.totalItems;
410+
this.nextNextImage = ((this.nextImage === 0 ? this.totalItems : this.nextImage) - 1) % this.totalItems;
397411
break;
398412

399413
// left to right
400414
case CarouselDirections.DIRECTION_RIGHT:
401-
this.indexMoveRight = this.currentImage;
402-
this.currentImage = (this.currentImage + 1) % this.totalItems;
403-
this.indexMoveCenter = this.currentImage;
415+
this.currentImage = ((this.currentImage === 0 ? this.totalItems : this.currentImage) + 1) % this.totalItems;
416+
this.nextImage = (this.currentImage + 1) % this.totalItems;
417+
this.nextNextImage = (this.nextImage + 1) % this.totalItems;
404418
break;
405419
}
406420
}
@@ -409,9 +423,8 @@ export class CarouselDirective implements AfterViewInit {
409423
* Reset values after animation
410424
*/
411425
private resetAnimationValues() {
412-
this.indexMoveLeft = null;
413-
this.indexMoveRight = null;
414-
this.indexMoveCenter = null;
426+
this.nextImage = null;
427+
this.nextNextImage = null;
415428
this.movingImages = false;
416429
}
417430

0 commit comments

Comments
 (0)