Skip to content

Commit ff1f6c3

Browse files
committed
Add Page indicators.
1 parent 39c9c64 commit ff1f6c3

File tree

3 files changed

+119
-31
lines changed

3 files changed

+119
-31
lines changed

demo/app/main-page.xml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
</Slides:Slide>
2020
</Slides:SlideContainer>
2121

22-
<StackLayout row="1">
23-
<button tap="next" text="Next"/>
24-
<button tap="prev" text="Prev"/>
25-
</StackLayout>
22+
2623
</GridLayout>
2724
</Page>

nativescript-slides.d.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { AbsoluteLayout } from 'ui/layouts/absolute-layout';
22
import { StackLayout } from 'ui/layouts/stack-layout';
3+
import { Label } from 'ui/label';
34
export declare class Slide extends StackLayout {
45
}
56
export interface ISlideMap {
67
panel: StackLayout;
8+
index: number;
79
left?: ISlideMap;
810
right?: ISlideMap;
911
}
@@ -20,6 +22,14 @@ export declare class SlideContainer extends AbsoluteLayout {
2022
private _androidTranslucentNavBar;
2123
private timer_reference;
2224
private _angular;
25+
private _footer;
26+
private _pageIndicators;
27+
private _pageIndicatorsColor;
28+
private _pageIndicatorsActiveImage;
29+
private indicatorImage;
30+
pageIndicators: boolean;
31+
pageIndicatorsColor: string;
32+
pageIndicatorsActiveImage: string;
2333
hasNext: boolean;
2434
hasPrevious: boolean;
2535
interval: number;
@@ -31,6 +41,7 @@ export declare class SlideContainer extends AbsoluteLayout {
3141
angular: boolean;
3242
android: any;
3343
ios: any;
44+
currentIndex: number;
3445
constructor();
3546
private setupDefaultValues();
3647
constructView(constructor?: boolean): void;
@@ -45,8 +56,10 @@ export declare class SlideContainer extends AbsoluteLayout {
4556
private applySwipe(pageWidth);
4657
private showRightSlide(panelMap, offset?, endingVelocity?);
4758
private showLeftSlide(panelMap, offset?, endingVelocity?);
48-
private buildFooter();
59+
private buildFooter(pageCount?, activeIndex?);
4960
private setwidthPercent(view, percentage);
5061
private newFooterButton(name);
5162
private buildSlideMap(views);
63+
createIndicator(): Label;
64+
setActivePageIndicator(index: number): void;
5265
}

nativescript-slides.ts

Lines changed: 104 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import { Button } from 'ui/button';
77
import {Label} from 'ui/label';
88
import * as AnimationModule from 'ui/animation';
99
import * as gestures from 'ui/gestures';
10-
import {AnimationCurve} from 'ui/enums';
10+
import {AnimationCurve, Orientation} from 'ui/enums';
11+
import {Color} from 'color';
12+
import {Image} from 'ui/image';
13+
import * as imageSource from 'image-source';
1114

1215
let LayoutParams: any;
1316
if (app.android) {
@@ -26,6 +29,7 @@ enum direction {
2629

2730
export interface ISlideMap {
2831
panel: StackLayout;
32+
index: number;
2933
left?: ISlideMap;
3034
right?: ISlideMap;
3135
}
@@ -43,11 +47,39 @@ export class SlideContainer extends AbsoluteLayout {
4347
private _androidTranslucentNavBar: boolean;
4448
private timer_reference: number;
4549
private _angular: boolean;
50+
private _footer: StackLayout;
51+
private _pageIndicators: boolean;
52+
private _pageIndicatorsColor: Color;
53+
private _pageIndicatorsActiveImage: string;
54+
private indicatorImage: Image;
55+
/* page indicator stuff*/
56+
get pageIndicators(): boolean {
57+
return this._pageIndicators;
58+
}
59+
set pageIndicators(value: boolean) {
60+
this._pageIndicators = value;
61+
}
62+
63+
set pageIndicatorsColor(value: string) {
64+
this._pageIndicatorsColor = new Color(value);
65+
}
66+
get pageIndicatorsColor() {
67+
return this._pageIndicatorsColor.hex
68+
}
69+
70+
get pageIndicatorsActiveImage(): string {
71+
return this._pageIndicatorsActiveImage;
72+
}
73+
set pageIndicatorsActiveImage(value: string) {
74+
this.indicatorImage.imageSource = imageSource.fromFile(value);
75+
this._pageIndicatorsActiveImage = value;
76+
}
77+
78+
4679

4780
get hasNext(): boolean {
4881
return !!this.currentPanel.right;
4982
}
50-
5183
get hasPrevious(): boolean {
5284
return !!this.currentPanel.left;
5385
}
@@ -110,14 +142,17 @@ export class SlideContainer extends AbsoluteLayout {
110142
return;
111143
}
112144

145+
get currentIndex(): number {
146+
return this.currentPanel.index;
147+
}
148+
113149
constructor() {
114150
super();
115151
this.setupDefaultValues();
116152
// if being used in an ng2 app we want to prevent it from excuting the constructView
117153
// until it is called manually in ngAfterViewInit.
118154

119155
this.constructView(true);
120-
121156
}
122157

123158
private setupDefaultValues(): void {
@@ -127,7 +162,6 @@ export class SlideContainer extends AbsoluteLayout {
127162
}
128163

129164
this.transitioning = false;
130-
131165
this._pageWidth = Platform.screen.mainScreen.widthDIPs;
132166

133167
if (this._interval == null) {
@@ -141,6 +175,13 @@ export class SlideContainer extends AbsoluteLayout {
141175
this.angular = false;
142176
}
143177

178+
if (this._pageIndicators == null) {
179+
this._pageIndicators = false;
180+
} else {
181+
if (this._pageIndicatorsColor == null) {
182+
this._pageIndicatorsColor = new Color('#fff')
183+
}
184+
}
144185
}
145186

146187
public constructView(constructor: boolean = false): void {
@@ -178,6 +219,13 @@ export class SlideContainer extends AbsoluteLayout {
178219
}
179220
});
180221

222+
if (this.pageIndicators) {
223+
this._footer = this.buildFooter(slides.length, 0);
224+
this.addChild(this._footer);
225+
this.setActivePageIndicator(0);
226+
}
227+
228+
181229
this.currentPanel = this.buildSlideMap(slides);
182230
this.currentPanel.panel.translateX = -this.pageWidth;
183231
this.applySwipe(this.pageWidth);
@@ -192,6 +240,8 @@ export class SlideContainer extends AbsoluteLayout {
192240
}
193241
});
194242
this.applySwipe(this.pageWidth);
243+
let topOffset = Platform.screen.mainScreen.heightDIPs - 105;
244+
AbsoluteLayout.setTop(this._footer, topOffset);
195245
this.currentPanel.panel.translateX = -this.pageWidth;
196246
});
197247
}
@@ -264,6 +314,7 @@ export class SlideContainer extends AbsoluteLayout {
264314
this.transitioning = false;
265315
this.currentPanel.panel.off('pan');
266316
this.currentPanel = panel;
317+
this.setActivePageIndicator(this.currentPanel.index);
267318
this.applySwipe(this.pageWidth);
268319
this.rebindSlideShow();
269320
}
@@ -428,31 +479,25 @@ export class SlideContainer extends AbsoluteLayout {
428479
/**
429480
* currently deprecated.... will come back to life for navigation dots.
430481
* */
431-
private buildFooter(): AbsoluteLayout {
432-
let footer = new AbsoluteLayout();
482+
private buildFooter(pageCount: number = 5, activeIndex: number = 0): StackLayout {
433483
let footerInnerWrap = new StackLayout();
434-
let footerInnerWrapLeft = new StackLayout();
435-
let footerInnerWrapMiddle = new StackLayout();
436-
let footerInnerWrapRight = new StackLayout();
437-
this.setwidthPercent(footer, 100);
484+
const topOffset = Platform.screen.mainScreen.heightDIPs - 105;
485+
footerInnerWrap.height = 20;
438486

439-
footerInnerWrap.orientation = 'horizontal';
440487
this.setwidthPercent(footerInnerWrap, 100);
488+
AbsoluteLayout.setLeft(footerInnerWrap, 0);
489+
AbsoluteLayout.setTop(footerInnerWrap, topOffset);
441490

442-
footer.addChild(footerInnerWrap);
443-
444-
this.setwidthPercent(footerInnerWrapRight, 30);
445-
this.setwidthPercent(footerInnerWrapLeft, 30);
446-
this.setwidthPercent(footerInnerWrapMiddle, 40);
447-
448-
footerInnerWrapLeft.addChild(this.newFooterButton('Previous'));
449-
footerInnerWrapRight.addChild(this.newFooterButton('Next'));
450-
451-
footerInnerWrap.addChild(footerInnerWrapLeft);
452-
footerInnerWrap.addChild(footerInnerWrapMiddle);
453-
footerInnerWrap.addChild(footerInnerWrapRight);
491+
footerInnerWrap.orientation = 'horizontal';
492+
footerInnerWrap.verticalAlignment = 'top';
493+
footerInnerWrap.horizontalAlignment = 'center';
454494

455-
return footer;
495+
let i = 0;
496+
while (i < pageCount) {
497+
footerInnerWrap.addChild(this.createIndicator());
498+
i++;
499+
}
500+
return footerInnerWrap;
456501
}
457502

458503
private setwidthPercent(view: View, percentage: number) {
@@ -469,9 +514,10 @@ export class SlideContainer extends AbsoluteLayout {
469514

470515
private buildSlideMap(views: StackLayout[]) {
471516
let slideMap: ISlideMap[] = [];
472-
views.forEach((view: StackLayout) => {
517+
views.forEach((view: StackLayout, index: number) => {
473518
slideMap.push({
474-
panel: view
519+
panel: view,
520+
index: index,
475521
});
476522
});
477523
slideMap.forEach((mapping: ISlideMap, index: number) => {
@@ -488,4 +534,36 @@ export class SlideContainer extends AbsoluteLayout {
488534
this.startSlideshow();
489535
return slideMap[0];
490536
}
537+
538+
createIndicator(): Label {
539+
let indicator = new Label();
540+
indicator.backgroundColor = new Color('#fff');
541+
indicator.width = 10;
542+
indicator.height = 10;
543+
indicator.marginLeft = 2.5;
544+
indicator.marginRight = 2.5;
545+
indicator.borderRadius = 5;
546+
return indicator;
547+
}
548+
549+
setActivePageIndicator(index: number) {
550+
551+
this._footer.eachLayoutChild((view: View) => {
552+
if (view instanceof Label) {
553+
view.opacity = 0.4;
554+
if (this._pageIndicatorsActiveImage != null) {
555+
view.backgroundColor = new Color('#fff');
556+
view.className = 'slide-indicator-inactive';
557+
view.backgroundImage = null;
558+
}
559+
}
560+
});
561+
let activeIndicator = this._footer.getChildAt(index);
562+
activeIndicator.className = 'slide-indicator-active';
563+
activeIndicator.opacity = 0.9;
564+
if (this._pageIndicatorsActiveImage != null) {
565+
activeIndicator.backgroundColor = null;
566+
activeIndicator.backgroundImage = this.pageIndicatorsActiveImage;
567+
}
568+
}
491569
}

0 commit comments

Comments
 (0)