nativescript(angular2)——轮播图组件
import { Directive, ElementRef, AfterViewInit, Input, OnDestroy } from "@angular/core";
import { AnimationCurve } from "tns-core-modules/ui/enums";
import { Image } from "tns-core-modules/ui/image";
import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout/stack-layout";
import { GridLayout, ItemSpec } from "tns-core-modules/ui/layouts/grid-layout";
import { GridUnitType } from "tns-core-modules/ui/layouts/grid-layout";
import { HorizontalAlignment } from "tns-core-modules/ui/enums";
import { Label } from "tns-core-modules/ui/label";
import { View } from "tns-core-modules/ui/core/view";
import { Visibility } from "tns-core-modules/ui/enums";
import { fromFile } from "tns-core-modules/image-source";
import { Color } from "tns-core-modules/ui/text-base/text-base";
import { GestureTypes, TouchGestureEventData, RotationGestureEventData, SwipeGestureEventData, GestureEventData } from "ui/gestures";
import labelModule = require("ui/label");
import * as Toast from "nativescript-toast";
import { RouterExtensions } from "nativescript-angular/router";
import { Config } from "../../../share/config";
import { isAndroid, isIOS, device, screen } from "platform";
/**
* hsf
* 2017-10
*/
@Directive({
selector: "[carousel]"
})
export class CarouselDirective implements AfterViewInit, OnDestroy {
private static animationSpeedDefault: number = 400; // 每一张图片动画的时间
private static autoPlaySpeedDefault: number = 0; // 前一张到后一张中间经历的时间
private container: GridLayout; // 总容器
private carouselSlides: GridLayout; // 图片容器
private totalItems: number = 0; // 图片总张数
// public autoPlayIntervalId: number; // 自动轮播区间
private autoPlayTimeoutId: number; // 自动轮播时间间隔
// private arrowType: number = CarouselArrowTypes.BOLD;
private direction: CarouselDirections = null; // 轮播方向
private currentImage: number = 0; // 当前轮播图
private movingImages: boolean = false; // 是否轮播标志
private indexMoveLeft: number = null; //
private indexMoveRight: number = null; //
private indexMoveCenter: number = null; //
private label: any;
@Input() carousel: any; // 轮播图数据集
@Input() carouselSpeed: number; // 前一张到后一张中间经历的时间
// @Input() carouselArrows: string; //
// @Input() carouselLabelOverlay: boolean; //
@Input() carouselAnimationSpeed: number; // 每一张图片动画的时间
constructor(private elem: ElementRef, private mrouter: RouterExtensions) {
this.container = elem.nativeElement;
}
ngAfterViewInit() {
this.initOptions();
this.initContainer();
this.initImagesLayout();
this.initSlides();
// this.initControls();
this.initAutoPlay();
}
/**
* 初始化
*/
private initOptions() {
// 动画持续时间
if (this.carouselAnimationSpeed && CarouselDirective.isNumeric(this.carouselAnimationSpeed)) {
this.carouselAnimationSpeed = +this.carouselAnimationSpeed;
}
// tslint:disable-next-line:one-line
else {
this.carouselAnimationSpeed = CarouselDirective.animationSpeedDefault;
}
if (this.carouselSpeed && CarouselDirective.isNumeric(this.carouselSpeed)) {
this.carouselSpeed = +(this.carouselSpeed);
}
// tslint:disable-next-line:one-line
else {
this.carouselSpeed = CarouselDirective.autoPlaySpeedDefault;
}
// Set arrow type
// if (this.carouselArrows) {
// switch (this.carouselArrows) {
// case "none":
// this.arrowType = CarouselArrowTypes.NONE;
// break;
// case "small":
// this.arrowType = CarouselArrowTypes.SMALL;
// break;
// case "normal":
// this.arrowType = CarouselArrowTypes.NORMAL;
// break;
// case "bold":
// this.arrowType = CarouselArrowTypes.BOLD;
// break;
// case "narrow":
// this.arrowType = CarouselArrowTypes.NARROW;
// break;
// default:
// }
// }
}
/**
* 初始化布局
*/
private initContainer() {
// this.container.margin = "5";
// this.container.width = 200 ;
// this.container.height = 130;
this.container.horizontalAlignment = "center";
// this.container.verticalAlignment = "middle";
this.container.addRow(new ItemSpec(1, "auto"));
// this.container.addColumn(new ItemSpec(1, "star"));
// this.container.addColumn(new ItemSpec(1, "star"));
}
/**
* 初始化图片容器
*/
private initImagesLayout() {
// this.initOntach();
this.totalItems = this.carousel.length;
this.carouselSlides = new GridLayout();
this.carouselSlides.horizontalAlignment = "center";
// this.carouselSlides.verticalAlignment = "middle";
GridLayout.setColumnSpan(this.carouselSlides, 2);
this.container.addChild(this.carouselSlides);
}
/**
* 获取图片资源,显示图片
*/
private initSlides() {
this.carousel.forEach((slide: CarouselSlide, i: number) => {
let gridLayout = new GridLayout();
gridLayout.addRow(new ItemSpec(1, "auto"));
gridLayout.visibility = i === 0 ? "visible" : "collapse";
if (slide.imageUrl) {
let image: Image = CarouselDirective.generateImageSliderFromUrl(slide.imageUrl);
if (image !== null) {
image.on(GestureTypes.swipe, (args: SwipeGestureEventData) => {
console.log("Swipe Direction: " + args.direction);
if (args.direction === 1) {
this.stopStartAutoplay();
this.swipe(CarouselDirections.DIRECTION_LEFT);
} else if (args.direction === 2) {
this.stopStartAutoplay();
this.swipe(CarouselDirections.DIRECTION_RIGHT);
}
});
image.on(GestureTypes.tap, (args: GestureEventData) => {
console.log(slide.link);
let linkSlice = slide.link.slice(0, 4);
console.log(linkSlice);
if (linkSlice === "http") {
this.mrouter.navigate(["/home/testapi/brokenline", slide.link]);
} else {
this.mrouter.navigate([slide.link]);
}
});
gridLayout.addChild(image);
this.carouselSlides.addChild(gridLayout);
}
if (this.carousel.length > 1) {
this.initCarouselPoint(i, gridLayout);
}
}
// if (slide.image) {
// let image: Image = CarouselDirective.generateImageSliderFromFile(slide.image);
// image.on(GestureTypes.swipe, (args: SwipeGestureEventData) => {
// console.log("Swipe Direction: " + args.direction);
// if (args.direction === 1) {
// this.stopStartAutoplay();
// this.swipe(CarouselDirections.DIRECTION_LEFT);
// } else if (args.direction === 2) {
// this.stopStartAutoplay();
// this.swipe(CarouselDirections.DIRECTION_RIGHT);
// }
// });
// image.on(GestureTypes.tap, (args: GestureEventData) => {
// console.log(slide.link);
// let linkSlice = slide.link.slice(0, 4);
// console.log(linkSlice);
// if (linkSlice === "http") {
// this.mrouter.navigate(["/home/testapi/brokenline", slide.link], {
// transition: {
// name: "slideLeft",
// duration: 100,
// curve: "linear"
// }
// });
// } else {
// this.mrouter.navigate([slide.link], {
// transition: {
// name: "slideLeft",
// duration: 100,
// curve: "linear"
// }
// });
// }
// });
// gridLayout.addChild(image);
// }
});
}
initScrollPoint(stackLayout: StackLayout, pointPngUrl: string, marginLeft: number) {
stackLayout.orientation = "horizontal";
let image1: Image = CarouselDirective.generateImageSliderFromFile(pointPngUrl);
stackLayout.addChild(image1);
stackLayout.width = 32;
stackLayout.height = 32;
stackLayout.marginRight = marginLeft;
stackLayout.horizontalAlignment = "right";
stackLayout.verticalAlignment = "bottom";
}
/**
* 轮播图点的初始化
* @param id
* @param gridLayout
*/
private initCarouselPoint(id: any, gridLayout: GridLayout) {
for (let i = 0; i < this.carousel.length; i++) {
let stackLayout = new StackLayout();
let url = "~/images/carouselpoint1.png";
if (i === this.carousel.length - 1 - id) {
url = "~/images/carouselpoint2.png";
}
this.initScrollPoint(stackLayout, url, i * 17);
gridLayout.addChild(stackLayout);
}
}
/**
* 从url加载图片
* @param src
* @returns {Image}
*/
private static generateImageSliderFromUrl(src: string): Image {
let image: Image = new Image();
image.src = src;
image.className = "carousellayout";
image.stretch = "aspectFill";
image.backgroundColor = "#f5f5f5";
if (screen.mainScreen.heightDIPs === 1280) {
image.height = 260;
} else {
image.height = 120;
}
// console.log("轮播图的scale======================================");
// console.log(screen.mainScreen.scale);
return image;
}
/**
* 从文件加载图片
* @param path
* @returns {Image}
*/
private static generateImageSliderFromFile(path: string): Image {
let image: Image = new Image();
image.imageSource = fromFile(path);
image.className = "slider-image";
return image;
}
/**
*
* @param id
* @returns {any}
*/
private static generateTitleSlider(id: string): Label {
let label = new Label();
label.text = id;
label.fontSize = 20;
// label.color = Color.;
label.textWrap = true;
label.className = "slider-title";
return label;
}
/**
* 自动轮播
*/
private initAutoPlay() {
if (this.carouselSpeed && CarouselDirective.isNumeric(this.carouselSpeed)) {
clearInterval(Config.autoPlayIntervalId);
Config.autoPlayIntervalId = setInterval(() => {
if (this.mrouter.router.url === "/home" && Config.state === 0) {
this.swipe(CarouselDirections.DIRECTION_RIGHT);
// Toast.makeText("轮播图在执行+++").show();
} else {
// Toast.makeText("轮播图在执行---").show();
// clearInterval(Config.autoPlayIntervalId);
}
}, this.carouselSpeed + this.carouselAnimationSpeed);
}
}
/**
* 手势检测停止,4秒后恢复
*/
private stopStartAutoplay() {
if (Config.autoPlayIntervalId) {
clearTimeout(this.autoPlayTimeoutId);
clearInterval(Config.autoPlayIntervalId);
this.autoPlayTimeoutId = setTimeout(() => {
this.swipe(CarouselDirections.DIRECTION_RIGHT);
this.initAutoPlay();
}, 4000);
}
}
/**
* 动画从右到左或从左到右
* @param direction
* @returns {boolean}
*/
private swipe(direction: CarouselDirections) {
if (this.totalItems < 2 || this.movingImages) {
return false;
}
this.direction = direction;
this.movingImages = true;
this.setDirectionValues();
this.animateSlides();
setTimeout(() => this.resetAnimationValues(), this.carouselAnimationSpeed);
}
/**
* 轮播动画
*/
private animateSlides() {
for (let i = 0; i < this.carouselSlides.getChildrenCount(); i++) {
let view: View = this.carouselSlides.getChildAt(i);
let elementWidth = this.elem.nativeElement.getActualSize().width;
view.visibility = [this.indexMoveCenter, this.indexMoveLeft, this.indexMoveRight].indexOf(i) > -1 ? "visible" : "collapse";
this.checkCL(view, i, elementWidth);
this.checkCR(view, i, elementWidth);
this.checkRC(view, i, elementWidth);
this.checkLC(view, i, elementWidth);
}
}
/**
* 中间到左边
* @param view
* @param index
* @param elementWidth
*/
private checkCL(view: View, index: number, elementWidth: number) {
if (this.indexMoveLeft === index) {
view.translateX = 0;
view.animate({
translate: { x: elementWidth, y: 0 },
duration: this.carouselAnimationSpeed,
curve: AnimationCurve.linear
}).catch((e) => {
console.log(e.message);
});
}
}
/**
* 右到中
* @param view
* @param index
* @param elementWidth
*/
private checkRC(view: View, index: number, elementWidth: number) {
if (this.indexMoveCenter === index && this.direction === CarouselDirections.DIRECTION_LEFT) {
view.translateX = -elementWidth;
view.animate({
translate: { x: 0, y: 0 },
duration: this.carouselAnimationSpeed,
curve: AnimationCurve.linear
}).catch((e) => {
console.log(e.message);
});
}
}
/**
* 中到右
* @param view
* @param index
* @param elementWidth
*/
private checkCR(view: View, index: number, elementWidth: number) {
if (this.indexMoveRight === index) {
view.translateX = 0;
view.animate({
translate: { x: -elementWidth, y: 0 },
duration: this.carouselAnimationSpeed,
curve: AnimationCurve.linear
}).catch((e) => {
console.log(e.message);
});
}
}
/**
* 左到中
* @param view
* @param index
* @param elementWidth
*/
private checkLC(view: View, index: number, elementWidth: number) {
if (this.indexMoveCenter === index && this.direction === CarouselDirections.DIRECTION_RIGHT) {
view.translateX = elementWidth;
view.animate({
translate: { x: 0, y: 0 },
duration: this.carouselAnimationSpeed,
curve: AnimationCurve.linear
}).catch((e) => {
console.log(e.message);
});
}
}
/**
* 设定值进行动画
*/
private setDirectionValues() {
switch (this.direction) {
// 右到左
case CarouselDirections.DIRECTION_LEFT:
this.indexMoveLeft = this.currentImage;
this.currentImage = ((this.currentImage === 0 ? this.totalItems : this.currentImage) - 1) % this.totalItems;
this.indexMoveCenter = this.currentImage;
break;
// 左到右
case CarouselDirections.DIRECTION_RIGHT:
this.indexMoveRight = this.currentImage;
this.currentImage = (this.currentImage + 1) % this.totalItems;
this.indexMoveCenter = this.currentImage;
break;
default:
}
}
/**
* 重置
*/
private resetAnimationValues() {
this.indexMoveLeft = null;
this.indexMoveRight = null;
this.indexMoveCenter = null;
this.movingImages = false;
}
/**
*
* @param value
* @returns {boolean}
*/
private static isNumeric(value: any) {
return !isNaN(value - parseFloat(value));
}
ngOnDestroy() {
console.log("ngOnDestroy()执行");
clearTimeout(this.autoPlayTimeoutId);
clearInterval(Config.autoPlayIntervalId);
}
}
enum CarouselDirections {
DIRECTION_LEFT,
DIRECTION_RIGHT
}
export class CarouselSlide {
imageUrl?: string;
image?: string;
id?: string;
link?: string;
}