邮箱、排行榜、好友列表等功能怎样实现循环加载,分页加载,已实现多行多列
邮箱、排行榜等功能怎样实现循环加载,分页加载,已实现多行多列
-
功能介绍:
在游戏中,经常会有邮箱,排行榜,好友列表等需要加载大量数据的功能,这个时候,就需要开发人员为游戏的性能考虑使用的方法,在此,做游戏前端开发三年的小菜鸟程序媛奉上自己的代码,供小伙伴们参考和批评~~~ -
代码实现背景:
引擎:CocosCreator v1.9.0
语言:TypeScript
废话不多说,直接上代码啦~~~~~
BaseScrollView.ts核心代码如下…
import UIManager from "../UIManager";
import ToolsMgr, { LogType } from "../FrameWork/ToolsMgr";
const {ccclass, property} = cc._decorator;
@ccclass
export default class BaseScrollView extends cc.ScrollView {
//item释放池
itemPool : cc.NodePool = null;
//item预制体
@property(cc.Prefab)
itemPerfab : cc.Prefab = null;
@property({ tooltip: "是否是垂直滚动" } || cc.Boolean)
_horizontal: boolean = false;
@property({ tooltip: "是否是垂直滚动" })
set horizontal(value) {
this._horizontal = value;
this._vertical = !value;
}
@property({ tooltip: "是否是垂直滚动" })
get horizontal() {
return this._horizontal;
}
@property({ tooltip: "是否是水平滚动" } || cc.Boolean)
_vertical: boolean = true;
@property({ tooltip: "是否是水平滚动" })
set vertical(value) {
this._horizontal = !value;
this._vertical = value;
}
@property({ tooltip: "是否是水平滚动" })
get vertical() {
return this._vertical;
}
/////////////////////// 缓冲加载添加的变量 ////////////////////////////
//item间隔
@property(cc.Float)
spacing : number = 0;
//创建的itemList
createItemList : cc.Node[] = [];
//创建的itemDataList
createItemDataList : any[] = [];
//数据List
dataList : any[] = [];
//数据的最大数量
maxCount : number = 0;
//item创建的最大数量
@property(cc.Integer)
curMaxCount : number = 5;
//每一个item的高度
@property(Number)
itemHeight : number = 0;
//每一个item的宽度
@property(Number)
itemWidth : number = 0;
viewCal : number = 0;
lastContentPosition: cc.Vec2 = cc.v2(0, 0);
Vec2SVV : cc.Vec2 = cc.p(0, 0);
Vec2SVH : cc.Vec2 = cc.p(0, 0);
////////////////// 多行多列 ////////////////////////
@property(Number)
moreNum : number = 1;
tempV : number = 0;
tempH : number = 0;
/////////////////// 多行多列 ///////////////////////////////
/////////////////// 分页请求数据 ///////////////////////////
changePageCallBack : Function = null;
// 每页显示的请求数据的位置(**比如:当前每页数据量为20,想在第15条的时候,请求下一页的数据,这块就是20 - 15 = showPagePos )
@property(Number)
showPagePos : number = 0;
// 分页提示“正在加载中。。。”的UI
@property(cc.Node)
loadingTips : cc.Node = null;
//数据的最大数量
maxTopNum : number = 0;
//当前翻得页数
curPage : number = 0;
// 防止在弱网情况下,多次请求相同数据
requestData : boolean = false;
/////////////////// 分页请求数据 ///////////////////////////
///////////////////////////////////////////
onLoad(){
this.Init();
}
/**
* 初始化释放池
*/
Init(){
this.itemPool = new cc.NodePool();
}
/**
* 创建节点item
* @param data 相关榜单的数据
*/
CreateItem() : cc.Node {
let item : cc.Node = null;
if(this.itemPerfab != null)
{
(this.itemPool.size() > 0) ? (item = this.itemPool.get()) : (item = cc.instantiate(this.itemPerfab));
}
else
{
ToolsMgr.Get().printAllLog("leaderboard itemPerfab is null!!", LogType.info);
}
return item;
}
// 清空
Clear()
{
this.ClearItemList();
if (!this.itemPool)
return;
while(this.itemPool.size() > 0)
{
let node = this.itemPool.get();
if (!node || !cc.isValid(node))
continue;
node.destroy();
node = null;
}
}
ClearItemList()
{
if (this.createItemList)
{
for(let i = 0; i < this.createItemList.length; ++i)
{
let node = this.createItemList[i];
if (!node || !cc.isValid(node))
continue;
node.removeFromParent(false);
this.createItemDataList[i].Release();
// node.getComponent(this.itemPerfab.name).Release();
node.active = false;
this.itemPool.put(node);
}
}
this.createItemList = [];
this.createItemDataList = [];
}
/**
*
* @param dataList 分页加载时的第一页数据 或者 不是分页加载时的所有数据
* @param closeBack 分页加载时的回调函数,用来返回下一个页数,并向服务器请求数据
* @param maxTopNum 当前数据可显示的最大数据量
* @param curPage 当前页数
*/
initCellDataList(dataList : any[], closeBack ?: Function, maxTopNum ?: number, curPage ?: number){
this.stopAutoScroll();
this.dataList = dataList;
this.createCellList();
if (closeBack) this.changePageCallBack = closeBack;
if (maxTopNum) this.maxTopNum = maxTopNum;
if (curPage) this.curPage = curPage;
}
/**
*
* @param dataList 分页加载时,每一页请求回来的数据
* @param curPage 分页加载时,当前页数
*/
addDataList(dataList : any[], curPage ?: number){
this.showLoadingTips(false);
this.requestData = false;
if(curPage) this.curPage = curPage;
dataList.forEach(data =>{
this.dataList.push(data);
});
this.refreshOnload();
}
/**
* 创建itemList列表,记下当前数据的最大量
*/
private createCellList(){
this.content.height = this.content.parent.height;
this.content.width = this.content.parent.width;
this.ClearItemList();
this.maxCount = this.dataList.length;
if(this._vertical){
this._VerticalOnLoad();
this._createVerticalCellList();
}else{
this._HorizontalOnLoad();
this._createHorizontalCellList();
}
}
/**
* 刷新最大值,重新计算可视范围
*/
private refreshOnload(this){
this.maxCount = this.dataList.length;
if(this._vertical){
this._VerticalOnLoad();
}else{
this._HorizontalOnLoad();
}
}
private _VerticalOnLoad(this){
this.content.setAnchorPoint(cc.p(0.5, 1));
this.viewCal = this.curMaxCount * (this.itemHeight + this.spacing) / 2;
if(this.maxCount % this.moreNum == 0){
this.content.height = this.maxCount / this.moreNum * (this.itemHeight + this.spacing);
}else{
this.content.height = (Math.floor(this.maxCount / this.moreNum) + 1) * (this.itemHeight + this.spacing);
}
}
private _HorizontalOnLoad(){
this.content.setAnchorPoint(cc.p(0, 0.5));
this.viewCal = this.curMaxCount * (this.itemWidth + this.spacing) / 2;
if(this.maxCount % this.moreNum == 0){
this.content.width = this.maxCount / this.moreNum * (this.itemWidth + this.spacing);
}else{
this.content.width = (Math.floor(this.maxCount / this.moreNum) + 1) * (this.itemWidth + this.spacing);
}
}
private _createVerticalCellList(){
if((this.curMaxCount -2) * this.itemHeight > this.content.parent.height){
UIManager.Get().CreatePromptLable("填写的curMaxCount参数大于数据的最大值,请修改!");
ToolsMgr.Get().printAllLog("填写的curMaxCount参数大于数据的最大值,请修改!" + (this.curMaxCount -1) * this.itemHeight + "------" + this.content.parent.height, LogType.info);
return;
}
this.tempV = (this.spacing + this.itemWidth) / 2;
let temp = this.moreNum - 1;
/**
* 为防止滑动到一半的时候会导致切换页面时,获取到的数据是前几个,
* 而当前位置的数据没有刷新,所以在切换页面的时候,直接跳到初始位置
*/
if(this.content.parent.getAnchorPoint().x == 0.5 && this.content.parent.getAnchorPoint().y == 0.5){
this.Vec2SVV = cc.p(this.content.parent.x, this.content.parent.height / 2);
}
this.setContentPosition(this.Vec2SVV);
//根据数据创建所有的item
for(var i = 0; i < this.dataList.length; i++){
if(i > this.curMaxCount * this.moreNum - 1){
return;
}
var item = this.CreateItem();
item.active = true;
this.content.addChild(item);
this.createItemList.push(item);
item["CellID"] = i;
this.createItemDataList.push(item.getComponent(this.itemPerfab.name));
this.createItemDataList[i].SetData(this.dataList[i]);
if( i !== 0 && ( i % this.moreNum === 0 )){
temp = this.moreNum - 1;
}else if(i !== 0 && ( i % this.moreNum !== 0 )){
temp = temp - 2;
}
let y = -item.height * (0.5 + Math.floor(i / this.moreNum)) - this.spacing * (Math.floor(i / this.moreNum) + 1);
item.setPosition( -this.tempV * (temp), y);
}
}
private _createHorizontalCellList(){
if((this.curMaxCount -2) * this.itemWidth > this.content.parent.width){
UIManager.Get().CreatePromptLable("填写的curMaxCount参数大于数据的最大值,请修改!");
ToolsMgr.Get().printAllLog("填写的curMaxCount参数大于数据的最大值,请修改!" + (this.curMaxCount -1) * this.itemWidth + "------" + this.content.parent.width, LogType.info);
return;
}
this.tempH = (this.spacing + this.itemHeight) / 2;
let temp = this.moreNum - 1;
if(this.content.parent.getAnchorPoint().x == 0.5 && this.content.parent.getAnchorPoint().y == 0.5){
this.Vec2SVH = cc.p(-this.content.parent.width / 2, this.content.parent.y);
}
this.setContentPosition(this.Vec2SVH);
//根据数据创建所有的item
for(var i = 0; i < this.dataList.length; i++){
if(i > this.curMaxCount * this.moreNum - 1){
return;
}
var item = this.CreateItem();
item.active = true;
this.content.addChild(item);
this.createItemList.push(item);
item["CellID"] = i;
this.createItemDataList.push(item.getComponent(this.itemPerfab.name));
this.createItemDataList[i].SetData(this.dataList[i]);
if( i !== 0 && ( i % this.moreNum === 0 )){
temp = this.moreNum - 1;
}
if(i !== 0 && ( i % this.moreNum !== 0 )){
temp = temp - 2;
}
// 父节点content的Anchor坐标是(0, 0.5),所以node的y坐标是负值
let x = item.width * (0.5 + Math.floor(i / this.moreNum)) + this.spacing * Math.floor(i / this.moreNum);
item.setPosition(x, this.tempH * (temp));
}
}
private getPosView(item : cc.Node){
let worldPos = item.parent.convertToWorldSpaceAR(item.getPosition());
let viewPos = this.node.convertToNodeSpaceAR(worldPos);
return viewPos;
}
private scrollEvent(sender, event){
if(this._vertical){
this._updateVerticalContentView();
}else{
this._updateHorizontalContentView();
}
}
private _updateVerticalContentView(){
let isDown = this.content.y < this.lastContentPosition.y;
let offsetY = (this.itemHeight + this.spacing) * (this.createItemList.length / this.moreNum);
let newY = 0;
for(var i = 0; i < this.createItemList.length; i++){
let viewPos = this.getPosView(this.createItemList[i]);
if(isDown){ // 数据的值变小
newY = this.createItemList[i].y + offsetY;
if (viewPos.y < -(this.viewCal) && newY < 0){
let item = this.createItemDataList[i];
let itemIdx = this.createItemList[i]["CellID"];
let idx = Number(itemIdx) - this.createItemList.length;
if (idx < 0)
continue;
this.createItemList[i].y = newY;
this.createItemList[i].x = viewPos.x;
if(item){
item.SetData(this.dataList[idx]);
}
this.createItemList[i]["CellID"] = idx;
}
}else{ // 数据的值变大
newY = this.createItemList[i].y - offsetY;
if (viewPos.y > this.viewCal && newY > -this.content.height){
let item = this.createItemDataList[i];
let itemIdx = this.createItemList[i]["CellID"];
let idx = Number(itemIdx) + this.createItemList.length;
if (idx >= this.dataList.length)
continue;
this.createItemList[i].y = newY;
this.createItemList[i].x = viewPos.x;
if(item){
item.SetData(this.dataList[idx]);
}
if(this.changePageCallBack) this.changePage(idx);
this.createItemList[i]["CellID"] = idx;
}
}
}
this.lastContentPosition = this.content.position.clone();
}
private _updateHorizontalContentView(){
let isLeft = this.content.x < this.lastContentPosition.x;
let offsetX = (this.itemWidth + this.spacing) * (this.createItemList.length / this.moreNum);
let newX = 0;
for (var i = 0; i < this.createItemList.length; i++) {
let viewPos = this.getPosView(this.createItemList[i]);
if (isLeft) {
newX = this.createItemList[i].x + offsetX;
if (viewPos.x < -this.viewCal && newX < this.content.width) {
let item = this.createItemDataList[i];
let itemIdx = this.createItemList[i]["CellID"];
let idx = Number(itemIdx) + this.createItemList.length;
if (idx >= this.dataList.length)
continue;
this.createItemList[i].x = newX;
this.createItemList[i].y = viewPos.y;
if(item){
item.SetData(this.dataList[idx]);
}
this.createItemList[i]["CellID"] = idx;
}
} else {
newX = this.createItemList[i].x - offsetX;
if (viewPos.x > this.viewCal && newX >= 0) {
let item = this.createItemDataList[i];
let itemIdx = this.createItemList[i]["CellID"];
let idx = Number(itemIdx) - this.createItemList.length;
if (idx < 0)
continue;
this.createItemList[i].x = newX;
this.createItemList[i].y = viewPos.y;
if(item){
item.SetData(this.dataList[idx]);
}
this.changePage(idx);
this.createItemList[i]["CellID"] = idx;
}
}
}
this.lastContentPosition = this.content.position.clone();
}
changePage(idx : number){
try
{
if(!this.changePageCallBack)
return;
if (this.requestData)
return;
let page = this.dataList.length - this.showPagePos;
if(idx >= this.showPagePos && idx == page && this.dataList.length < this.maxTopNum){
// this.loadingTips.setPositionY(-this.loadingTips.parent.height / 2 + this.loadingTips.height / 2);
if((this.curPage + 1) != 1){
this.showLoadingTips(true);
}
this.requestData = true;
this.changePageCallBack(this.curPage + 1);
}
}
catch(e)
{
cc.error("BaseScrollView:changePage catch err " + e.message);
}
}
showLoadingTips(isShow : boolean){
if(this.loadingTips) this.loadingTips.active = isShow;
}
}
-
代码块的使用方法:
changePageCallBack(curPage : number){ ToolsMgr.Get().printAllLog("数值在变大。。。。:", LogType.info); LeaderboardLayer.curPage = curPage; LeaderboardModel.Get().RequestData(LeaderboardLayer.curListType, LeaderboardLayer.curPage); } RefreshSV(dataList : Array<any>, maxTopNum : number, curPage ?: number){ this.scrollView.stopAutoScroll(); this.scrollView.getComponent(BaseScrollView).initCellDataList(dataList, this.changePageCallBack, maxTopNum, curPage); }
在需要使用循环加载或者分页加载的节点上的ScrollView组件移除,并将BaseScrollView脚本挂上去,然后设置参数如下:
注意:
1、ScrollEvents要设置
2、itemPerfab : 循环加载的itemPerfab,Perfab的名字一定要跟Perfab所挂的脚本的名字一致,这个没想到解决办法,有更好方法的小伙伴,可以给我留言哦~~~
3、CurMaxCount:当前可视范围内可显示的最大的item数量
4、itemHeight:itemPerfab的高度
5、itemWidth:itemPerfab的宽度
6、MoreNum:多行多列时使用的数据,默认为1
7、ShowPagePos:在什么位置进行下一页数据的加载
(比如:当前每页数据量为20,想在第15条的时候,请求下一页的数据,这块就是20 - 15 = showPagePos)
8、LoadingTips:分页加载时,“加载中。。。”的tips的UI