微日志_免费提供日志记录|作品展示|学习教程|免费日记

LayaBox2.0教你如何实现ScrollView效果?

LayaBox 游戏引擎 阅读:133

体验地址:暂无地址

在LayaBox开放引擎中,封装还比较完善,但是某些功能还是需要我们自己写的,比如我们要实现一个ScrollView效果,这个时候我们就不能使用普通的List去实现了,需要我们自己去完成封装,这一篇博客,我将记录我自己如何封装一个List,实现ScrollView效果。

在使用Laya开发中,要实现一个滚动列表,可是使用List组件,但是要实现一些复杂的功能,可能就需要我们自行进行封装了,比如说要实现一个如下效果:



看了以后,发现普通的List是无法实现这个效果的,那么这篇我们将记录一下,如何使用Laya封装一个自己的ScrollView。

要封装ScrollView,我们需要重写一下List,由于本人习惯直接使用代码去操作,所有在下面我们直接上代码:

1. 新建项目

本项目以TS为例,具体创建过程就不说了,如果不会的可以看我前面的记录,一样的。

2. ScrollView类

自定义ScrollView类,在src目录下新建ScrollView.ts,然后进入该文件,开始封装ScrollView类,由于代码注释齐全,所以我们就不加以解释了,实现思路也就是继承Box,然后实现IItem以及IRender接口,去重写一些方法等。代码如下:

//自定义滚动类,继承BOX,并实现IRedner以及IItem接口
export default class ScrollView extends Laya.Box implements Laya.IRender, Laya.IItem {
private array: Array<any>; //数据源
private renderHandler: Laya.Handler; //每个单元格渲染处理器
private mouseHandler: Laya.Handler; //单元格鼠标事件处理器
private selectHandler: Laya.Handler;//选中的时候的处理器
/*****记录是否有已经渲染过单元格了******/
private haveRender: boolean = false;
private haveInit: boolean = false;
private haveInitItem: boolean = false;
//鼠标抬起后,是否继续滑动单元格
private sensitive: boolean = true;
//单元格的宽高
private cellWidth: number;
private cellHeight: number;
//左右边距
private spaceLeft: number = 0;
private spaceRight: number = 0;
//单元格集合
private cells: Array<any>;
private itemRender: any;
//单元格之间间距
private space: number = 0;
constructor() {
super();
this.mouseEnabled = true;
//初始化鼠标事件
this.on(Laya.Event.MOUSE_DOWN, this, this.mouseDown);
this.on(Laya.Event.MOUSE_UP, this, this.mouseUp, [Laya.Event.MOUSE_UP]); //正常的抬起
this.on(Laya.Event.MOUSE_MOVE, this, this.mouseMove);
this.on(Laya.Event.MOUSE_OUT, this, this.mouseUp, [Laya.Event.MOUSE_OUT]); //离开后抬起
}
//初始化单元格数据
private init(): void {
if (!this.haveInit) {
// 初始化单元格
this.initItems();
// 初始化渲染
this.initRender();
if (this.haveInitItem && this.haveRender) {
this.haveInit = true;
}
}
}
//设置数据源接口
public set setArray(array: Array<any>) {
this.array = array;
//设置完数据以后,从新渲染一次
this.init();
}
//获取数据源
public get getArray(): Array<any> {
return this.array;
}
//设置单元格渲染
public set setItemRender(itemRender: any) {
this.itemRender = itemRender; //设置完单元格数据以后,在进行初始化一次
this.init();
}
//设置单元格处理器
public set setRenderHandler(hander: Laya.Handler) {
this.renderHandler = hander;
this.init();
}
//设置鼠标处理器
public set setMouseHandler(hander: Laya.Handler) {
this.mouseHandler = hander;
}
//设置选中处理器
public set setSelectHandler(hander: Laya.Handler) {
this.selectHandler = hander;
}
//设置单元格的宽度,高度,设置左边距右边距,获取宽度高度左边距右边距
public set setCellWidth(cellWidth: number) {
this.cellWidth = cellWidth;
}
public get getCellWidth(): number {
return this.cellWidth;
}
public set setCellHeight(cellHeight: number) {
this.cellHeight = cellHeight;
}
public get getCellHeight(): number {
return this.cellHeight;
}
public set setSpaceLeft(spaceLeft: number) {
this.spaceLeft = spaceLeft;
}
public get getSpaceLeft(): number {
return this.spaceLeft;
}
public set setSpaceRight(spaceRight: number) {
this.spaceRight = spaceRight;
}
public get getSpaceRight(): number {
return this.spaceRight;
}
//添加单元格
public addItem(item: any): void { }
//获取单元格
/**
* 通过索引获取对应的单元格
* @param index
*/
public getItemByIndex(index: number): any {
return this.cells[index];
}
/**
* 根据单元格获取单元格的位置
* @param cell
*/
public getItemIndex(cell: any): number {
for (var i = 0; i < this.cells.length; i++) {
if (cell == this.cells[i]) {
return i;
}
}
return -1;
}
/**
* 单元格响应事件
*/
private onCellEvent(event: Event, cell: any) {
var index = this.getItemIndex(cell);
if (index == -1) {
return;
}
if (this.selectHandler) {
this.selectHandler.runWith([event, index]);
}
}
//实现接口,初始化所有单元格
public initItems(): void {
if (!this.haveInitItem && this.itemRender != null && this.array != null && this.array.length > 0) {
this.cells = new Array<any>()
for (var i = 0; i < this.array.length; i++) {
let item = new this.itemRender(this.cellWidth, this.cellHeight);
if (this.array[i] instanceof Laya.Sprite || this.array[i] instanceof Laya.Box || this.array[i] instanceof Laya.Image) { //如果是其原型,则添加为子对象
item.addChild(this.array[i]);
}else if(this.array[i] instanceof String || this.array[i] instanceof Number || this.array[i] instanceof Boolean){
item.custom=this.array[i]; //自定义属性
}
this.cells.push(item);
this.addChild(item);
}
this.haveInitItem = true;
//调用刷新单元格位置
this.refreshCellsPos();
}
}
/**
* 所有单元格执行渲染
*/
private initRender(): void {
if (!this.haveRender && this.renderHandler != null && this.array != null && this.array.length > 0) {
for (var i = 0; i < this.array.length; i++) {
this.renderHandler.runWith([this.cells[i], i]);
}
this.haveRender = true;
}
}
/**
* 刷新ScrollView下Cell的位置
*/
private refreshCellsPos() {
var cellCount = this.cells.length;
for (var i = 0; i < cellCount; i++) {
let cell: Laya.Box = this.cells[i] as Laya.Box;
let posX: number = this.getCellPosByIndex(i);
let posY: number = cell.height;
cell.pos(posX, posY / 2);
}
this.width = this.spaceLeft + cellCount * this.cellWidth + (cellCount - 1) * this.space + this.spaceRight;
}
/**
* 单个单元格执行渲染
*/
private doSingleRender(index: number): void {
if (!this.haveRender) {
this.initRender();
return;
}
if (this.renderHandler != null) {
this.renderHandler.runWith([this.cells[index], index]);
}
}
/**
* 根据单元格索引获取单元格位置
* @param index
*/
public getCellPosByIndex(index: number): number {
return this.spaceLeft + (index + 0.5) * this.cellWidth + index * this.space;
}
//鼠标操作事件
private mouseDown() {
if (this.mouseHandler != null) {
var e: Event = new Event(Laya.Event.MOUSE_DOWN);
this.mouseHandler.runWith([e]);
}
}
/**
* 鼠标离开屏幕
*/
private mouseUp(event: string) {
if (this.mouseHandler != null) {
var e: Event = new Event(Laya.Event.MOUSE_UP);
this.mouseHandler.runWith([e]);
}
}
/**
* 鼠标移动
*/
private mouseMove() {
if (this.mouseHandler != null) {
var e: Event = new Event(Laya.Event.MOUSE_MOVE);
this.mouseHandler.runWith([e]);
}
}
}

3. 使用ScrollView

使用也就是直接实例化这个类,然后去设置数据源,设置位置,绑定事件(鼠标事件,点击事件等),设置渲染事件等等。代码注释齐全,具体代码如下:

private scrollView: any; //scrollView
// 鼠标按下
private mouseDownEvent: boolean = false;
// 鼠标移动速度
private mouseSpeed: number = 0;
private mouseStartEventX: number = 0; //鼠标开始位置
private curMoveFrame: number = 0;
private itemMaxScale: number = 1; //最大缩放比
private itemMinScale: number = .6; //最小缩放比
private startX:number=0; //记录开始位置
private mouseDownEventOpen:boolean=true;//是否开始点击
private deviation:boolean=false;//是否偏离
private mouseEventX: number = 0;
onConfigLoaded(): void {
//加载IDE指定的场景
//使用ScrollView
this.scrollView = new ScrollView(); //实例化列表
Laya.stage.addChild(this.scrollView);
//启动侦听器,自动回笼中间元素
Laya.timer.frameLoop(1, this, this.onUpdate);
//生成数据源
var array = [];
for (var i: number = 0; i < 10; ++i) {
// array.push('zs.png');
let sp:any=new Laya.Sprite();
sp.loadImage('zs.png');
sp.width=300;
sp.height=300;
if(i%2==0)sp.price='分享获得';
else if(i%5==0)sp.price='看视频获得';
else
sp.price=1000;
//此处传递的是一个对象
array.push(sp);
}
this.btmBye(); //添加购买按钮
this.scrollView.setArray = array; //设置数据源//这里调用的是setter方法
this.initScrollView(); //初始化信息
this.scrollView.setRenderHandler = new Laya.Handler(this, this.onScrollRender);
this.scrollView.setMouseHandler = new Laya.Handler(this, this.onScrollMouse);
this.centeringControl(0); //设置第一个居中
this.updateScale(0); //设置第一个缩放
}
//设置自动居中效果
private onUpdate() {
if (!this.mouseDownEvent && this.mouseSpeed != 0) {
var direction = Math.abs(this.mouseSpeed) / this.mouseSpeed;
var absSpeed = Math.sqrt(Math.abs(this.mouseSpeed));
var moveDis = this.mouseSpeed;
this.updateScrollViewPos(moveDis);
this.updateScale();
absSpeed = absSpeed - 0.3;
if (absSpeed < 1) {
absSpeed = 0;
this.mouseSpeed = 0;
// 居中显示
this.centeringControl();
} else {
this.mouseSpeed = absSpeed * absSpeed * direction;
}
}
}
//渲染的时候更新,绑定点击事件
private onScrollRender(cell: Laya.Box, index: number) {
// console.log(cell,index)
if(this.mouseDownEventOpen){
cell.on(Laya.Event.CLICK,this,(e:Laya.Event)=>{
if(!this.deviation){
//鼠标是否在原位置
console.log('CLICK ME!');
}
})
}
}
//自定义滚动
/**
* ScrollView鼠标操作响应
* @param e
*/
private onScrollMouse(e: Event) {
// 移动ScrollView时其中单元格缩放
if (e.type == Laya.Event.MOUSE_DOWN) {
this.mouseDown();
} else if (e.type == Laya.Event.MOUSE_UP) {
this.mouseUp();
} else if (e.type == Laya.Event.MOUSE_MOVE) {
this.mouseMove();
}
}
/**
* 鼠标按下响应事件
*/
private mouseDown() {
this.deviation=false;
this.mouseDownEvent = true;
this.mouseStartEventX = Laya.MouseManager.instance.mouseX;
this.mouseEventX = Laya.MouseManager.instance.mouseX;
}
/**
* 鼠标抬起响应事件
*/
private mouseUp() {
if (!this.mouseDownEvent) {
return;
}
var stableFrame = Laya.timer.currFrame - this.curMoveFrame;
// 滑动
if (stableFrame > 2) {
this.mouseSpeed = 0;
this.centeringControl();
}
this.mouseDownEvent = false;
}
/**
* 鼠标移动事件响应
*/
private mouseMove() {
if (this.mouseDownEvent) {
this.deviation=true;
var dis = Laya.MouseManager.instance.mouseX - this.mouseEventX;
this.mouseEventX = Laya.MouseManager.instance.mouseX;
this.updateScrollViewPos(dis);
this.updateScale();
this.curMoveFrame = Laya.timer.currFrame;
this.mouseSpeed = dis;
}
}
/**
* 调整图像大小
*/
//更新缩放,设置元素缩放
private updateScale(startNum:number=-1) {
var centerIndex = startNum==-1?this.getScreenCenterCellIndex():startNum;
var leftIndex = Math.max(centerIndex - 1, 0);
var rightIndex = Math.min(centerIndex + 1, this.scrollView.array.length - 1);
var scrollPosX = this.scrollView.x;
var centerPos = Laya.stage.width / 2 - scrollPosX;
for (var index = leftIndex; index <= rightIndex; index++) {
let cellPos = this.scrollView.getCellPosByIndex(index);
let cellDis = Math.abs(cellPos - centerPos);
if (cellDis < 180) {
let scaleRate = this.itemMaxScale - (this.itemMaxScale - this.itemMinScale) / 180 * cellDis;
let item: Item = this.scrollView.getItemByIndex(index) as Item;
item.alpha=1; //选中状态,中间元素
item.scale(scaleRate, scaleRate);
// console.log(item)
this.setByeText(item._children[0].price); //获取自定义属性
} else {
let item: Item = this.scrollView.getItemByIndex(index) as Item;
item.graphics.clear();
item.alpha=.2; //设置很透明
item!=undefined && item!=null && Laya.Tween.to(item, {
scaleX:.4,
scaleY:.4
}, 0, Laya.Ease.linearInOut);
}
}
}
//获取屏幕中间的单元格
public getScreenCenterCellIndex(): number {
var distance = -this.scrollView.x;
var index: number = (distance - this.scrollView.spaceLeft + this.scrollView.space + (Laya.stage.width + this.scrollView.cellWidth) / 2) / (this.scrollView.cellWidth + this.scrollView.space);
return Math.round(index) - 1;
}
/**
* 将角色居中显示
* startNum:设置哪个角色居中,默认不设置
*/
private centeringControl(sartNum:number=-1) {
var centerIndex = sartNum==-1?this.getScreenCenterCellIndex():sartNum;
var cellPosX = this.getCellPosByIndex(centerIndex);
var posX = Laya.stage.width / 2 - cellPosX;
if(sartNum==-1)
Laya.Tween.to(this.scrollView, { x: posX }, 500, Laya.Ease.cubicOut).update = new Laya.Handler(this, this.updateScale);
else{
this.scrollView.x=posX;
this.startX=posX;}
}
/**
* 根据单元格索引获取单元格位置
* @param index
*/
public getCellPosByIndex(index: number): number {
return this.scrollView.spaceLeft + (index + 0.5) * this.scrollView.cellWidth + index * this.scrollView.space;
}
//初始化信息
private initScrollView() {
// this.scrollView.setSpaceLeft = 100;
// this.scrollView.setSpaceRight = 100;
this.scrollView.space = 50; //设置左右间距
this.scrollView.setCellWidth = 300; //方块的宽高
this.scrollView.setCellHeight = 300;
this.scrollView.setItemRender = Item; //渲染类
this.scrollView.height = 300; //view的高度
this.scrollView.pos(0, 200); //位置
}
/**
* 设置元素滚动
* dis:距离
* ***/
private updateScrollViewPos(dis: number) {
var posX: number = dis + this.scrollView.x;
if (posX > this.startX) { //开始的位置 0位置,如果需要其他位置,自行调试
posX = this.startX;
}
var posEnd:number = Laya.stage.width / 2 - this.getCellPosByIndex(this.scrollView.array.length-1);
if (posX < posEnd) { //结束的位置
posX = posEnd;
}
this.scrollView.pos(posX, this.scrollView.y);
}
private byeText:Laya.Text;
//增加下方购买按钮
private btmBye():void{
let byeBtn:Laya.Sprite=new Laya.Sprite();
byeBtn.loadImage('byebtn.png');
byeBtn.width=233;
byeBtn.height=122;
byeBtn.pos((Laya.stage.width-byeBtn.getBounds().width)/2,(Laya.stage.height-byeBtn.getBounds().height)/2);
this.byeText=new Laya.Text();
this.byeText.width=byeBtn.getBounds().width;
this.byeText.align='center';
this.byeText.fontSize=40;
this.byeText.color='#fff';
this.byeText.text=``;
this.byeText.pos(0,(122-40)/2);
byeBtn.addChild(this.byeText);
Laya.stage.addChild(byeBtn);
byeBtn.on(Laya.Event.CLICK,this,(e:Laya.Event)=>{
let target:any=e.target;
console.log('购买价格',target.price);
})
}
//更新内容
private setByeText(str:any):void{
this.byeText.text=`${str}`;
Object.defineProperty(this.byeText.parent,'price',{
writable:true,
value:typeof str == 'number'? str:-1
})
}

4. 渲染项的类

class Item extends Laya.Box {
private sprite:Laya.Sprite;
constructor(w:number,h:number) {
super();
this.pivot(w/2,h/2); //设置居中
this.size(w, h);
}
public set setImage(url:string){
this.sprite.loadImage(url);
}
}

以上就是 完整的教程了, 如果有不明白的,可以随时问我,也可以查看github地址:https://github.com/vlinr/ScrollView 进行学习,如果您觉得对你有帮助得话,记得支持一下站长哟,以便于写出更好得东西帮助到大家。