cocoscreator循环滚动控件,选择日期选择时间
在网上找了一下没看到有人分享这种类型的控件,都是无限滚动的控件。所以自己动手写了一个,效果大概这样
//循环滚动组件,实现循环滚动效果
const {ccclass, property} = cc._decorator;
const biggistRotation = 90
//摩擦力
const friction = 0.98
//自动滚动时间
const autoMoveTime = 0.05
@ccclass
export default class LoopScrow extends cc.Component
{
@property({tooltip:"滚动节点",type:cc.Node})
item:cc.Node = null
@property({tooltip:"滚动节点父节点",type:cc.Node})
content:cc.Node = null
@property({tooltip:"显示节点数,最好为奇数"})
showItemNum = 0
@property({tooltip:"惯性大小,取值0~1"})
inertiaScale = 1
//触摸事件ID
_touchId = null
//滚动节点初始化时开始位置
_startPosY = 0
//上次触摸位置
_lastPos = null
//滚动节点列表
_scrollItem:Array<cc.Node> = []
//中间item位置
_centerItemIndex = 0
//更新节点回调
_onUpdateItem!:(data, item: cc.Node) => void
//滚动视图数据
_dataList = []
//中心位置数据索引
_dataIndex = 0
//滚动速度
_scrollSpeed = 0
//开始触摸时间
_startTouchTime = 0
//开始滚动
_startMove = false
//自动滚动
_startAutoMove = false
//是否循环滚动
_isLoopScroll = true
//不是循环滚动的话,滑动回弹上限
_scrollBiggestLength = 0
onLoad(){
this.item.active = false
if(this.inertiaScale < 0){
this.inertiaScale = 0
}else if(this.inertiaScale > 1){
this.inertiaScale = 1
}
}
start(){
this.node.on(cc.Node.EventType.TOUCH_START,this.onEventStart,this);
this.node.on(cc.Node.EventType.TOUCH_END,this.onEventEnd,this);
this.node.on(cc.Node.EventType.TOUCH_MOVE,this.onEventMove,this);
this.node.on(cc.Node.EventType.TOUCH_CANCEL,this.onEventCancel,this)
this._startPosY = this.content.height/2 + this.item.height/2
this._centerItemIndex = Math.floor((this.showItemNum+2)/2)
this._scrollBiggestLength = Math.floor(this.showItemNum/2)*this.item.height
this.init()
}
update(dt){
for (let i = 0; i < this._scrollItem.length; i++) {
const element = this._scrollItem[i];
this.updateItemVal(element)
}
if(this._scrollSpeed > 0){
this._scrollSpeed -= friction*dt
if(this._scrollSpeed <= 0){
this._scrollSpeed = 0
}
}else if(this._scrollSpeed < 0){
this._scrollSpeed += friction*dt
if(this._scrollSpeed >= 0){
this._scrollSpeed = 0
}
}else{
if(this._startMove){
this.scrollEnd()
this._startMove = false
}
}
if(this._scrollSpeed !== 0){
this.scrollMove(this._scrollSpeed*dt*1000)
}
}
onEventStart(event:cc.Touch){
if(event.getID() != this._touchId && this._touchId != null){
return
}
if(this._startAutoMove){
return
}
this._touchId = event.getID()
this._lastPos = event.getLocation()
this._startTouchTime = new Date().getTime()
this._scrollSpeed = 0
}
onEventEnd(event:cc.Touch){
if(event.getID() != this._touchId){
return
}
if(this._startAutoMove){
return
}
this._touchId = null
let nowPos = event.getLocation()
let startPos = event.getStartLocation()
this._scrollSpeed = (nowPos.y - startPos.y)/(new Date().getTime()-this._startTouchTime)
if(this._scrollSpeed > 1.4){
this._scrollSpeed = 1.4
}else if(this._scrollSpeed < -1.4){
this._scrollSpeed = -1.4
}
this._scrollSpeed *= this.inertiaScale
this._startMove = true
}
onEventMove(event:cc.Touch){
if(event.getID() != this._touchId){
return
}
if(this._startAutoMove){
return
}
this.scrollMove(event.getLocation().y - this._lastPos.y)
this._lastPos = event.getLocation()
}
onEventCancel(event:cc.Touch){
if(event.getID() != this._touchId){
return
}
if(this._startAutoMove){
return
}
this._touchId = null
let nowPos = event.getLocation()
let startPos = event.getStartLocation()
this._scrollSpeed = (nowPos.y - startPos.y)/(new Date().getTime()-this._startTouchTime)
if(this._scrollSpeed > 1.4){
this._scrollSpeed = 1.4
}else if(this._scrollSpeed < -1.4){
this._scrollSpeed = -1.4
}
this._scrollSpeed *= this.inertiaScale
this._startMove = true
}
init(){
for (let i = 0; i < this.showItemNum + 2; i++) {
let item = cc.instantiate(this.item)
item.active = true
item.parent = this.content
item.position = cc.v3(0,this._startPosY - i*this.item.height,0)
this._scrollItem[this._scrollItem.length] = item
//初始化节点数据
this.updateItem(i,item)
}
}
/**
* 初始化数据
* @param dataList 数据列表
* @param onUpdateItem 更新节点回调 (节点数据,节点)
* @param startIndex 滚动节点开始的位置
*/
initData(dataList,onUpdateItem:(data, item: cc.Node) => void,startIndex:number = 0){
if(!onUpdateItem){
cc.error("LoopScrow.initData:","滚动更新节点回调为空")
}
if(!dataList || dataList.length === 0){
cc.error("LoopScrow.initData:","dataList为空")
}
if(startIndex<0||startIndex>=dataList.length){
cc.error("LoopScrow.initData:","startIndex取值不正确,应该在数据列表长度范围内")
}
this._dataList = dataList
this._onUpdateItem = onUpdateItem
this._dataIndex = startIndex
if(this._dataList.length <= this.showItemNum){
this._isLoopScroll = false
}
}
/**
* 滚动视图
* @param dir 向上滚动dir>0,向下滚动dir<0
*/
scrollMove(dir){
let tempDir = dir
while (tempDir > 5) {
this.moveItem(dir,5)
tempDir -= 5
}
this.moveItem(dir,tempDir)
}
moveItem(dir,length){
if(this._isLoopScroll){
for (let i = 0; i < this._scrollItem.length; i++) {
const element = this._scrollItem[i];
element.y += length
}
if(dir>0){
if(this._scrollItem[this._centerItemIndex + 1].y >= 0){
//调整节点位置
this.changeItem(dir,this._scrollItem[this._centerItemIndex + 1].y)
}
}else{
if(this._scrollItem[this._centerItemIndex - 1].y <= 0){
//调整节点位置
this.changeItem(dir,this._scrollItem[this._centerItemIndex - 1].y)
}
}
}else{
if((this._dataIndex === 0 && dir<=0)||
(this._dataIndex === this._dataList.length - 1 && dir>=0)){
this._scrollSpeed = 0
if(this._scrollItem[this._centerItemIndex].y > -this._scrollBiggestLength &&
this._scrollItem[this._centerItemIndex].y < this._scrollBiggestLength){
for (let i = 0; i < this._scrollItem.length; i++) {
const element = this._scrollItem[i];
element.y += length
}
}
return
}
for (let i = 0; i < this._scrollItem.length; i++) {
const element = this._scrollItem[i];
element.y += length
}
if(dir>0){
if(this._scrollItem[this._centerItemIndex + 1].y >= 0){
//调整节点位置
this.changeItem(dir,this._scrollItem[this._centerItemIndex + 1].y)
}
}else{
if(this._scrollItem[this._centerItemIndex - 1].y <= 0){
//调整节点位置
this.changeItem(dir,this._scrollItem[this._centerItemIndex - 1].y)
}
}
}
}
/**
* 调整节点位置(向上滚动的时候,将头部节点移动到尾部,向下滚动的时候,将尾部节点移动到头部)
* @param dir 向上滚动dir>0,向下滚动dir<0
* @param middleItemPos 中心节点的位置
*/
changeItem(dir,middleItemPos){
if(dir>0){
let item = this._scrollItem.shift()
this._scrollItem[this._scrollItem.length] = item
item.y = this._startPosY - (this._scrollItem.length - 1)*this.item.height + middleItemPos
this._dataIndex++
if(this._dataIndex >= this._dataList.length){
this._dataIndex = 0
}
this.updateItem(this._scrollItem.length - 1,item)
}else{
let item = this._scrollItem.pop()
this._scrollItem.splice(0,0,item)
item.y = this._startPosY + middleItemPos
this._dataIndex--
if(this._dataIndex < 0){
this._dataIndex = this._dataList.length - 1
}
this.updateItem(0,item)
}
}
/**
* 更新节点数据
* @param i 索引
* @param item 节点
*/
updateItem(i,item){
let index = i - this._centerItemIndex + this._dataIndex
if(this._isLoopScroll){
if(index < 0){
index += this._dataList.length
}else if(index >= this._dataList.length){
index -= this._dataList.length
}
}
if(this._onUpdateItem){
this._onUpdateItem(this._dataList[index],item)
}
}
updateItemVal(item:cc.Node){
let y = item.y
if(y > this._startPosY){
y = this._startPosY
}else if(y < -this._startPosY){
y = -this._startPosY
}
item.eulerAngles = cc.v3((y/this._startPosY)*biggistRotation,0,0)
item.opacity = 255 - Math.abs(y)
item.scale = 1 - Math.abs(y/this._startPosY)*0.3
}
/**滚动停止 */
scrollEnd(){
this._startAutoMove = true
let moveLength = this.item.height - Math.abs(this._scrollItem[this._centerItemIndex].y)
if(this._isLoopScroll){
if(this._scrollItem[this._centerItemIndex].y > this.item.height/2){ //向上自动滚动一格
for (let i = 0; i < this._scrollItem.length; i++) {
const element = this._scrollItem[i];
if(i === this._scrollItem.length - 1){
cc.tween(element).to(autoMoveTime,{position:cc.v3(element.position.x,element.position.y + moveLength,element.position.z)})
.call(()=>{
this.changeItem(1,0)
this._startAutoMove = false
})
.start()
}else{
cc.tween(element).to(autoMoveTime,{position:cc.v3(element.position.x,element.position.y + moveLength,element.position.z)}).start()
}
}
}else if(this._scrollItem[this._centerItemIndex].y < -this.item.height/2){ //向下自动滚动一格
for (let i = 0; i < this._scrollItem.length; i++) {
const element = this._scrollItem[i];
if(i === this._scrollItem.length - 1){
cc.tween(element).to(autoMoveTime,{position:cc.v3(element.position.x,element.position.y - moveLength,element.position.z)})
.call(()=>{
this.changeItem(-1,0)
this._startAutoMove = false
})
.start()
}else{
cc.tween(element).to(autoMoveTime,{position:cc.v3(element.position.x,element.position.y - moveLength,element.position.z)}).start()
}
}
}else{ //滚动回中间
for (let i = 0; i < this._scrollItem.length; i++) {
const element = this._scrollItem[i];
if(i === this._scrollItem.length - 1){
cc.tween(element).to(autoMoveTime,{position:cc.v3(element.position.x,element.position.y - this._scrollItem[this._centerItemIndex].y,element.position.z)})
.call(()=>{
this._startAutoMove = false
})
.start()
}else{
cc.tween(element).to(autoMoveTime,{position:cc.v3(element.position.x,element.position.y - this._scrollItem[this._centerItemIndex].y,element.position.z)}).start()
}
}
}
}else{
if(this._scrollItem[this._centerItemIndex].y > this.item.height/2 && this._dataIndex < this._dataList.length - 1){ //向上自动滚动一格
for (let i = 0; i < this._scrollItem.length; i++) {
const element = this._scrollItem[i];
if(i === this._scrollItem.length - 1){
cc.tween(element).to(autoMoveTime,{position:cc.v3(element.position.x,element.position.y + moveLength,element.position.z)})
.call(()=>{
this.changeItem(1,0)
this._startAutoMove = false
})
.start()
}else{
cc.tween(element).to(autoMoveTime,{position:cc.v3(element.position.x,element.position.y + moveLength,element.position.z)}).start()
}
}
}else if(this._scrollItem[this._centerItemIndex].y < -this.item.height/2 && this._dataIndex > 0){ //向下自动滚动一格
for (let i = 0; i < this._scrollItem.length; i++) {
const element = this._scrollItem[i];
if(i === this._scrollItem.length - 1){
cc.tween(element).to(autoMoveTime,{position:cc.v3(element.position.x,element.position.y - moveLength,element.position.z)})
.call(()=>{
this.changeItem(-1,0)
this._startAutoMove = false
})
.start()
}else{
cc.tween(element).to(autoMoveTime,{position:cc.v3(element.position.x,element.position.y - moveLength,element.position.z)}).start()
}
}
}else{ //滚动回中间
for (let i = 0; i < this._scrollItem.length; i++) {
const element = this._scrollItem[i];
if(i === this._scrollItem.length - 1){
cc.tween(element).to(autoMoveTime,{position:cc.v3(element.position.x,element.position.y - this._scrollItem[this._centerItemIndex].y,element.position.z)})
.call(()=>{
this._startAutoMove = false
})
.start()
}else{
cc.tween(element).to(autoMoveTime,{position:cc.v3(element.position.x,element.position.y - this._scrollItem[this._centerItemIndex].y,element.position.z)}).start()
}
}
}
}
}
}
应用代码
import LoopScrow from "./LoopScrow";
const {ccclass, property} = cc._decorator;
@ccclass
export default class LoopScrowTest extends cc.Component {
@property(LoopScrow)
loopScrow:LoopScrow = null;
onLoad () {
let onUpdateItem:any = (data, item: cc.Node) =>
{
if (data == null)
{
item.active = false
return;
}
item.active = true
let label = item.getComponent(cc.Label);
label.string = data;
}
let dataList = []
for (let i = 0; i < 30; i++) {
dataList[dataList.length] = i
}
this.loopScrow.initData(dataList,onUpdateItem,0)
}
start () {
}
// update (dt) {}
}