Skip to content
UI 拖拽事件

UI 拖拽事件

阅读本文大概需要 15 分钟

本文档介绍了如何制作可进行拖放操作的UI,这常用于实现背包内物品拖拽的效果

UI拖拽事件及相关函数

onDragDetected(InGemotry :Geometry,InPointerEvent:PointerEvent) : DragDropOperation

  • 当触发拖拽时返回一次生成的拖拽事件
  • InGeometry :Geometry可以用来获取UI的坐标信息
  • InPointerEvent:PointerEvent可以用来获取鼠标点击或者滑动的信息
  • 注意需要先在onTouch事件中调用detectDrag(dragKey: Keys): EventReply或者detectDragIfPressed(inPointEvent: PointerEvent, dragKey: Keys): EventReply,这代表开始进行检测是否有拖拽操作,这之后才能触发onDragDetected事件
  • 在onDragDetected事件里使用newDragDrop(inVisualWidget: Widget, inTag?: string, inPayLoad?: any, inPivot?: DragPivot, inOffset?: Vector2): DragDropOperation来返回新的拖拽事件
    • inVisualWidget: Widget 传入所生成的拖拽事件在拖拽时展示的UI,注意拖拽用于展示的UI内容会在之后销毁,因此这里最好使用新建的临时UI
    • inTag?: string 传入所生成的拖拽事件的标签文本
    • inPayLoad?: any 传入拖拽事件数据信息
    • inPivot?: DragPivot 传入拖拽显示UI的锚点
    • inOffset?: Vector2 传入拖拽显示UI相对于锚点的偏移的百分比,inPivot和inOffset共同决定了鼠标点击或滑动处与此展示UI的相对位置

示例:

ts
     /**
     * 当这个UI界面是可以接收事件的时候
     * 手指或则鼠标触发一次Touch时触发
     * 返回事件是否处理了
     * 如果处理了,那么这个UI界面可以接收这次Touch后续的Move和End事件
     * 如果没有处理,那么这个UI界面就无法接收这次Touch后续的Move和End事件
     */
    onTouchStarted(InGeometry :Geometry,InPointerEvent:PointerEvent) :EventReply{
        return this.detectDragIfPressed(InPointerEvent, Keys.AnyKey)
    }
      /**
     * 当在UI界面上调用detectDrag/detectDragIfPressed时触发一次
     * 可以触发一次拖拽事件的开始生成
     * 返回一次生成的拖拽事件 newDragDrop可以生成一次事件
     */
    protected onDragDetected(InGemotry :Geometry,InPointerEvent:PointerEvent):DragDropOperation {
        let ui=createUIByName("NewUI")
        return this.newDragDrop(ui,"DragDropTag",null,DragPivot.CenterCenter,Vector2.zero);
    }
     /**
     * 当这个UI界面是可以接收事件的时候
     * 手指或则鼠标触发一次Touch时触发
     * 返回事件是否处理了
     * 如果处理了,那么这个UI界面可以接收这次Touch后续的Move和End事件
     * 如果没有处理,那么这个UI界面就无法接收这次Touch后续的Move和End事件
     */
    onTouchStarted(InGeometry :Geometry,InPointerEvent:PointerEvent) :EventReply{
        return this.detectDragIfPressed(InPointerEvent, Keys.AnyKey)
    }
      /**
     * 当在UI界面上调用detectDrag/detectDragIfPressed时触发一次
     * 可以触发一次拖拽事件的开始生成
     * 返回一次生成的拖拽事件 newDragDrop可以生成一次事件
     */
    protected onDragDetected(InGemotry :Geometry,InPointerEvent:PointerEvent):DragDropOperation {
        let ui=createUIByName("NewUI")
        return this.newDragDrop(ui,"DragDropTag",null,DragPivot.CenterCenter,Vector2.zero);
    }

onDrop(InGemotry :Geometry,InDragDropEvent:PointerEvent,InDragDropOperation:DragDropOperation) : boolean

  • 拖拽事件在这个UI完成释放时触发,返回true表示处理完成这次事件;这里可以编写释放UI时想要触发的逻辑
  • 拖拽事件所展示的UI会自动销毁,如果仍想要展示此UI需要重新创建

示例:

ts
    /**
     * 拖拽操作生成事件触发后在这个UI释放完成时
     * 返回true的话表示处理了这次事件,不会再往这个UI的下一层的UI继续冒泡这个事件
     */
    protected onDrop(InGemotry :Geometry,InDragDropEvent:PointerEvent,InDragDropOperation:DragDropOperation):boolean {
        let UI1=createUIByName("NewUI")
        this.uiWidgetBase.rootContent.addChild(UI1)
        UI1.position=(new Vector2(absoluteToLocal(InGemotry,InDragDropEvent.screenSpacePosition).x-UI1.size.x*0.5,absoluteToLocal(InGemotry,InDragDropEvent.screenSpacePosition).y-UI1.size.y*0.5))
        return true;
    }
    /**
     * 拖拽操作生成事件触发后在这个UI释放完成时
     * 返回true的话表示处理了这次事件,不会再往这个UI的下一层的UI继续冒泡这个事件
     */
    protected onDrop(InGemotry :Geometry,InDragDropEvent:PointerEvent,InDragDropOperation:DragDropOperation):boolean {
        let UI1=createUIByName("NewUI")
        this.uiWidgetBase.rootContent.addChild(UI1)
        UI1.position=(new Vector2(absoluteToLocal(InGemotry,InDragDropEvent.screenSpacePosition).x-UI1.size.x*0.5,absoluteToLocal(InGemotry,InDragDropEvent.screenSpacePosition).y-UI1.size.y*0.5))
        return true;
    }

onDragEnter(InGemotry :Geometry,InDragDropEvent:PointerEvent,InDragDropOperation:DragDropOperation) : void

  • 当有正在拖拽的UI进入这个UI的范围内时触发

示例:

ts
    /**
     * 拖拽操作生成事件触发后进入这个UI时触发
     */
    protected onDragEnter(InGemotry :Geometry,InDragDropEvent:PointerEvent,InDragDropOperation:DragDropOperation) {
        console.warn("onDragEnter"+InDragDropEvent.screenSpacePosition)
    }
    /**
     * 拖拽操作生成事件触发后进入这个UI时触发
     */
    protected onDragEnter(InGemotry :Geometry,InDragDropEvent:PointerEvent,InDragDropOperation:DragDropOperation) {
        console.warn("onDragEnter"+InDragDropEvent.screenSpacePosition)
    }

onDragLeave(InDragDropEvent:PointerEvent,InDragDropOperation : DragDropOperation) : void

  • 当有正在拖拽的UI离开这个UI的范围内时触发

示例:

ts
    /**
     * 拖拽操作生成事件触发后离开这个UI时触发
     */
    protected onDragLeave(InDragDropEvent:PointerEvent,InDragDropOperation : DragDropOperation) {
        console.warn("onDragLeave"+InDragDropEvent.screenSpacePosition)
    }
    /**
     * 拖拽操作生成事件触发后离开这个UI时触发
     */
    protected onDragLeave(InDragDropEvent:PointerEvent,InDragDropOperation : DragDropOperation) {
        console.warn("onDragLeave"+InDragDropEvent.screenSpacePosition)
    }

onDragCancelled(InDragDropEvent:PointerEvent,InDragDropOperation : DragDropOperation) : void

  • 拖拽事件没有被完成而是取消时触发
  • 如果释放的时候没有触发onDrop事件就结束了,则会触发onDragCancelled;也可以通过函数cancelDragDrop/endDragDrop来取消拖拽事件

示例:

ts
    /**
     * 拖拽操作生成事件触发后,拖拽事件没有完成而是取消时触发
     */
    protected onDragCancelled(InDragDropEvent:PointerEvent,InDragDropOperation : DragDropOperation) {
        console.warn("onDragCancelled")
    }
    /**
     * 拖拽操作生成事件触发后,拖拽事件没有完成而是取消时触发
     */
    protected onDragCancelled(InDragDropEvent:PointerEvent,InDragDropOperation : DragDropOperation) {
        console.warn("onDragCancelled")
    }

onDragOver(InGeometry :Geometry,InDragDropEvent:PointerEvent,InDragDropOperation:DragDropOperation):boolean

  • 当有正在拖拽的UI经过这个UI的范围内时触发,返回true表示处理完成这次事件

示例:

ts
    /**
     * 拖拽操作生成事件触发后经过这个UI时触发
     * 返回true的话表示处理了这次事件,不会再往这个UI的下一层的UI继续冒泡这个事件
     */
    protected onDragOver(InGeometry :Geometry,InDragDropEvent:PointerEvent,InDragDropOperation:DragDropOperation):boolean {
        console.warn("onDragOver"+InDragDropEvent.screenSpacePosition)
        return true;
    }
    /**
     * 拖拽操作生成事件触发后经过这个UI时触发
     * 返回true的话表示处理了这次事件,不会再往这个UI的下一层的UI继续冒泡这个事件
     */
    protected onDragOver(InGeometry :Geometry,InDragDropEvent:PointerEvent,InDragDropOperation:DragDropOperation):boolean {
        console.warn("onDragOver"+InDragDropEvent.screenSpacePosition)
        return true;
    }

其他相关函数

  • UIBehavior类下的detectDrag/detectDragIfPressed函数,用于开始检测是否有拖拽操作
  • UIBehavior类下的newDragDrop函数,用于创建新的拖拽事件
    • 这三个函数在前文onDragDetected的部分已经介绍过了

示例:

ts
    class UIBehavior {
        /**
         * @description 触发DragDrop事件的检测
         * @effect  只在客户端调用生效
         * @param dragKey usage:触发按键 default:Keys
         * @returns 返回触发的事件回复
         */
        detectDrag(dragKey: Keys): EventReply;
        /**
         * @description 如果事件检测通过就触发DragDrop事件的回复
         * @effect  只在客户端调用生效
         * @param inPointEvent usage:传递触发的事件信息
         * @param dragKey usage:触发按键
         * @returns 返回触发的事件回复
         */
        detectDragIfPressed(inPointEvent: PointerEvent, dragKey: Keys): EventReply;
        /**
         * @description 创建DragDrop事件
         * @effect  只在客户端调用生效
         * @param inVisualWidget usage:拖拽显示的UI控件
         * @param inTag usage:标签文本 default:""
         * @param inPayLoad usage:拖拽事件数据信息 default:null
         * @param inPivot usage:拖拽显示UI的锚点 default:UIDragPivot.TopLeft
         * @param inOffset usage:拖拽显示UI相对于锚点的偏移的百分比 default:vector2(0,0)
         * @returns 返回触发的事件回复
         */
        newDragDrop(inVisualWidget: Widget, inTag?: string, inPayLoad?: any, inPivot?: DragPivot, inOffset?: Vector2): DragDropOperation;
    }
    class UIBehavior {
        /**
         * @description 触发DragDrop事件的检测
         * @effect  只在客户端调用生效
         * @param dragKey usage:触发按键 default:Keys
         * @returns 返回触发的事件回复
         */
        detectDrag(dragKey: Keys): EventReply;
        /**
         * @description 如果事件检测通过就触发DragDrop事件的回复
         * @effect  只在客户端调用生效
         * @param inPointEvent usage:传递触发的事件信息
         * @param dragKey usage:触发按键
         * @returns 返回触发的事件回复
         */
        detectDragIfPressed(inPointEvent: PointerEvent, dragKey: Keys): EventReply;
        /**
         * @description 创建DragDrop事件
         * @effect  只在客户端调用生效
         * @param inVisualWidget usage:拖拽显示的UI控件
         * @param inTag usage:标签文本 default:""
         * @param inPayLoad usage:拖拽事件数据信息 default:null
         * @param inPivot usage:拖拽显示UI的锚点 default:UIDragPivot.TopLeft
         * @param inOffset usage:拖拽显示UI相对于锚点的偏移的百分比 default:vector2(0,0)
         * @returns 返回触发的事件回复
         */
        newDragDrop(inVisualWidget: Widget, inTag?: string, inPayLoad?: any, inPivot?: DragPivot, inOffset?: Vector2): DragDropOperation;
    }
  • 还有一些拖拽事件相关的函数,可以用来中断/获取/判断当前的拖拽事件
ts
declare namespace UI {
        /**
         * @description 中断一个拖拽事件, 传入一个操作的事件
         * @effect 只在客户端调用生效
         * @param InReply usage:事件
         */
        function endDragDrop(InReply: EventReply): void;
        /**
         * @description 中断所有的DragDrop
         * @effect 只在客户端调用生效
         */
        function cancelDragDrop(): void;
        /**
         * @description 判断当前是否有一个DragDrop事件
         * @effect 只在客户端调用生效
         * @returns boolean
         */
        function isDragDropping(): boolean;
        /**
         * @description 获取当前的DragDrop事件
         * @effect 只在客户端调用生效
         * @returns 返回当前的DragDrop事件
         */
        function getDragDroppingContent(): DragDropOperation;
    }
declare namespace UI {
        /**
         * @description 中断一个拖拽事件, 传入一个操作的事件
         * @effect 只在客户端调用生效
         * @param InReply usage:事件
         */
        function endDragDrop(InReply: EventReply): void;
        /**
         * @description 中断所有的DragDrop
         * @effect 只在客户端调用生效
         */
        function cancelDragDrop(): void;
        /**
         * @description 判断当前是否有一个DragDrop事件
         * @effect 只在客户端调用生效
         * @returns boolean
         */
        function isDragDropping(): boolean;
        /**
         * @description 获取当前的DragDrop事件
         * @effect 只在客户端调用生效
         * @returns 返回当前的DragDrop事件
         */
        function getDragDroppingContent(): DragDropOperation;
    }
ts
    class DragDropOperation {
        /**
         * @description 判断是否相同
         * @effect 只在客户端调用生效
         * @param other usage:另一个UI拖拽事件
         * @returns boolean
         */
        equal(other: DragDropOperation): boolean;
        /**
         * @description 获取Tag 标签
         * @effect 只在客户端调用生效
         * @returns 返回tag
         */
        getTag(): string;
        /**
         * @description 获取拖拽显示的UI
         * @effect 只在客户端调用生效
         * @returns 拖拽显示的UI
         */
        getDragVisualWidget(): Widget;
        /**
         * @description 获取拖拽锚点
         * @effect 只在客户端调用生效
         * @returns 拖拽锚点
         */
        getDragPivot(): DragPivot;
        /**
         * @description 获取拖拽UI的百分比偏移
         * @effect 只在客户端调用生效
         * @returns 百分比偏移
         */
        getOffset(): Vector2;
        /**
         * @description 获取传递的数据信息
         * @effect 只在客户端调用生效
         * @returns 数据信息
         */
        tryGetDragDropPayLoad(): DragDropPayLoad;
        /**
         * @description 获取传递的数据信息
         * @effect 只在客户端调用生效
         * @returns 数据信息
         */
        tryGetDragDropPayLoadAs<T extends DragDropPayLoad>(): T;
    }
    class DragDropOperation {
        /**
         * @description 判断是否相同
         * @effect 只在客户端调用生效
         * @param other usage:另一个UI拖拽事件
         * @returns boolean
         */
        equal(other: DragDropOperation): boolean;
        /**
         * @description 获取Tag 标签
         * @effect 只在客户端调用生效
         * @returns 返回tag
         */
        getTag(): string;
        /**
         * @description 获取拖拽显示的UI
         * @effect 只在客户端调用生效
         * @returns 拖拽显示的UI
         */
        getDragVisualWidget(): Widget;
        /**
         * @description 获取拖拽锚点
         * @effect 只在客户端调用生效
         * @returns 拖拽锚点
         */
        getDragPivot(): DragPivot;
        /**
         * @description 获取拖拽UI的百分比偏移
         * @effect 只在客户端调用生效
         * @returns 百分比偏移
         */
        getOffset(): Vector2;
        /**
         * @description 获取传递的数据信息
         * @effect 只在客户端调用生效
         * @returns 数据信息
         */
        tryGetDragDropPayLoad(): DragDropPayLoad;
        /**
         * @description 获取传递的数据信息
         * @effect 只在客户端调用生效
         * @returns 数据信息
         */
        tryGetDragDropPayLoadAs<T extends DragDropPayLoad>(): T;
    }

UI拖拽事件及相关函数

示例一:制作一张最简单的可拖拽图片

  • step.1 新建一个NewUI文件,并把允许拖动的UI内容单独放在这个UI文件里面作为一个自定义UI控件,然后编写脚本
  • 在这个例子中,我们想要拖拽的是一张空白图片
  • 注意应将Root的对齐方式设置为左上对齐,并且把图片的可见性设置为可见

TypeScript
import NewUI_generate from "./ui-generate/NewUI_generate";

//创建一个继承DragDropPayLoad的TestDragDropPayLoad类,传入newDragDrop函数作为参数payLoad,跟随拖拽事件传递一些信息
export class TestDragDropPayLoad extends DragDropPayLoad {

    private test1 : UserWidget ;
    public get Test1() {
        return this.test1;
    }
    public set Test1(v :UserWidget) {
         this.test1 = v;
    }
}

export default class NewUIScript extends NewUI_generate {
	/** 
	 * 构造UI文件成功后,在合适的时机最先初始化一次 
	 */
	protected onStart() {
		//设置能否每帧触发onUpdate
		this.canUpdate = false;
		this.layer = UILayerMiddle;
		console.log("________");
	}

    //当玩家触摸到此UI时,开始检测是否发生拖拽操作
	onTouchStarted(InGeometry :Geometry,InPointerEvent:PointerEvent) :EventReply{
        console.log("OnTouch"+InPointerEvent.screenSpacePosition)
        return this.detectDragIfPressed(InPointerEvent, Keys.AnyKey)
    }
    //当玩家触摸到此UI时,开始检测是否发生拖拽操作
    onTouchEnded(InGemetry: Geometry, InPointEvent: PointerEvent): EventReply {
        return EventReply.handled;
    }
        //当检测到发生拖拽操作时,创建一个新的拖拽事件,同时设置此拖拽事件的展示UI、tag、数据信息、锚点及偏移
	protected onDragDetected(InGeometry :Geometry,InPointerEvent:PointerEvent):DragDropOperation {
		console.log("OnDrag"+InPointerEvent.screenSpacePosition)
		let ui=createUIByName("NewUI")

		//这里我们用payLoad参数传递的信息是这个UI对象,以便于在onDrop时创建一个新的UI对象并销毁旧的
		const payLoad = new TestDragDropPayLoad();
        payLoad.Test1=this.uiWidgetBase
        return this.newDragDrop(ui, "DragDropTag", payLoad, DragPivot.CenterCenter, new Vector2(0,0));	
	}
import NewUI_generate from "./ui-generate/NewUI_generate";

//创建一个继承DragDropPayLoad的TestDragDropPayLoad类,传入newDragDrop函数作为参数payLoad,跟随拖拽事件传递一些信息
export class TestDragDropPayLoad extends DragDropPayLoad {

    private test1 : UserWidget ;
    public get Test1() {
        return this.test1;
    }
    public set Test1(v :UserWidget) {
         this.test1 = v;
    }
}

export default class NewUIScript extends NewUI_generate {
	/** 
	 * 构造UI文件成功后,在合适的时机最先初始化一次 
	 */
	protected onStart() {
		//设置能否每帧触发onUpdate
		this.canUpdate = false;
		this.layer = UILayerMiddle;
		console.log("________");
	}

    //当玩家触摸到此UI时,开始检测是否发生拖拽操作
	onTouchStarted(InGeometry :Geometry,InPointerEvent:PointerEvent) :EventReply{
        console.log("OnTouch"+InPointerEvent.screenSpacePosition)
        return this.detectDragIfPressed(InPointerEvent, Keys.AnyKey)
    }
    //当玩家触摸到此UI时,开始检测是否发生拖拽操作
    onTouchEnded(InGemetry: Geometry, InPointEvent: PointerEvent): EventReply {
        return EventReply.handled;
    }
        //当检测到发生拖拽操作时,创建一个新的拖拽事件,同时设置此拖拽事件的展示UI、tag、数据信息、锚点及偏移
	protected onDragDetected(InGeometry :Geometry,InPointerEvent:PointerEvent):DragDropOperation {
		console.log("OnDrag"+InPointerEvent.screenSpacePosition)
		let ui=createUIByName("NewUI")

		//这里我们用payLoad参数传递的信息是这个UI对象,以便于在onDrop时创建一个新的UI对象并销毁旧的
		const payLoad = new TestDragDropPayLoad();
        payLoad.Test1=this.uiWidgetBase
        return this.newDragDrop(ui, "DragDropTag", payLoad, DragPivot.CenterCenter, new Vector2(0,0));	
	}
  • step.2 然后在监听释放的另一个UI文件(这个例子中直接使用了DefaultUI文件)的UI脚本内编写释放的逻辑;
  • 在这个例子中,我们不需要指定释放在某个UI上触发的逻辑,而是希望在整个屏幕中监听这张空白图片的释放,在释放的位置重新创建一个新的空白图片,并销毁旧的空白图片,因此可以就在新建项目的DefaultUI文件的UI脚本中编写onDrop事件
TypeScript
import {TestDragDropPayLoad} from "./NewUIScript";
import DefaultUI_generate from "./ui-generate/DefaultUI_generate";

@UIBind('')
export default class UIDefault extends DefaultUI_generate {

	/** 仅在游戏时间对非模板实例调用一次 */
    protected onStart() {
	}

    /**
     * 拖拽事件完成
     */
    onDrop(InGemotry: Geometry, InDragDropEvent: PointerEvent, InOperation: DragDropOperation) {
		console.warn("OnDrop"+InDragDropEvent.screenSpacePosition)
		//重新创建一个空白图片的自定义UI并设置位置
		let ui1=createUIByName("NewUI")
		this.uiWidgetBase.rootContent.addChild(ui1)
		ui1.position=(new Vector2(absoluteToLocal(InGemotry,InDragDropEvent.screenSpacePosition).x-ui1.size.x*0.5,absoluteToLocal(InGemotry,InDragDropEvent.screenSpacePosition).y-ui1.size.y*0.5))
		console.log(ui1.position);
		//把旧的空白图片UI销毁
		const payLoad = InOperation.tryGetDragDropPayLoadAs<TestDragDropPayLoad>();
		const test1 = payLoad.Test1;
		test1.destroyObject()
    }

	    /**
     * 拖拽操作生成事件触发后,没有完成完成的拖拽事件而取消时触发
     */
    protected onDragCancelled(InGemotry :Geometry,InDragDropEvent:PointerEvent) {
		console.warn("onDragCancelled"+InDragDropEvent.screenSpacePosition)
    }
}
import {TestDragDropPayLoad} from "./NewUIScript";
import DefaultUI_generate from "./ui-generate/DefaultUI_generate";

@UIBind('')
export default class UIDefault extends DefaultUI_generate {

	/** 仅在游戏时间对非模板实例调用一次 */
    protected onStart() {
	}

    /**
     * 拖拽事件完成
     */
    onDrop(InGemotry: Geometry, InDragDropEvent: PointerEvent, InOperation: DragDropOperation) {
		console.warn("OnDrop"+InDragDropEvent.screenSpacePosition)
		//重新创建一个空白图片的自定义UI并设置位置
		let ui1=createUIByName("NewUI")
		this.uiWidgetBase.rootContent.addChild(ui1)
		ui1.position=(new Vector2(absoluteToLocal(InGemotry,InDragDropEvent.screenSpacePosition).x-ui1.size.x*0.5,absoluteToLocal(InGemotry,InDragDropEvent.screenSpacePosition).y-ui1.size.y*0.5))
		console.log(ui1.position);
		//把旧的空白图片UI销毁
		const payLoad = InOperation.tryGetDragDropPayLoadAs<TestDragDropPayLoad>();
		const test1 = payLoad.Test1;
		test1.destroyObject()
    }

	    /**
     * 拖拽操作生成事件触发后,没有完成完成的拖拽事件而取消时触发
     */
    protected onDragCancelled(InGemotry :Geometry,InDragDropEvent:PointerEvent) {
		console.warn("onDragCancelled"+InDragDropEvent.screenSpacePosition)
    }
}
  • step.3 最后我们把空白图片的自定义UI控件(也就是NewUI文件)拖入到DefaultUI文件中;也可以使用动态创建的方法,然后运行游戏,我们就得到了一张可以自由拖拽改变位置的空白图片

示例二:制作一个有拖拽功能的背包面板

  • step.1 新建一个BagItem文件,并把允许拖动的UI内容单独放在这个UI文件里面作为一个自定义UI控件
  • 这里我们把所有UI内容挂在一个自建的容器下,便于拖拽两个格子交换位置时直接交换整个容器
  • 每个格子都要允许被拖拽,和前面的例子一样,使用onDragDetected事件来新建UI拖拽事件
  • 需要有在有其他格子被拖拽到这个格子上时,实现两个格子交换位置的功能,这部分逻辑写在onDrop事件里
  • 还需要制作一个拖出背包面板并释放就丢弃物品的效果,这部分逻辑写在onDropCancelled事件里
  • 注意应将Root的对齐方式设置为左上对齐,并且把图片的可见性设置为可见

TypeScript
import BagItem_generate from "./ui-generate/BagItem_generate";
//创建一个继承DragDropPayLoad的TestDragDropPayLoad类,传入newDragDrop函数作为参数payLoad,跟随拖拽事件传递一些信息
export class TestDragDropPayLoad extends DragDropPayLoad {

    private test1 : UserWidget ;
    public get Test1() {
        return this.test1;
    }
    public set Test1(v :UserWidget) {
         this.test1 = v;
    }
}

export default class BagItem extends BagItem_generate {
	imageColor:LinearColor
	/** 
	 * 构造UI文件成功后,在合适的时机最先初始化一次 
	 */
	protected onStart() {
		//给每个格子创建时随机改变图片的颜色,这里我们是模拟每个格子都是不同的物品
		this.imageColor= new LinearColor(Math.random(),Math.random(),Math.random(),1.0)
		this.icon.imageColor= this.imageColor
	}


	onTouchStarted(InGeometry :Geometry,InPointerEvent:PointerEvent) :EventReply{
        console.log("onTouchStarted"+InPointerEvent.screenSpacePosition)
        return this.detectDragIfPressed(InPointerEvent, Keys.AnyKey)
    }
	onTouchEnded(InGemotry: Geometry, InPointerEvent: PointerEvent): EventReply {
		console.log("onTouchEnded"+InPointerEvent.screenSpacePosition)
        return EventReply.handled;
    }
	onDragDetected(InGeometry :Geometry,InPointerEvent:PointerEvent):DragDropOperation {
		console.log("onDragDetected"+InPointerEvent.screenSpacePosition)
		let uiiconnow=this.uiWidgetBase.findChildByPath('RootCanvas/canvas/icon') as Image
		this.imageColor=uiiconnow.imageColor
		let uidrag=createUIByName("BagItem")
		let uiicon=uidrag.findChildByPath('RootCanvas/canvas/icon') as Image
		uiicon.imageColor= this.imageColor
		const payLoad = new TestDragDropPayLoad();
        payLoad.Test1=this.uiWidgetBase
        return this.newDragDrop(uidrag, "DragDropTag", payLoad, DragPivot.CenterCenter, Vector2.zero);	
	}
    
	//拖出各item范围之后释放,消耗UI,模拟丢弃的效果
	onDragCancelled(InGemotry :Geometry,InDragDropEvent:PointerEvent) {
		this.uiWidgetBase.destroyObject()
		console.log("onDragCancelled")
	}
	
	//其他item在此item上完成onDrop事件后,双方交换UI
	onDrop(InGemotry: Geometry, InDragDropEvent: PointerEvent, InOperation: DragDropOperation) {
		console.log("OnDrop"+InDragDropEvent.screenSpacePosition)
		const payLoad = InOperation.tryGetDragDropPayLoadAs<TestDragDropPayLoad>();
		const test1 = payLoad.Test1;
		let uiexchange=test1.rootContent.getChildAt(0) as Widget
		test1.rootContent.addChild(this.rootCanvas.getChildAt(0))
		this.rootCanvas.addChild(uiexchange)
		console.log(test1.parent);
		return true
    }
}
import BagItem_generate from "./ui-generate/BagItem_generate";
//创建一个继承DragDropPayLoad的TestDragDropPayLoad类,传入newDragDrop函数作为参数payLoad,跟随拖拽事件传递一些信息
export class TestDragDropPayLoad extends DragDropPayLoad {

    private test1 : UserWidget ;
    public get Test1() {
        return this.test1;
    }
    public set Test1(v :UserWidget) {
         this.test1 = v;
    }
}

export default class BagItem extends BagItem_generate {
	imageColor:LinearColor
	/** 
	 * 构造UI文件成功后,在合适的时机最先初始化一次 
	 */
	protected onStart() {
		//给每个格子创建时随机改变图片的颜色,这里我们是模拟每个格子都是不同的物品
		this.imageColor= new LinearColor(Math.random(),Math.random(),Math.random(),1.0)
		this.icon.imageColor= this.imageColor
	}


	onTouchStarted(InGeometry :Geometry,InPointerEvent:PointerEvent) :EventReply{
        console.log("onTouchStarted"+InPointerEvent.screenSpacePosition)
        return this.detectDragIfPressed(InPointerEvent, Keys.AnyKey)
    }
	onTouchEnded(InGemotry: Geometry, InPointerEvent: PointerEvent): EventReply {
		console.log("onTouchEnded"+InPointerEvent.screenSpacePosition)
        return EventReply.handled;
    }
	onDragDetected(InGeometry :Geometry,InPointerEvent:PointerEvent):DragDropOperation {
		console.log("onDragDetected"+InPointerEvent.screenSpacePosition)
		let uiiconnow=this.uiWidgetBase.findChildByPath('RootCanvas/canvas/icon') as Image
		this.imageColor=uiiconnow.imageColor
		let uidrag=createUIByName("BagItem")
		let uiicon=uidrag.findChildByPath('RootCanvas/canvas/icon') as Image
		uiicon.imageColor= this.imageColor
		const payLoad = new TestDragDropPayLoad();
        payLoad.Test1=this.uiWidgetBase
        return this.newDragDrop(uidrag, "DragDropTag", payLoad, DragPivot.CenterCenter, Vector2.zero);	
	}
    
	//拖出各item范围之后释放,消耗UI,模拟丢弃的效果
	onDragCancelled(InGemotry :Geometry,InDragDropEvent:PointerEvent) {
		this.uiWidgetBase.destroyObject()
		console.log("onDragCancelled")
	}
	
	//其他item在此item上完成onDrop事件后,双方交换UI
	onDrop(InGemotry: Geometry, InDragDropEvent: PointerEvent, InOperation: DragDropOperation) {
		console.log("OnDrop"+InDragDropEvent.screenSpacePosition)
		const payLoad = InOperation.tryGetDragDropPayLoadAs<TestDragDropPayLoad>();
		const test1 = payLoad.Test1;
		let uiexchange=test1.rootContent.getChildAt(0) as Widget
		test1.rootContent.addChild(this.rootCanvas.getChildAt(0))
		this.rootCanvas.addChild(uiexchange)
		console.log(test1.parent);
		return true
    }
}
  • step.2 制作一个简单的背包面板,并且编写手动添加物品格子的逻辑
  • 背包面板里的容器需要打开自动布局和网格布局功能,这样动态添加的格子会自动排布;更多关于容器的功能请查看产品手册UI 控件-容器
TypeScript
@UIBind('')
export default class UIDefault extends UIScript {
    Character: Character;

	/** 仅在游戏时间对非模板实例调用一次 */
    protected onStart() { 
		//设置能否每帧触发onUpdate
		this.canUpdate = false;

		//找到对应的按钮和容器
		const newBtn = this.uiWidgetBase.findChildByPath('RootCanvas/StaleButton') as StaleButton
		const canvas = this.uiWidgetBase.findChildByPath('RootCanvas/Canvas') as Canvas

		//点击按钮,创建UI
		newBtn.onPressed.add(()=>{
			//创建自定义UI组件并挂载到容器下
			let item= createUIByName('BagItem.ui') as UserWidget
			canvas.addChild(item)
		})	
    }

	onDrop(InGemotry: Geometry, InDragDropEvent: PointerEvent, InOperation: DragDropOperation) {
		console.log("OnDrop"+InDragDropEvent.screenSpacePosition)
		return true
    }
}
@UIBind('')
export default class UIDefault extends UIScript {
    Character: Character;

	/** 仅在游戏时间对非模板实例调用一次 */
    protected onStart() { 
		//设置能否每帧触发onUpdate
		this.canUpdate = false;

		//找到对应的按钮和容器
		const newBtn = this.uiWidgetBase.findChildByPath('RootCanvas/StaleButton') as StaleButton
		const canvas = this.uiWidgetBase.findChildByPath('RootCanvas/Canvas') as Canvas

		//点击按钮,创建UI
		newBtn.onPressed.add(()=>{
			//创建自定义UI组件并挂载到容器下
			let item= createUIByName('BagItem.ui') as UserWidget
			canvas.addChild(item)
		})	
    }

	onDrop(InGemotry: Geometry, InDragDropEvent: PointerEvent, InOperation: DragDropOperation) {
		console.log("OnDrop"+InDragDropEvent.screenSpacePosition)
		return true
    }
}

  • 最终实现的效果:

  • 请注意:这里只是为了演示拖拽事件的用法,实际上如果想要制作一个有完整功能的背包,不仅背包内每个格子的样式要传递过去,对应的物品功能也要作为信息传递过去,大家可以自行尝试。

注意事项

  • 按钮、文本按钮、遮罩按钮等按钮类控件不支持使用UI拖拽事件(如果按到按钮类组件会直接触发click事件,而无法触发拖拽事件),因此请使用图片控件作为可拖拽UI,如果想要监听图片作为可拖拽UI是否被点击可以使用touch事件

  • 注意应将被拖拽UI的Root节点的对齐方式设置为左上对齐
  • 目前在摄像机滑动区边缘会无法触发onDrop事件,请尽量避免这种情况