Files
netease-bedrock-wiki/mcguide/18-界面与交互/30-UI说明文档.md

119 KiB
Raw Blame History

front, hard, time
front hard time
入门 分钟

UI说明文档

文件命名说明

  • json文件名 json中的namespace python文件名 三者需要一致

  • 示例中为"myUIName"

myUIName.json

"namespace": "myUIName"

myUIName.py

JSON编写说明

Json是UI界面的显示内容和绑定的集合UI是一种树状的组织结构界面和界面中的控件都是一个UI Node节点后续的很多方法的调用也需要这个树状结构的路径来标识。

  • 目前MCStudio已提供UI编辑器开发者可以在UI编辑器内对界面进行可视化编辑并导出可以使用的json文件。各个控件在UI编辑器中的使用介绍将在下文中详细介绍。

命名空间

命名空间是这个界面的名称我们规定json文件名和namespace一致。

{
    "namespace" : "myUIName"
}

Main Screen

main是这个界面名称我们规定使用main即一个json文件是一个界面。

controls中的内容是该界面下的树状节点即子节点。

{
    "main@common.base_screen" : {
		"controls" : [
		]
	}
}
变量 解释
main@common.base_screen 表示main screen是common.base_screen的一个子类
my_namespace
|____main
     |test_image
	 |test_panel
              |test_label
  • 关于控件的适配问题,固定大小像素能在屏幕像素发生变化时保持形状大小不变,而百分比则能够保持与屏幕分辨率一致的比例,可能导致控件变形。

特殊情况下的根节点路径变化

一般地在使用UI API时对某控件进行操作时我们需要通过传入该控件相对于展示screen的相对路径来对控件实例进行操作例如如下UI界面结构

my_namespace
| main
	| panel0
		| text0

text0的路径为

path = "/panel0/text0"

但是当展示screen为了使用原生的功能而继承了common.base_screen时部分功能的生效会伴随着根节点路径的修改因此在使用UI API时控件的路径都发生了变化。

适配异形屏

为了适配异形屏我们可以展示screen中的内容通过引用的形式写在screen的$screen_content属性中。

{
    "main@common.base_screen" : {
		"$screen_content":"myUIName.panel0"
    },
    "panel0":{
        "controls" : [
            {
                "text0@myUIName.text0" : {}
            }
        ],
        "type" : "panel"
    },
    "text0" : {
        "text" : "Hello World!",
        "type" : "label",
        "visible" : true
   }
}

被$screen_content引用的内容其显示内容的范围不会被异形屏遮挡。此时text0的路径为

base_path = "/variables_button_mappings_and_controls/safezone_screen_matrix/inner_matrix/safezone_screen_panel/root_screen_panel"
path = base_path + "/text0"

可见控件的路径相对于展示screen的相对路径前还需要加上base_path路径才能正确拿到对应text0控件的路径有关text0的api才会生效。

控件介绍

screen

screen即画布控件是游戏中一个UI界面的根节点所有其他控件只有挂在画布下才能被正确显示出来。

{
    "main1" : {
        "absorbs_input" : true,
        "always_accepts_input" : false,
        "controls" : [
            {
                "label0@test.label0" : {}
            }
        ],
        "force_render_below" : false,
        "is_showing_menu" : true,
        "render_game_behind" : true,
        "render_only_when_topmost" : true,
        "should_steal_mouse" : false,
        "type" : "screen"
   },
   "main2@common.base_screen" : {
        "$screen_content" : "test.netease_editor_root_panel_base_screen0",
        "absorbs_input" : true,
        "always_accepts_input" : false,
        "force_render_below" : false,
        "is_showing_menu" : true,
        "render_game_behind" : true,
        "render_only_when_topmost" : true,
        "should_steal_mouse" : false
   },
   "netease_editor_root_panel_base_screen0" : {
        "anchor_from" : "top_left",
        "anchor_to" : "top_left",
        "controls" : [
            {
                "label1@test.label1" : {}
            }
        ],
        "layer" : 1,
        "offset" : [ 0, 0 ],
        "size" : [ "100%", "100%" ],
        "type" : "panel",
        "visible" : true
   }
}
变量
解释
type 当前控件类型
absorbs_input 是否阻挡输入默认值为true置false时方向键生效
always_accepts_input 是否始终接受鼠标事件默认值为false置true时该界面不在堆栈顶部也可以接受事件
force_render_below 是否渲染下方的界面默认值为false置true时被该界面覆盖的界面也会被渲染
is_showing_menu 是否是非常驻UI界面默认为true置false时该界面不会影响hud_screen的渲染
render_game_behind 是否在该界面创建时依然渲染游戏默认值为true置false时该界面创建时游戏界面定格
render_only_when_topmost 是否仅在堆栈顶部时渲染默认值为true置false时即使该界面被其他界面覆盖也会被渲染
should_steal_mouse 是否隐藏鼠标默认值为false置true时该界面被创建时将不会出现鼠标
gamepad_cursor_deflection_mode 是否开启手柄光标偏转模式默认值为false主要用于手柄适配轮盘控件
$screen_content 当该画布继承自common.base_screen时生效会将该属性对应的控件作为该画布的内容显示该内容将会适配异形屏

always_accepts_inputforce_render_below render_game_behind render_only_when_topmost属性仅在调用PushScreen接口创建UI时才会正常生效。

absorbs_input暂时无法生效等待后续修复。

下图为UI编辑器中画布属性编辑面板

画布属性

变量
解释
始终支持按键 对应always_accepts_input字段
创建时运行游戏 对应render_game_behind字段
强制持续渲染 对应force_render_below字段
仅在顶层渲染 对应render_only_when_topmost字段
继承基类画布 是否继承基类控件若勾选UI编辑器会自动创建一个不可见的以netease_editor_root_panel开头的panel并将该画布的内容放置在该panel下并将$screen_content属性代表的控件指向该panel。继承基类控件后画布内容将会适配异形屏。

通用属性

通用属性是每个控件都支持编辑的属性,对每个控件的位置、大小等基本属性进行设置。

变量
解释
anchor_from 挂接在父节点锚点的位置,取值范围["top_left", "top_middle", "top_right", "left_middle", "center", "right_middle", "bottom_left", "bottom_middle", "bottom_right"]
anchor_to 自身挂接锚点的位置取值同anchor_from
layer 当前控件相对父节点的层级最终显示层级取决于父节点到该节点的layer之和
offset 自身相对父节点的偏移,值为百分比+像素(1个像素等于屏幕上3个像素)
size 相对父节点的大小取值同offset
max_size 最大尺寸取值同offset。当该控件尺寸可变时最大不能超过该属性配置的尺寸
min_size 最小尺寸取值同offset。当该控件尺寸可变时最小不能小于该属性配置的尺寸
clips_children 裁剪子控件取值bool值开启后该控件范围外的子控件将不会被渲染
clip_offset 裁剪偏移,取值[x,y]。当开启裁剪子控件后,用来调整裁剪范围的偏移
alpha 透明度取值0-1.0。调整控件的透明度
propagate_alpha 透明度传递取值bool。该控件的透明度是否会影响子控件
enable 是否可交互取值bool。关闭该属性后按钮等控件变得不可交互
type 当前控件类型
visible 默认是否显示true为显示false为不显示

下图为UI编辑器中控件的通用属性编辑面板

通用属性

变量
解释
锚点 左右两侧的按钮组分别代表anchor_from字段和anchor_to字段的值从左到右从上到下依次代表取值范围中["top_left", "top_middle", "top_right", "left_middle", "center", "right_middle", "bottom_left", "bottom_middle", "bottom_right"]的其中一个
名称 改变控件的名称,只接受字母、数字、下划线的组合
隐藏控件 对应visible字段设置visible属性会实时的反映在UI编辑器左侧的控件结构窗口里
层级 对应layer字段 当UI编辑器关闭自动层级调整功能时该属性会在属性窗口中出现。该属性仅支持正整数。
位移X 对应offset字段的第一个数据用于控制该控件相对于锚点位置的偏移。位移的形式为%+PxPx表示像素%表示百分比跟随以位移X为例跟随有["无", "父控件尺寸X", "最大兄弟控件尺寸X", "子控件尺寸X", "最大子控件尺寸X", "尺寸Y"]选项。详情见。点击"PX"和"%"按钮将实现百分比跟随和像素的相互转换。
位移Y 对应offset字段的第二个数据用于控制该控件相对于锚点位置的偏移和位移X组成该控件的offset属性
尺寸X 对应size字段的第一个数据配置形式同位移界面和位移属性基本相同不同在“适应”属性勾选框。勾选后尺寸的宽度将适应该控件的内容如Label控件的文本内容或图片控件的图片宽度生成的json中尺寸样式为"default"
最大尺寸 对应max_size字段。
最小尺寸 对应min_size字段。
裁剪内容 对应clips_children字段。
裁剪偏移 对应clip_offset字段。
透明度 对应alpha字段。若勾选影响子控件则会将该控件的propagate_alpha属性置True繁殖则置False
交互 对应enable字段。
可被继承 若勾选可被继承则该控件可以被继承控件继承使用反之则不能被继承。勾选后该控件会生成在json文件的最外层和main处在同一层级即一个命名空间下唯一不勾选则生成在该控件父节点的controls字段中

注 以位移X为例的跟随选项解释

选项
解释
无跟随仅Px生效生成json中位移样式类似"100px"或100
父控件尺寸X 跟随父控件的宽度生成json中位移样式类似"100%+100px"
最大兄弟控件尺寸X 跟随其兄弟控件中控件宽度最大控件的宽度,选中后百分比将锁定为100生成json中位移样式类似"100%sm+100px"
子控件尺寸X 跟随子控件的宽度之和生成json中位移样式类似"100%c+100px"
最大子控件尺寸X 跟随其子控件中控件宽度最大控件的宽度,选中后百分比将锁定为100生成json中位移样式类似"100%cm+100px"
尺寸Y 跟随自身控件的高度生成json中位移样式类似"100%y+100px"

位移Y尺寸X 尺寸Y类似

Label

Label 是文本框控件用来显示文本信息默认的字体是MC字体如果有中文会变成中文字体格式暂时不支持换字体可以通过接口统一设置字体如果需要设置后续有介绍。

{
    "label0" : {
        "anchor_from" : "center",
        "anchor_to" : "center",
        "color" : [ 1, 1, 1 ],
        "font_scale_factor" : 1.0,
        "font_size" : "normal",
        "font_type" : "smooth",
        "layer" : 1,
        "offset" : [ 0, 0 ],
        "shadow" : false,
        "size" : [ 100, 100 ],
        "text" : "Hello World!",
        "text_alignment" : "center",
        "line_padding" : 0.0,
        "type" : "label",
        "visible" : true
   }
}
变量
解释
color 字体颜色r , g, b, a取值范围[0 , 1]
font_size 字体大小,取值["large", "normal", "small"]
font_scale_factor 字体缩放比例
shadow MC自带的字体阴影true为显示false则不显示
text 该Label显示的内容可以通过后续的API在代码中设置该值
text_alignment Label中文字的对齐方式取值为["left", "center", "right"]
line_padding 行间距,可以设置每行文字之间的间距
font_type 字体,取值["smooth", "unicode", "default", "rune"]

下图为UI编辑器中文本控件的属性编辑面板

控件表现

属性编辑

变量
解释
内容 对应text字段支持任何形式的文本
显示投影 对应shadow字段
字体 对应font_type字段可以修改文本的字体。需要注意的是当文本中出现中文时该字体显示将强制转为unicode该属性将不会生效。
对齐 对应text_alignment字段左中右对应["left", "center", "right"]数据
文本颜色 对应color字段点击按钮弹出颜色选择窗口可以在调色板上取色或者使用吸管吸取界面上的颜色
字号 对应font_size和font_scale_factor字段以一定的规则同时设置两个字段达到字号的效果
行间距 对应line_padding字段

由于游戏的UI框架遵循整数倍缩放, 不同分辨率的机型其缩放倍率和表现存在些微区别其中文本控件受影响较大当字体大小较小时会出现部分机型文字显示模糊的情况。经过测试在UI编辑器中字体大小定为8及以上

最小字体

即属性font_size为normalfont_scale_factor为1.0及以上时

最小字体

该文字在任何机型上都不会模糊。当字体大小小于这个标准时,将不保证该文字在任意机型下都能清晰显示。

由于格式控制符的存在,文本中尽量不要使用“%”。若一定需要显示“%”,应当在代码中输入"%%%%"方可生效。

Image

Image是指图片控件具有图片裁剪图片九宫格颜色叠加uv偏移旋转显示的额外属性。

{
    "image0" : {
        "anchor_from" : "center",
        "anchor_to" : "center",
        "is_new_nine_slice" : false,
        "layer" : 2,
        "nine_slice_buttom" : 0,
        "nine_slice_left" : 0,
        "nine_slice_right" : 0,
        "nine_slice_top" : 0,
        "offset" : [ 0, 0 ],
        "size" : [ 100, 100 ],
        "texture" : "textures/netease/common/image/default",
        "nineslice_size" : [ 0, 0, 0, 0 ],
        "grayscale" : false,
        "keep_ratio" : true,
        "clip_direction" : "left",
        "clip_ratio" : 0.0,
        "type" : "image",
        "uv" : [ 0, 0 ],
        "uv_size" : [ 107, 107 ],
        "rotate_pivot": [0.5, 0.5],
        "rotate_angle": 0,
        "visible" : true
   }
}
变量
解释
texture 贴图的路径该路径从resouce_pack中的textures目录开始
uv uv坐标的初始值为[0, 0]。uv坐标为[x,y]表示图片控件以所选图片左上角为原点,偏移(x,y)像素开始截取图片。
uv_size uv尺寸表示需要显示的尺寸默认值为图片的宽高。uv尺寸为[x,y]表示图片控件将截图x*y像素的图片范围显示在控件中。
keep_ratio 保持宽高比。取值bool。
grayscale 是否去色取值bool。勾选后该图片变为黑白图片。
clip_direction 裁剪方向,取值范围["left", "right", "up", "down", "center"]
clip_ratio 裁剪尺寸,取值范围0-1.0。0表示不裁剪1表示完全裁剪即该控件不渲染
is_new_nine_slice 设置为true标记该图片开启九宫格显示的功能与下方的nine_slice_bottom,nine_slice_left,nine_slice_right,nine_slice_top共同设置旧版九宫属性
nine_slice_bottom 切片距离下边的距离默认值为0
nine_slice_left 切片距离左边的距离默认值为0
nine_slice_right 切片距离右边的距离默认值为0
nine_slice_top 切片距离上边的距离默认值为0
nineslice_size 设置原版九宫属性,相比于旧版九宫属性更符合像素风格。当设置了旧版九宫属性时优先旧版属性。该值支持数组和单个数字,数组代表[left,top,right,down]九宫属性单个数值代表上下左右均采用该数值作为九宫属性当四个方向的数值均为0时表示不开启原版九宫
rotate_pivot 旋转锚点,数值类型为[float, float],默认值为[0.5, 0.5],具体见下文旋转说明
rotate_angle 旋转角度数值类型为float默认值为0具体见下文旋转说明

当Image控件进行旋转操作时它是以旋转锚点为基准进行变换而rotate_pivot是用来计算控件旋转锚点坐标的属性。旋转锚点坐标系的原点位于控件的左上角X轴正方向向右Y轴正方向向下和图像坐标系一样。rotate_pivot属性的值是一个二维向量取值范围不限实际的 旋转锚点的坐标 =控件的x坐标 + rotate_pivot[0] * 控件的宽度, 控件的y坐标 + rotate_pivot[1] * 控件的高度),比如(0,0)表示控件的左上角,(1,1)表示控件的右下角。

这是以左上角作为旋转锚点的旋转rotate_pivot = (0, 0)

旋转1

这是以右上角作为旋转锚点的旋转rotate_pivot = (1, 0)

旋转2

旋转锚点不仅仅是在图片内,也可以去到图片外,需要注意的是,旋转这个变换是最后作用的变换,图片控件先是算出当前的位置大小,再根据当前的位置大小算出旋转锚点,然后再应用旋转,并且这个旋转也只是视觉上的旋转,并不是控件真实的位置发生了改变(红框才是控件本身的位置信息和大小信息)。明白这点后,我们可以用一些常见例子来完成一些复杂的效果,比如给一张旋转的图添加水平运动动画。

旋转3

json如下

{
   "main" : {
      "controls" : [
         {
            "panel":
            {
               "size": [200, 200],
               "controls": [
                  {
                     "testImage@UIDemo.image": {}
                  }
               ],
               "type": "panel"
            }
         }
      ],
      "type" : "screen"
   },
    "image" : {
        "layer": 3,
        "size": [ 100, 100 ],
        "offset": "@UIDemo.animation_in",
        "texture": "textures/netease/common/image/default",
        "is_new_nine_slice": false,
        "nine_slice_buttom" : 0,
        "nine_slice_left" : 0,
        "nine_slice_right" : 0,
        "nine_slice_top" : 0,
        "nineslice_size" : [0, 0, 0, 0],
        "type": "image"
    },
    "animation_in": {
        "anim_type": "offset",
        "duration": 1.5,
        "from": [ -100, 0 ],
        "to": [ 100, 0 ],
        "next": "@UIDemo.animation_out"
    },
    "animation_out": {
        "anim_type": "offset",
        "duration": 1.5,
        "from": [ 100, 0 ],
        "to": [ -100, 0 ],
        "next": "@UIDemo.animation_in"
    },
    "namespace" : "UIDemo"
}

可以从上面看出来,根据旋转锚点做的旋转,本质上是一种自转,对应于接口 Rotate ,如果想进行的是绕着某个固定点旋转,则需要用到接口 RotateAround(和公转的概念是一致的),这两种旋转是能复合到一起的,具体如何一起使用做出稍微复杂的效果可以参考 Demo,需要注意无论是哪种旋转,本质上都只是视觉上的效果,并不是实际的坐标和大小。

下图为UI编辑器中图片控件的属性编辑面板

控件表现

图片属性

变量
解释
使用贴图 对应texture字段将资源管理窗口中的图片资源拖曳到该图片小窗内赋值可以在上方的下拉选项栏中重新选回默认图片
图片适配 普通表示不开启九宫并保持宽高比填充表示填满当前控件选中旧版九宫则is_new_nine_slice置true开启旧版九宫设置选中原版九宫则开启原版九宫。
去色 对应grayscale字段。
裁剪方向 对应clip_direction字段。分别对应["从右向左裁剪","从左向右裁剪","从下向上裁剪","从上向下裁剪","从四周向中心裁剪"]
裁剪尺寸 对应clip_ratio字段。
uv起点 对应uv字段默认为00
uv尺寸 对应uv_size字段默认值为该texture的宽高
旋转角度 对应rotate_angle字段默认为 0
旋转锚点 对应rotate_pivot字段默认为 0.50.5

Image Button

Button 是按钮控件同时含有Image和Label。按钮有三种状态分别为default/hover/pressed可以分别对应不同的贴图。

  • 注 $符号表示定义变量
  • controls表示控制的子节点
{
    "button0@common.button" : {
        "$default_texture" : "textures/netease/common/button/default",
        "$hover_texture" : "textures/netease/common/button/hover",
        "$is_new_nine_slice" : false,
        "$label_color" : [ 1, 1, 1 ],
        "$label_font_scale_factor" : 1.0,
        "$label_font_size" : "large",
        "$label_layer" : 3,
        "$label_offset" : [ 0, 0 ],
        "$label_text" : "Button",
        "$nine_slice_buttom" : 0,
        "$nine_slice_left" : 0,
        "$nine_slice_right" : 0,
        "$nine_slice_top" : 0,
        "$nineslice_size" : [ 0, 0, 0, 0 ],
        "$pressed_button_name" : "%fpsBattle.click",
        "$pressed_texture" : "textures/netease/common/button/pressed",
        "$texture_layer" : 2,
        "anchor_from" : "center",
        "anchor_to" : "center",
        "is_handle_button_move_event" : true,
        "button_mappings" : [],
        "bindings" : [
            {
                "binding_collection_name" : "",
                "binding_condition" : "always_when_visible",
                "binding_type" : "collection_details"
            }
        ],
        "controls" : [
            {
                "default@fpsBattle.default" : {}
            },
            {
                "hover@fpsBattle.hover" : {}
            },
            {
                "pressed@fpsBattle.pressed" : {}
            },
            {
                "button_label@fpsBattle.button_label" : {}
            }
        ],
        "default_control" : "default",
        "hover_control" : "hover",
        "layer" : 3,
        "offset" : [ 0, 0 ],
        "pressed_control" : "pressed",
        "size" : [ 100, 50 ],
        "type" : "button",
        "visible" : true
   },
   "button_label" : {
        "color" : "$label_color",
        "font_scale_factor" : "$label_font_scale_factor",
        "font_size" : "$label_font_size",
        "font_type" : "smooth",
        "layer" : "$label_layer",
        "max_size" : [ "100%", "100%" ],
        "offset" : [ 0, 0 ],
        "shadow" : false,
        "text" : "$label_text",
        "text_alignment" : "center",
        "type" : "label"
   },
   "default" : {
        "is_new_nine_slice" : "$is_new_nine_slice",
        "layer" : "$texture_layer",
        "nine_slice_buttom" : "$nine_slice_buttom",
        "nine_slice_left" : "$nine_slice_left",
        "nine_slice_right" : "$nine_slice_right",
        "nine_slice_top" : "$nine_slice_top",
        "texture" : "$default_texture",
        "type" : "image"
   },
   "hover" : {
        "is_new_nine_slice" : "$is_new_nine_slice",
        "layer" : "$texture_layer",
        "nine_slice_buttom" : "$nine_slice_buttom",
        "nine_slice_left" : "$nine_slice_left",
        "nine_slice_right" : "$nine_slice_right",
        "nine_slice_top" : "$nine_slice_top",
        "texture" : "$hover_texture",
        "type" : "image"
   },
   "pressed" : {
        "is_new_nine_slice" : "$is_new_nine_slice",
        "layer" : "$texture_layer",
        "nine_slice_buttom" : "$nine_slice_buttom",
        "nine_slice_left" : "$nine_slice_left",
        "nine_slice_right" : "$nine_slice_right",
        "nine_slice_top" : "$nine_slice_top",
        "texture" : "$pressed_texture",
        "type" : "image"
   }
}
变量
解释
default 表示按钮默认状态下的显示的图片内容
hover 表示按钮处于悬浮状态下的图片内容
pressed 表示按钮处于按下状态下的图片内容
$is_new_nine_slice 设置为true标记该图片开启九宫格显示的功能,从Json结构里可以看出三张图片的九宫设置用的是同一个
$nine_slice_bottom 切片距离下边的距离默认值为0
$nine_slice_left 切片距离左边的距离默认值为0
$nine_slice_right 切片距离右边的距离默认值为0
$nine_slice_top 切片距离上边的距离默认值为0
$nineslice_size 设置原版九宫属性,相比于旧版九宫属性更符合像素风格。当设置了旧版九宫属性时优先旧版属性。该值支持数组和单个数字,数组代表[left,top,right,down]九宫属性单个数值代表上下左右均采用该数值作为九宫属性当四个方向的数值均为0时表示不开启原版九宫
$pressed_button_name fpsBattle代表编写UI逻辑的python类名click代表按钮按下时会执行该python类的click函数。也可以使用API AddTouchEventHandler 动态注册按钮回调
is_handle_button_move_event 表示按钮是否可以响应按钮移动事件需置true配合API AddTouchEventHandler使用
button_mappings 表示按钮事件响应映射网,需置[]配合API AddTouchEventHandler使用

下图为UI编辑器中按钮控件的属性编辑面板。

控件表现

按钮属性

变量
解释
文本 对应button_label/text字段所引用的值支持任何形式的文本
文本颜色 对应button_label/color字段所引用的值点击按钮弹出颜色选择窗口可以在调色板上取色或者使用吸管吸取界面上的颜色
字号 对应button_label/font_size和button_label/font_scale_factor字段以一定的规则同时设置两个字段达到字号的效果
文本偏移 对应button_label/offset字段所引用的值设置按钮上的文字相对中心点的偏移
使用贴图 分别对应default/texture,pressed/texture,hover/texture字段所引用的值将资源管理窗口中的图片资源拖曳到该图片小窗内赋值可以在上方的下拉选项栏中重新选回默认图
图片适配 普通表示不开启九宫选中旧版九宫则is_new_nine_slice置true开启旧版九宫设置选中原版九宫则开启原版九宫。

Panel

panel为面板控件主要是用来将控件进行分类和管理类似文件夹。

{
    "panel" : {
        "anchor_from" : "center",
        "anchor_to" : "center",
        "layer" : 0,
        "offset" : [ 0, 0 ],
        "size" : [ "50.000000%+0 px", "50.000000%+0px" ],
        "type" : "panel",
        "visible" : true
   }
}
变量 解释
type 类型为panel

面板控件暂时没有专属的属性,如有,后续在此处添加。

InputPanel

input_panel与panel类似可以用来放置其他控件但除此之外还可以用来拖动或实现“模态框”功能。

{
    "InputPanel" : {
        "anchor_from" : "top_left",
        "anchor_to" : "top_left",
        "button_mappings": [
            {
                "from_button_id": "button.menu_select",
                "to_button_id": "#netease_to_button_id",
                "mapping_type": "pressed"
            }
        ],
        "layer" : 10,
        "modal" : true,
        "is_swallow": true,
        "contained": true,
        "draggable": "both",
        "offset" : [ 0.0, 0.0 ],
        "size" : [ 198.0, 137.0 ],
        "type" : "input_panel",
        "visible" : true
    }
}
变量 默认值 解释
modal false 设为true时该InputPanel视为模态框注2
is_swallow false 设为true时该InputPanel的输入会吞噬事件注3
draggable not_draggable 当前控件可拖拽方式默认为not_draggable不可拖拽"horizontal"代表水平拖拽,"vertical"代表垂直拖拽,"both"代表自由拖拽
contained false 该控件可拖动时是否会被父控件的大小范围所限制默认值为false注4
button_mappings [] 该值为开启拖拽功能所必须的属性,可以理解成开启接受屏幕点击事件
  • 注1
该控件的拖动功能也遵循UI控件的碰撞规则当InputPanel中有按钮、滚动列表等接受鼠标事件的控件时点击在这些控件并不会触发InputPanel的拖动操作。
  • 注2
“模态框”是指将用户的UI点击操作限制在这个控件及其子控件而其他的控件都不会响应用户操作。

如果界面上同时存在多个模态框,其中层级最高的生效。

可以用来处理ScrollView控件上显示其他控件时点击会穿透到ScrollView的问题可参考UIDemo示例的“InputPanel演示”

界面编辑器暂不支持可先用Panel搭建后手动在json中修改属性。

  • 注3
吞噬事件是指点击该面板时,点击事件不会穿透到世界。如破坏方块、镜头转向不会被响应。

  • 注4
InputPanel维护着一个拖拽偏移量它代表着在整个拖拽过程中InputPanel相对于控件出生点坐标的偏移量**与控件自身的offset无关**。举个例子InputPanel经过了5次手动拖拽后位置向右移动了5像素则拖拽偏移量的值为(5, 0)。

当contained为true时拖拽偏移量存在限制最小不能超过(0,0)最大不能超过父控件的大小减去InputPanel控件的大小。

这也就意味着无论InputPanel是否设置了offset由于初始拖拽偏移量为(0,0), 使控件无法负方向移动因此需要将InputPanel放置在其父控件的左上角或调用SetOffsetDelta接口手动设置拖拽偏移量。

StackPanel

布局面板,用于自动布局该控件的子控件

{
    "stack_panel0": {
        "layer": 1,
        "orientation": "horizontal",
        "size": [100, 100],
        "type": "stack_panel",
        "controls": [
            {
            "panel_0": {
                "type": "panel",
                    "size": [2, 2]
                }
            }, 
            {
            "fill_0": {
                    "type": "panel",
                    "size": ["fill", 1]
                }
            }
        ]
    }
}
变量 解释
orientation 当前控件布局方式方式,"horizontal"代表水平排布,"vertical"代表垂直排布
type 类型为stack_panel
size 在stack_panel的子控件中size属性支持使用"fill"字段来动态填充剩余空间。例如,若排列方式为"horizontal",可以通过设置子控件"size":["fill",1]来让控件在横向上铺满剩余空间。

下图为UI编辑器中布局面板控件的属性编辑面板。

控件表现

布局面板属性

变量 解释
排列方式 对应orientation字段

排序的顺序和子控件的排序有关,需要手动调整。

TextEditBox

TextEditBox是输入框控件用来输入文字信息可以获取输入内容设置输入框内容触发输入中和输入完成事件设置最大输入值等。下面的示例展示了一个搜索框的信息。

{
    "text_edit_box0@common.text_edit_box" : {
        "$edit_box_default_texture" : "textures/ui/edit_box_indent",
        "$edit_box_hover_texture" : "textures/ui/edit_box_indent_hover",
        "$font_size" : "normal",
        "$is_new_nine_slice" : false,
        "$nine_slice_buttom" : 0,
        "$nine_slice_left" : 0,
        "$nine_slice_right" : 0,
        "$nine_slice_top" : 0,
        "$nineslice_size" : [ 0, 0, 0, 0 ],
        "$place_holder_text" : "请输入内容",
        "$place_holder_text_color" : [ 0.50, 0.50, 0.50 ],
        "$text_background_default" : "fpsBattle.edit_box_background_default",
        "$text_background_hover" : "fpsBattle.edit_box_background_hover",
        "$text_box_name" : "%fpsBattle.message_text_box",
        "$text_box_text_color" : [ 1, 1, 1 ],
        "$text_edit_box_content_binding_name" : "#fpsBattle.message_text_box_content",
        "anchor_from" : "center",
        "anchor_to" : "center",
        "enabled_newline" : false,
        "layer" : 5,
        "max_length" : 512,
        "offset" : [ 0, 0 ],
        "size" : [ 300, 27 ],
        "type" : "edit_box",
        "visible" : true
   },
   "edit_box_background_default" : {
        "is_new_nine_slice" : "$is_new_nine_slice",
        "nine_slice_buttom" : "$nine_slice_buttom",
        "nine_slice_left" : "$nine_slice_left",
        "nine_slice_right" : "$nine_slice_right",
        "nine_slice_top" : "$nine_slice_top",
        "texture" : "$edit_box_default_texture",
        "type" : "image"
   },
   "edit_box_background_hover" : {
        "is_new_nine_slice" : "$is_new_nine_slice",
        "nine_slice_buttom" : "$nine_slice_buttom",
        "nine_slice_left" : "$nine_slice_left",
        "nine_slice_right" : "$nine_slice_right",
        "nine_slice_top" : "$nine_slice_top",
        "texture" : "$edit_box_hover_texture",
        "type" : "image"
   }
}
变量
解释
max_length 初始最大输入长度,后续可代码设置
$text_box_name 获取输入到的信息监听了BF_EditChanged和BF_EditFinished的函数Textbox会在输入框内容修改和输入完成时调到该函数可参考下面的注1
$text_edit_box_content_binding_name 输入框显示ReturnTextString中返回的内容这与上面形成了一个双向绑定可参考下面的注1
$place_holder_text 输入框初始化没有输入时的提示语
$is_new_nine_slice 设置为true标记该图片开启九宫格显示的功能,从Json结构里可以看出两张图片的九宫设置用的是同一个
$nine_slice_bottom 切片距离下边的距离默认值为0
$nine_slice_left 切片距离左边的距离默认值为0
$nine_slice_right 切片距离右边的距离默认值为0
$nine_slice_top 切片距离上边的距离默认值为0
$nineslice_size 设置原版九宫属性,相比于旧版九宫属性更符合像素风格。当设置了旧版九宫属性时优先旧版属性。该值支持数组和单个数字,数组代表[left,top,right,down]九宫属性单个数值代表上下左右均采用该数值作为九宫属性当四个方向的数值均为0时表示不开启原版九宫
  • 注1
import mod.client.extraClientApi as clientApi
ViewBinder = clientApi.GetViewBinderCls()
ViewRequest = clientApi.GetViewViewRequestCls()
ScreenNode = clientApi.GetScreenNodeCls()

class TestScreen(ScreenNode):
    def __init__(self, namespace, name, param):
        ScreenNode.__init__(self, namespace, name, param)
        self.text = ""
        self.holder = str("请输入姓名")
        
    @ViewBinder.binding(ViewBinder.BF_EditChanged | ViewBinder.BF_EditFinished)
    def TextBox(self, args):
        print "SearchTextBox  ", args
        self.text = args["Text"]
        return ViewRequest.Refresh

    @ViewBinder.binding(ViewBinder.BF_BindString)
    def ReturnTextString(self):
        return self.text
  • 注2

max_length 可以通过接口SetEditTextMaxLength接口详细调用可见下文。

注意输入框推荐在创建UI的isHud为0的情况下使用

clientApi.CreateUI("testMod", "testUI", {"isHud":0})

因为在安卓机器上当isHud为1时选中文本输入框后单指无法取消选中需要双指点击屏幕取消选中如下图

问题gif

PC和IOS平台没有这个问题

下图为UI编辑器中文本输入框控件的属性编辑面板。

控件表现

文本输入框属性

变量
解释
提示文字 对应$place_holder_text字段代表没有文本输入时底部显示
提示文字颜色 对应$place_holder_text_color字段代表提示文字的颜色点击按钮弹出颜色选择窗口可以在调色板上取色或者使用吸管吸取界面上的颜色
输入文本颜色 对应$text_box_text_color字段代表输入文本的颜色
绑定输入框交互 对应$text_box_name字段
绑定输入框内容 对应$text_edit_box_content_binding_name字段
提示文字字号 对应$font_size字段可供选择的有["small","middle","large"],对应值[4816]
文字最大长度 对应max_length字段即代表可输入文本的最大长度
使用贴图 分别对应$edit_box_default_texture控件默认状态,$edit_box_hover_texture控件鼠标悬浮状态字段所引用的值将资源管理窗口中的图片资源拖曳到该图片小窗内赋值可以在上方的下拉选项栏中重新选回默认
图片适配 普通表示不开启九宫选中旧版九宫则is_new_nine_slice置true开启旧版九宫设置选中原版九宫则开启原版九宫。

PaperDoll

该控件可以用于在ui上显示骨骼模型

{
    "paper_doll0" : {
        "anchor_from" : "center",
        "anchor_to" : "center",
        "animation" : "",
        "animation_looped": true,
        "layer" : 7,
        "modelname" : "",
        "modelsize" : 1.0,
        "offset" : [ 0, 0 ],
        "renderer" : "paper_doll_renderer",
        "size" : [ 100, 100 ],
        "type" : "custom",
        "visible" : true,
        "enable_scissor_test" : false,
   }
}
变量
解释
modelname 要显示的骨骼模型的名称可通过API中的SetUiModel接口动态修改
animation 骨骼模型播放的动作可通过API中的SetUiModel接口动态修改
animation_looped 骨骼模型播放动作是否循环播放可通过API中的SetUiModel接口动态修改
modelsize 骨骼模型的显示缩放
renderer 对纸娃娃控件自定义的渲染模块,不建议改动该字段
enable_scissor_test 超出父控件区域后是否裁剪默认为false, 该属性需要父控件开启clips_children属性才能生效RenderPaperDoll

下图为UI编辑器中纸娃娃控件的属性编辑面板。

控件表现

纸娃娃控件属性

变量
解释
模型类型 可选原版模型和FBX模型FBX模型可通过资源管理器界面导入。选中FBX模型时显示模型名称选项可选导入的FBX模型。选中原版模型时默认modelname使用steve
模型名称 对应modelname字段
模型缩放 对应modelsize字段支持0-100的正整数

NeteasePaperDoll

该控件可以用于在ui上显示

1生物包括玩家与普通生物

2骨骼模型展示

3生物类型原版模型展示。

{
    "paper_doll0" : {
        "anchor_from" : "center",
        "anchor_to" : "center",
        "layer" : 22,
        "offset" : [ 0.0, 0.0 ],
        "renderer" : "netease_paper_doll_renderer",
        "init_rot_y": 60.0,
        "rotation": "gesture_x",
        "screen_scale": 1.0,
        "size" : [ 100, 100 ],
        "type" : "custom",
        "visible" : true,
        "enable_scissor_test" : false
    }
}

相关字段说明:

变量
解释
renderer 不能改动该字段
rotation 渲染模型的朝向,可选的值有:
none默认值没有任何旋转角度
auto随着时间而旋转
gesture_x可以通过触控以Y轴旋转, 但需要InputPanel控件配合生效。详情请参考UIDemoMod中的纸娃娃演示示例
freedom_gesture可以自主选择绕xyz轴旋转, 但需要InputPanel控件配合生效。详情请参考官网Mod 中的NeteasePaperDollDemoMod
init_rot_y 初始朝向Y轴为旋转轴单位角度RenderPaperDoll参数init_rot_y动态设置
screen_scale 放缩系数默认为1基于UI的size进行放缩RenderPaperDoll参数scale动态设置
skeleton_model_name 骨骼模型名称,默认为空字符,RenderPaperDoll参数skeleton_model_name动态设置
animation 骨骼模型动画名称默认为idleRenderPaperDoll参数animation动态设置
animation_looped 骨骼动画是否循环播放默认为trueRenderPaperDoll参数animation_looped动态设置
entity_identifier 生物标识如minecraft:cat默认为空字符RenderPaperDoll参数entity_identifier动态设置
enable_scissor_test 超出父控件区域后是否裁剪默认为false, 该属性需要父控件开启clips_children属性才能生效RenderPaperDoll

接口使用例子以及说明:

1渲染玩家或者生物包括玩家的装备等物品的渲染

path = '/demoPanel/dollPanel/viewer_panel/paper_doll_panel/paper_doll'
param = {
    "entity_id": "-8589934591", # 玩家或生物Id
    "scale": 0.5, # 放缩系数
    "render_depth": -50, # 渲染深度,对于玩家默认-50普通生物-15该参数可解决UI遮挡剔除问题
    "init_rot_y": 60, # 初始朝向
    "molang_dict": {"variable.liedownamount": 1} # molang变量dict其中key为字符串value为float类型
}
self.GetBaseUIControl(path).asNeteasePaperDoll().RenderEntity(param)

2渲染骨骼模型

path = '/demoPanel/dollPanel/viewer_panel/paper_doll_panel/paper_doll'
param = {
    "skeleton_model_name": "datiangou", # 大天狗模型
    "scale": 1.0,
    "animation": "fengxi", # 动画名称
    "animation_looped": False, # 是否循环播放
}
self.GetBaseUIControl(path).asNeteasePaperDoll().RenderSkeletonModel(param)

3渲染原版生物模型不需要生物实例

path = '/demoPanel/dollPanel/viewer_panel/paper_doll_panel/paper_doll'
param = {
    "scale": 1.0,
    "entity_identifier": "minecraft:cat", # 渲染猫的原版模型
    "init_rot_y": 60,
    "molang_dict": {"variable.state": 2, "variable.liedownamount": 1} # 通过molang变量来调整渲染效果坐下的猫
}
self.GetBaseUIControl(path).asNeteasePaperDoll().RenderEntity(param)

使用注意事项:

1如果渲染位置不正确请调整UI的位置

2如果渲染模型过大或者过小请调整UI的大小或者参数scale

3如果生物模型被裁剪请调整参数render_depth或者UI的layer

4可以通过使用参数molang_dict来驱动原版模型的渲染如果发生如下图的渲染错误需要自行调整molang表达式

molang渲染错误提示

ItemRenderer

该控件可以用于在ui上显示物品

{
    "item_renderer0" : {
        "anchor_from" : "center",
        "anchor_to" : "center",
        "layer" : 1,
        "offset" : [ 0, 0 ],
        "property_bag" : {
            "#item_id_aux" : 131072
        },
        "renderer" : "inventory_item_renderer",
        "size" : [ 100, 100 ],
        "type" : "custom",
        "visible" : true
   }
}
变量
解释
renderer 对显示物品自定义的渲染模块,不建议改动该字段
property_bag 控件属性信息,#item_id_aux代表物品id131072代表草方块在游戏内的值

下图为ItemRenderer在UI编辑器中的控件表现

控件表现

物品渲染控件属性

物品渲染控件属性

变量
解释
道具类型 可选原版道具和自定义道具自定义道具可在关卡编辑器中设置。选中自定义道具时显示道具ID和附加值输入栏可输入自定的道具ID和附加值。选中原版道具时隐藏道具ID和附加值输入栏显示道具材质点击弹出道具材质选择窗口
道具材质 点击弹出道具材质选择窗口展示所有原版道具图片选中后编辑器自动设置该道具对应的道具ID和附加值
道具ID和附加值 填写设置自定义道具时设置的道具ID和附加值
附魔效果 勾选后道具表现出现附魔流光效果

道具在游戏中的物品id会根据游戏运行平台、加载Mod数量、游戏大版本等不同会发生变化因此UI编辑器的ItemRenderer控件静态保存在json中的数据在游戏中并不一定能正确显示建议使用UIAPI-SetUiItem来对该控件进行动态设置详见《UIAPI文档》。

原版道具显示正常。

ScrollView

该控件是可以滑动的窗口,需要有其他控件附属。

{
    "scroll_view0@common.scrolling_panel" : {
        "$background_nine_slice_buttom" : 0,
        "$background_nine_slice_left" : 0,
        "$background_nine_slice_right" : 0,
        "$background_nine_slice_top" : 0,
        "$background_nineslice_size" : [ 0, 0, 0, 0 ],
        "$box_nine_slice_buttom" : 0,
        "$box_nine_slice_left" : 0,
        "$box_nine_slice_right" : 0,
        "$box_nine_slice_top" : 0,
        "$box_nineslice_size" : [ 0, 0, 0, 0 ],
        "$is_background_nine_slice" : false,
        "$is_box_nine_slice" : false,
        "$is_track_nine_slice" : false,
        "$scroll_background_image_control" : "fpsBattle.scroll_background_image",
        "$scroll_background_texture" : "textures/ui/ScrollRail",
        "$scroll_box_mouse_image_control" : "fpsBattle.scroll_box_image",
        "$scroll_box_texture" : "textures/ui/newTouchScrollBox",
        "$scroll_box_touch_image_control" : "fpsBattle.scroll_box_image",
        "$scroll_track_image_control" : "fpsBattle.scroll_track_image",
        "$scroll_track_texture" : "textures/ui/ScrollRail",
        "$scrolling_content" : "fpsBattle.image",
        "$show_background" : true,
        "$track_nine_slice_buttom" : 0,
        "$track_nine_slice_left" : 0,
        "$track_nine_slice_right" : 0,
        "$track_nine_slice_top" : 0,
        "$track_nineslice_size" : [ 0, 0, 0, 0 ],
        "anchor_from" : "center",
        "anchor_to" : "center",
        "layer" : 9,
        "offset" : [ 0, 0 ],
        "size" : [ 100, 80 ],
        "type" : "scroll_view",
        "visible" : true
   }
}
变量
解释
scrolling_content 这里保存了该滑动窗口的内容
show_background 是否显示背景
$is_background_nine_slice 设置为true标记背景图片开启九宫格显示的功能
$background_nine_slice_buttom 切片距离下边的距离默认值为0
$background_nine_slice_left 切片距离左边的距离默认值为0
$background_nine_slice_right 切片距离右边的距离默认值为0
$background_nine_slice_top 切片距离上边的距离默认值为0
$background_nineslice_size 设置原版九宫属性,相比于旧版九宫属性更符合像素风格。当设置了旧版九宫属性时优先旧版属性。该值支持数组和单个数字,数组代表[left,top,right,down]九宫属性单个数值代表上下左右均采用该数值作为九宫属性当四个方向的数值均为0时表示不开启原版九宫
$is_box_nine_slice 设置为true标记滑动块图片开启九宫格显示的功能
$box_nine_slice_buttom 切片距离下边的距离默认值为0
$box_nine_slice_left 切片距离左边的距离默认值为0
$box_nine_slice_right 切片距离右边的距离默认值为0
$box_nine_slice_top 切片距离上边的距离默认值为0
$box_nineslice_size 设置原版九宫属性,相比于旧版九宫属性更符合像素风格。
$is_track_nine_slice 设置为true标记滑轨图片开启九宫格显示的功能
$track_nine_slice_buttom 切片距离下边的距离默认值为0
$track_nine_slice_left 切片距离左边的距离默认值为0
$track_nine_slice_right 切片距离右边的距离默认值为0
$track_nine_slice_top 切片距离上边的距离默认值为0
$track_nineslice_size 设置原版九宫属性,相比于旧版九宫属性更符合像素风格。
$scroll_background_texture 滚动列表背景图片
$scroll_box_texture 滑动块图片
$scroll_track_texture 滑轨图片

下图为UI编辑器中滚动列表控件的属性编辑面板。

控件表现

滚动列表属性

滚动列表属性

变量
解释
滚动列表-内容 对应$scrolling_content字段只接受其他screen画布中的控件且被选中控件不可以是文本、图片、滚动列表控件若被选中控件为panel那么子节点中含有滚动列表的panel控件同样不可以被选中
滚动列表-隐藏背景 对应show_background字段
滚动列表-使用贴图 对应$scroll_background_texture字段将资源管理窗口中的图片资源拖曳到该图片小窗内赋值可以在上方的下拉选项栏中重新选回默认图片
滚动列表-图片适配 普通表示不开启九宫选中旧版九宫则is_new_nine_slice置true开启旧版九宫设置选中原版九宫则开启原版九宫。
滚动条滑块-使用贴图 对应$scroll_box_texture字段将资源管理窗口中的图片资源拖曳到该图片小窗内赋值可以在上方的下拉选项栏中重新选回默认图片
滚动条滑块-图片适配 普通表示不开启九宫选中旧版九宫则is_new_nine_slice置true开启旧版九宫设置选中原版九宫则开启原版九宫。
滚动条背景-使用贴图 对应$scroll_track_texture字段将资源管理窗口中的图片资源拖曳到该图片小窗内赋值可以在上方的下拉选项栏中重新选回默认图片
滚动条背景-图片适配 普通表示不开启九宫选中旧版九宫则is_new_nine_slice置true开启旧版九宫设置选中原版九宫则开启原版九宫。

滚动列表的内容以scrolling_content为引用可以由我们自定义但是承载scrolling_content的父控件scrolling_view_port的size如不经修改默认为["100%","100%"]即与我们的滚动列表定的大小相同而可滚动区域的判定会取scrolling_content的size和其父控件scrolling_view_port作比较两者大小之差即为可拖动范围。而我们UI控件的size是不会根据其子控件的size做到动态完全覆盖因此如果我们的scrolling_content的大小是动态变化的需要我们在代码中手动设置scrolling_content的size,详见UI-APISetSize

而对于scrolling_content的绝对路径一共有以下两种可以通过UI-APIGetAllChildrenPath清楚的看到。

scroll_view_path = "/scroll_view0"
touch_path = scroll_view_path + "/scroll_touch/scroll_view/panel/background_and_viewport/scrolling_view_port/scrolling_content"
mouse_path = scroll_view_path + "/scroll_mouse/scroll_view/stack_panel/background_and_viewport/scrolling_view_port/scrolling_content"

我们知道在PC端进行游戏时按F11可以切换鼠标控制和遥感控制两种操作模式而在手机端进行游戏时只有遥感控制这一种操作模式。不同的操作模式scroll_view的scrolling_content会生成在不同的路径下遥感模式使用touch_path获得scrolling_content的绝对路径而鼠标控制使用mouse_path获得。

Grid

Grid组件属于网格型的排列可以依附在滚动条中用来实现背包等功能。

{
    "grid0" : {
        "anchor_from" : "center",
        "anchor_to" : "center",
        "collection_name" : "test_grid",
        "grid_dimensions" : [ 2, 2 ],
        "grid_item_template" : "fpsBattle.netease_editor_template_image",
        "grid_rescaling_type" : "none",
        "maximum_grid_items" : 0,
        "layer" : 1,
        "offset" : [ 0, 0 ],
        "size" : [ 200, 200 ],
        "type" : "grid",
        "visible" : true
   },
   "netease_editor_template_image" : {
        "anchor_from" : "center",
        "anchor_to" : "center",
        "layer" : 1,
        "offset" : [ 0, 0 ],
        "size" : [ "50%", "50%" ],
        "texture" : "textures/netease/common/image/default",
        "type" : "image",
        "uv" : [ 0, 0 ],
        "uv_size" : [ 107, 107 ],
        "visible" : true
   }
}
变量
解释
grid_rescaling_type 网格调节方式,目前可取值范围["none","horizontal"]当取值none是grid_dimensions生效取值horizontal时maximum_grid_items生效
maximum_grid_items 最大格子数量
grid_dimensions 初始值大小2X2
grid_item_template 被当作生成网格单元的控件模板

下图为UI编辑器中网格控件的属性编辑面板。

控件表现

网格属性

网格属性

变量
解释
集合名 对应collection_name字段
内容 对应grid_item_template字段只接受其他screen画布中的控件且被选中控件不可以是滚动列表、网格控件若被选中控件为panel那么子节点中含有滚动列表、网格的panel控件同样不可以被选中
网格调节方式 对应grid_rescaling_type字段,配置网格模式时格子固定生成m * n个格子配置水平模式时格子按网格最大数量水平连续生成若干格子一般搭配控件尺寸Y勾选"适应"使用
网格规模 对应grid_dimensions字段
网格最大数量 对应maximum_grid_items字段

注:

  1. grid是在renderer渲染的时候才创建所以只要没有显示过该界面调用GetChildrenName和GetAllChildrenPath都无法获取到grid的子节点信息。如果要初始化grid的信息必须在UI渲染结束后一帧再来调用这两个接口获取子节点信息并初始化

  2. 当grid控件与ScrollView一起使用时如果grid控件中设置单个UI元素例如按钮的数目值超过当前grid控件显示的最大数目时需要配合scrollview一同使用。当scrollview拉动时由于MC内置逻辑实现方式grid控件会将没有渲染必要的格子剔除并缓存以节约渲染成本并在其恢复渲染必要时添加回grid的子节点列表中。在这一过程中每个UI元素都不一定会在其原本的位置从而导致内容错位。此时需要开发者监听GridComponentSizeChangedClientEvent事件,当收到事件后,需要通过GetAllChildrenPath接口获取grid中返回的所有UI元素的路径值这些路径值尾部包含该UI元素在grid中的索引数目。依据索引数目mod开发者将物品背包或者类似的显示所需的UI信息值依次设置到grid中的子元素中。建议开发者采用MVC模式控制grid中的内容显示M代表需要显示的数据信息容器V代表grid容器和容器中包含的子UI控件C代表控制组装的UI元素的函数或者模块并由初始化和监听GridComponentSizeChangedClientEvent事件触发驱动。详情请参考UIDemoMod中的滚动列表演示示例。

  3. grid控件不建议使用其子控件路径对其动态生成的格子控件直接进行SetVisible等操作因为在每次界面刷新时grid控件会对所有的格子做一次数据更新更新的过程中会强制将格子可见性置True。如果有需要对格子进行操作可以使用数据绑定的方式如下代码和json。需要注意的是在数据绑定的回调函数中需要明确grid本身是否可见否则会造成grid子节点控件的可见性数据异常从而影响界面操作逻辑。

{
    "grid1" : {
        "anchor_from" : "center",
        "anchor_to" : "center",
        "collection_name" : "gridDemo",
        "grid_dimensions" : [ 2, 2 ],
        "grid_item_template" : "UIDemo.scrollviewBtn0",
        "layer" : 39,
        "offset" : [ 0, 0 ],
        "size" : [ 200, 200 ],
        "type" : "grid",
        "visible" : true
   },
   "scrollviewBtn0@UIDemo.scrollviewBtn": {
	    "bindings" : [
            {
			    "binding_collection_name" : "gridDemo",
			    "binding_condition" : "always",
			    "binding_name" : "#UIDemo.visible",
			    "binding_name_override" : "#visible",
			    "binding_type" : "collection"
		    }
        ],
        "visible" : "#UIDemo.visible"
   }
}
import mod.client.extraClientApi as clientApi
ViewBinder = clientApi.GetViewBinderCls()
ViewRequest = clientApi.GetViewViewRequestCls()
ScreenNode = clientApi.GetScreenNodeCls()

class UIDemoScreen(ScreenNode):
	def __init__(self, namespace, name, param):
		ScreenNode.__init__(self, namespace, name, param)
		self.demoGridControl = None
	
	def Create(self):
		self.demoGridControl = self.GetBaseUIControl("/grid1")

	@ViewBinder.binding_collection(ViewBinder.BF_BindBool, "gridDemo", "#UIDemo.visible")
	def GridItemVisible(self, index):
		return index < self.showNum and self.demoGridControl.GetVisible()

可以看到grid格子的visible属性我们以"#UIDemo.visible"设置而该字段经由bindings字段的设置取代了系统变量#visible再在python代码中绑定了"#UIDemo.visible"字段的函数更新回调。因此每个格子的visible属性就会读取python函数的返回值进行动态的设置。有关于数据绑定详情可见UI绑定和返回

ProgressBar

ProgressBar进度条控件用于百分比显示进度

{
    "progress_bar0" : {
        "$clip_direction" : "left",
        "$clip_ratio" : 0.0,
        "$is_new_nine_slice" : false,
        "$nine_slice_buttom" : 0,
        "$nine_slice_left" : 0,
        "$nine_slice_right" : 0,
        "$nine_slice_top" : 0,
        "$nineslice_size" : [ 0, 0, 0, 0 ],
        "$progress_bar_empty_texture" : "textures/ui/empty_progress_bar",
        "$progress_bar_filled_texture" : "textures/ui/filled_progress_bar",
        "anchor_from" : "center",
        "anchor_to" : "center",
        "controls" : [
            {
                "empty_progress_bar@fpsBattle.empty_progress_bar" : {}
            },
            {
                "filled_progress_bar@fpsBattle.filled_progress_bar" : {}
            }
        ],
        "layer" : 8,
        "offset" : [ 0, 0 ],
        "size" : [ 100, 10 ],
        "type" : "panel",
        "visible" : true
    },
    "empty_progress_bar" : {
        "is_new_nine_slice" : "$is_new_nine_slice",
        "layer" : 1,
        "nine_slice_buttom" : "$nine_slice_buttom",
        "nine_slice_left" : "$nine_slice_left",
        "nine_slice_right" : "$nine_slice_right",
        "nine_slice_top" : "$nine_slice_top",
        "texture" : "$progress_bar_empty_texture",
        "type" : "image"
    },
    "filled_progress_bar" : {
        "clip_direction" : "$clip_direction",
        "clip_ratio" : "$clip_ratio",
        "is_new_nine_slice" : "$is_new_nine_slice",
        "layer" : 2,
        "nine_slice_buttom" : "$nine_slice_buttom",
        "nine_slice_left" : "$nine_slice_left",
        "nine_slice_right" : "$nine_slice_right",
        "nine_slice_top" : "$nine_slice_top",
        "texture" : "$progress_bar_filled_texture",
        "type" : "image"
    }
}
变量
解释
$progress_bar_empty_texture 进度条背景图片
$progress_bar_filled_texture 进度条前景图片
$clip_direction 进度条加载方向,目前支持["left", "right", "up", "down", "center"]
grid_item_template 被当作生成网格单元的控件模板
$is_new_nine_slice 设置为true标记该图片开启九宫格显示的功能,从Json结构里可以看出两张图片的九宫设置用的是同一个
$nine_slice_bottom 切片距离下边的距离默认值为0
$nine_slice_left 切片距离左边的距离默认值为0
$nine_slice_right 切片距离右边的距离默认值为0
$nine_slice_top 切片距离上边的距离默认值为0
$nineslice_size 设置原版九宫属性,相比于旧版九宫属性更符合像素风格。当设置了旧版九宫属性时优先旧版属性。该值支持数组和单个数字,数组代表[left,top,right,down]九宫属性单个数值代表上下左右均采用该数值作为九宫属性当四个方向的数值均为0时表示不开启原版九宫

下图为UI编辑器中进度条控件的属性编辑面板。

控件表现

进度条属性

变量
解释
使用贴图 填充对应$progress_bar_filled_texture字段空白对应$progress_bar_empty_texture,将资源管理窗口中的图片资源拖曳到该图片小窗内赋值,可以在上方的下拉选项栏中重新选回默认图片
图片适配 普通表示不开启九宫选中旧版九宫则is_new_nine_slice置true开启旧版九宫设置选中原版九宫则开启原版九宫。

SwitchToggle

开关控件,用于两个状态之间的切换

{
    "switch_toggle0@common_toggles.switch_toggle_collection" : {
        "$default_texture" : "textures/ui/toggle_off",
        "$hover_texture" : "textures/ui/toggle_on",
        "$pressed_no_hover_texture" : "textures/ui/toggle_on_hover",
        "$pressed_texture" : "textures/ui/toggle_off_hover",
        "$toggle_name" : "#fpsBattle.toggle_name",
        "$toggle_state_binding_name" : "#fpsBattle.toggle_state",
        "anchor_from" : "center",
        "anchor_to" : "center",
        "bindings" : [
            {
                "binding_collection_name" : "",
                "binding_condition" : "always_when_visible",
                "binding_type" : "collection_details"
            }
        ],
        "layer" : 6,
        "offset" : [ 0, 0 ],
        "size" : [ 100, 100 ],
        "type" : "panel",
        "visible" : true
   }
}
变量
解释
$default_texture 开关默认图片
$hover_texture 开关鼠标悬浮状态图片
$pressed_texture 开关按下图片
$pressed_no_hover_texture 开关鼠标悬浮状态按下图片
$toggle_name 获取输入到的信息监听了BF_ToggleChanged的函数,类似文本输入框
$toggle_state_binding_name 开关控件显示toggle_state中返回的内容这与上面形成了一个双向绑定类似文本输入框
  • 注1
import mod.client.extraClientApi as clientApi
ViewBinder = clientApi.GetViewBinderCls()
ViewRequest = clientApi.GetViewViewRequestCls()
ScreenNode = clientApi.GetScreenNodeCls()

class TestScreen(ScreenNode):
    def __init__(self, namespace, name, param):
        ScreenNode.__init__(self, namespace, name, param)
        self.currentToggleShow = True

    @ViewBinder.binding(ViewBinder.BF_ToggleChanged)
    def OnDemoToggleChangeCallback(self,args):
        self.currentToggleShow = args["state"]
        return ViewRequest.Refresh

    @ViewBinder.binding(ViewBinder.BF_BindBool)
    def ReturnToggleState(self):
        return self.currentToggleShow

下图为UI编辑器中开关控件的属性编辑面板。

控件表现

开关属性

变量
解释
使用贴图 滑轨开对应$hover_texture字段滑轨关对应$default_texture,滑轨开时按下对应$pressed_no_hover_texture字段滑轨关时按下对应$pressed_texture,将资源管理窗口中的图片资源拖曳到该图片小窗内赋值,可以在上方的下拉选项栏中重新选回默认图片
绑定开关交互 对应$toggle_name字段
绑定开关内容 对应$toggle_state_binding_name字段

Slider

滑动条控件,用于拖动设置进度或百分比。

{
    "slider0@common.slider": {
        "$slider_tts_text_value": "#netease_tts_text_value",
        "$slider_name": "#UIDemoScreen.OnDemoSliderChange",
        "$slider_value_binding_name": "#UIDemoScreen.ReturnSliderValue",
        "$slider_steps_binding_name": "#UIDemoScreen.ReturnSliderStep",
        "$background_default_control": "common.slider_background",
        "$progress_default_control": "common.slider_progress",
        "$progress_default_clip_direction": "left",
        "$background_hover_control": "common.slider_background_hover",
        "$progress_hover_control": "common.slider_progress_hover",
        "$progress_hover_clip_direction": "left",
        "$slider_direction": "horizontal",
        "$slider_box_layout": "common.slider_button_layout",
        "$slider_box_hover_layout": "common.slider_button_hover_layout",
        "$slider_box_locked_layout": "common.slider_button_locked_layout",
        "$slider_box_indent_layout": "common.slider_button_indent_layout",
        "$slider_box_size": [10, 16],
        "size": [100, 10],
        "offset": [0, 0],
        "$slider_step_factory_control_ids": {
            "slider_step": "@common.slider_step",
            "slider_step_hover": "@common.slider_step_hover",
            "slider_step_progress": "@common.slider_step_progress",
            "slider_step_progress_hover": "@common.slider_step_progress_hover"
        }
    }
}
变量
解释
$slider_tts_text_value 开发者无需关注,但为必填属性,建议值为 "#netease_tts_text_value"(只要是以"#"开头的字符串值即可)
$slider_name 获取滑动条的信息监听了BF_SliderChanged的函数OnDemoSliderChange会在滑动条值改变时调到该函数可参考下面的注1
$slider_value_binding_name 滑动条显示ReturnSliderValue中返回的值这与上面形成了一个双向绑定该值必须是float类型可参考下面的注1
$slider_steps_binding_name 滑动条总步长由ReturnSliderStep函数中返回的值进行设置。当设置大于1时该滑动条为固定格类型类似设置面板中能见度设置滑动范围为0-总步长当设置小于等于1时该滑动条为百分比类型类似设置面板中音量设置滑动范围为0-1。
$background_default_control 滑动条背景默认情况下显示的控件须为image
$progress_default_control 滑动条前景默认情况下显示的控件会根据当前进度进行裁剪须为image
$progress_default_clip_direction 滑动条前景默认情况下被裁剪方向, 可填"left", "right", "up", "down", "center"
$background_hover_control 滑动条背景在鼠标悬浮及按下情况下显示的控件须为image
$progress_hover_control 滑动条前景在鼠标悬浮及按下情况下显示的控件会根据当前进度进行裁剪须为image
$progress_hover_clip_direction 滑动条前景在鼠标悬浮及按下情况下被裁剪方向, 可填"left", "right", "up", "down", "center"
$slider_direction 滑动条方向,可填"horizontal","vertical"和"none",默认为"horizontal"。注意当滑动条方向改变时不会自动改变滑动条前景默认情况和悬浮及按下情况下被裁减的方向,如有需要请修改$progress_default_clip_direction和$progress_hover_clip_direction属性
$slider_box_layout 滑动格默认情况下显示的控件
$slider_box_hover_layout 滑动格鼠标悬浮情况下显示的控件
$slider_box_locked_layout 滑动格鼠标不可用情况下显示的控件
$slider_box_indent_layout 滑动格按下情况下显示的控件
$slider_box_size 滑动格大小
$slider_step_factory_control_ids 当滑动条为固定格类型滑动条时,滑动条会生成等距的分隔线来标明单步滑动的位置。而这一系列的分割线就是由$slider_step_factory_control_ids属性内的各个控件控制的。
slider_step 背景分隔线默认情况下显示的控件
slider_step_hover 背景分隔线鼠标悬浮情况下显示的控件
slider_step_progress 前景分隔线默认情况下显示的控件
slider_step_progress_hover 前景分隔线鼠标悬浮情况下显示的控件
  • 注1
import mod.client.extraClientApi as clientApi
ViewBinder = clientApi.GetViewBinderCls()
ViewRequest = clientApi.GetViewViewRequestCls()
ScreenNode = clientApi.GetScreenNodeCls()

class UIDemoScreen(ScreenNode):
    def __init__(self, namespace, name, param):
        ScreenNode.__init__(self, namespace, name, param)
        self.sliderPercentValue = 0.5  # 百分比值
        # self.sliderAbsValue = 5.0 # 固定值

    @ViewBinder.binding(ViewBinder.BF_SliderChanged | ViewBinder.BF_SliderFinished)
    def OnDemoSliderChange(self, value, isFinish, _unused):
        self.sliderPercentValue = value   # 百分比类型滑动条保存值
        # self.sliderAbsValue = value   # 固定格类型滑动条保存值
        return ViewRequest.Refresh

    @ViewBinder.binding(ViewBinder.BF_BindFloat)
    def ReturnSliderValue(self):
        return self.sliderPercentValue   # 百分比类型滑动条返回值
        # return self.sliderAbsValue  # 固定格类型滑动条返回值

	@ViewBinder.binding(ViewBinder.BF_BindInt)
    def ReturnSliderStep(self):
        return 1 # 百分比类型滑动条
        # return 10  # 固定格类型滑动条

下图为Slider在游戏中的控件表现

滑动控件

SelectionWheel

该控件表现为一个轮盘选择UI为了开发方便可继承common_selection_wheels命名空间下的base_selection_wheel控件Demo中表现如下。

轮盘控件-1

该控件结构稍微复杂本质上是一堆控件的组合直接看json不够直观。总体是分为两部分一部分控件是不管鼠标怎么移动都不影响那部分控件的可见性visible属性比如这些ItemRenderer以及中间的Label。

轮盘控件-2

而另一部分控件根据鼠标不同的位置,确定显示哪个控件,比如这个轮盘本身,本质上是一堆带不同选中效果的图片控件。

轮盘控件-3

Demo中显示的轮盘控件是一个圆环形状这是因为计算鼠标位置映射到哪个控件的时候是按照鼠标落在圆环的哪个扇区决定的这是比较精确的显示但实际上是可以用相似的形状去贴近这个圆环的比如如果圆环切分的不够多均分成6个就可以用下面的形状去近似。

这是轮盘控件近似的映射区域。

轮盘控件-4

这是轮盘控件实际的映射区域。

轮盘控件-5

了解了这个控件结构后制作自己的轮盘控件需要确定的就是弄清楚鼠标移到哪个区域对应哪一个图片。实际上轮盘的映射规则并不明显这里提供一个python函数计算出 index == 0 的区域在极坐标系中的角度范围,下图是极坐标系示意图。

极坐标

index == 0 的区域在极坐标系中的坐标范围计算

# 获取第一个item的角度范围
def getFirstItemRange(itemNum):
	perItemSize = 360 / itemNum
	offset = 180 - perItemSize / 2
	rangeStart = -(0 - offset)
	rangeEnd = -(perItemSize - offset)
	print(rangeStart, rangeEnd)
	return rangeStart, perItemSize

为了方便开发者更快地确定不同数量叶片的情况,UIDemoMod 中有3-10个叶片的图片示例外直径400内直径200路径为 "UIDemoMod/uidemoResourcePack/textures/ui/SelectionWheel/samples"后续UI编辑器中将会集成对应的工具生成这些图片。

轮盘控件-7

值得注意的是,生成的图片中,有一张图片是需要作为这个轮盘的默认状态(也就是鼠标还未移到控件上的时候控件显示的状态),这张图片所对应的控件,就是轮盘的默认状态(也叫默认索引)。

有了上面的理解json中的属性就比较清晰我们以下面的json为例说明。

{
   "namespace": "custom_wheel_namespace",
   "wheel_state" : {
      "type" : "image"
   },
   "custom_selection_wheel_content":{
      "type": "panel",
      "controls": [
         {
            "state_default@custom_wheel_namespace.wheel_state": {
                "texture" : "textures/ui/circle/custom_wheel_selection_default"
            }
         },
         {
            "state_0@custom_wheel_namespace.wheel_state": {
                "texture" : "textures/ui/circle/custom_wheel_selection_0"
            }
         },
         {
            "state_1@custom_wheel_namespace.wheel_state": {
                "texture" : "textures/ui/circle/custom_wheel_selection_1"
            }
         },
         {
            "state_2@custom_wheel_namespace.wheel_state": {
                "texture" : "textures/ui/circle/custom_wheel_selection_2"
            }
         },
         {
            "state_3@custom_wheel_namespace.wheel_state": {
                "texture" : "textures/ui/circle/custom_wheel_selection_3"
            }
         },
         {
            "state_4@custom_wheel_namespace.wheel_state": {
                "texture" : "textures/ui/circle/custom_wheel_selection_4"
            }
         },
         {
            "state_5@custom_wheel_namespace.wheel_state": {
                "texture" : "textures/ui/circle/custom_wheel_selection_5"
            }
         }
      ]
   },
   "custom_selection_wheel@common_selection_wheels.base_selection_wheel" : {
      "inner_radius" : 0.35,
      "outer_radius" : 1.0,
      "size" : [ 200, 200 ],
      "slice_count" : 6,
      "initial_button_slice": -1,
      "$content": "custom_wheel_namespace.custom_selection_wheel_content",
      "state_controls" : [
         "state_default",
         "state_0",
         "state_1",
         "state_2",
         "state_3",
         "state_4",
         "state_5"
      ]
   }
}

属性
解释
slice_count 轮盘切片的数量如上图显示这个轮盘有6个选择所以将圆环平均切成了6份
outer_radius 轮盘的外直径系数,该值是一个比例值默认为1.0不建议修改该值。 该比例值是用来计算轮盘响应的外直径的有多大,轮盘的外直径 = outer_radius * min(width, height),其中 widthheight分别轮盘控件的宽高控件size属性值
inner_radius 轮盘的内直径系数默认为0.0。
state_controls 上文所说的那一部分跟随鼠标位置变化的控件的名称, 这些控件必须是轮盘的子控件(不一定是直接子控件,可以是孙子或者更往下的子控件),在轮盘中,每个状态控件都有一个索引 index默认状态控件的 index = -1其他状态的index范围为 [0, slice_count - 1] ,需要注意的是,第一个控件必须是作为默认状态控件。
initial_button_slice 轮盘刚创建出来时所处的索引,默认值为-1
变量
解释
$content 轮盘的内容控件,本质是一个控件变量,请将所有子控件都声明到该控件中

对于上面所出现的三种轮盘,UIDemo 中都涵盖了。

  • 注1

目前轮盘控件在SDK中支持的回调仅有两个hover的回调通过SetHoverCallback接口设置回调)以及SetTouchUpCallback接口设置回调这些事件是在SelectionWheel控件的区域内发出注意这个区域并不是可见的圆环区域而是方形的区域如下图所示

hover事件的触发本质上是与鼠标悬浮相关在PC模式中当鼠标从控件方形区域外移动到方形区域内时会触发一次hover事件从方形区域内移到方形区域外也会触发一次hover事件当选中轮盘并且轮盘的选中索引发生了改变index值改变也会触发一次hover事件。 而在PE模式下鼠标是模拟出来的鼠标的悬浮是通过按着鼠标模拟点进行拖动或者点击某个位置来模拟的因此hover事件触发逻辑其实和PC模式是一致的。

鼠标按下后弹起的事件则无论是PC还是PE都是一致的是在控件方形区域内检测到鼠标按下后弹起都会触发无论index是否改变了

轮盘控件-8

  • 注2

推荐轮盘所在的Screen用PushScreen的方式创建因为PushScreen加载的UI是会对该UI中存在的控件中的贴图资源进行强制加载如果这个贴图从未显示过的话考虑到轮盘的贴图资源比较多6切片的轮盘如果用CreateUI的方式创建轮盘,并且这些轮盘贴图从未显示过,那么选择轮盘的时候就会产生闪烁现象,原因就是第一次显示的贴图资源会动态加载,而动态加载是需要一定时间的。如果想彻底解决这类加载问题,详见 贴图预加载

轮盘控件-9

  • 注3

如果希望用手柄对轮盘进行控制需要在轮盘所在的Screen上声明属性 "gamepad_cursor_deflection_mode" 为 true具体可见下方的类似json代码

{
    "main" : {
        "controls" : [],
        "type" : "screen",
        "gamepad_cursor_deflection_mode": true
   }
}

NeteaseComboBox

网易版单选下拉框,可以在给定的选项中进行选择。

{
    "comboBoxPanel@combo_box.comboBoxPanel" : {
        "$content_size":[ "100.0%+0.0px", 100 ],
        "$item_size":[ "100.0%+0.0px", "10.0%x+0.0px" ],
        "$title_label":"combo_box.titleLabel",
        "$content_label":"combo_box.label",
        "$title_down_image":"combo_box.dropdownImage",
        "$title_up_image":"combo_box.dropupImage",
        "$default_title_texture" : "textures/ui/button_borderless_light",
        "$hover_title_texture" : "textures/ui/button_borderless_lighthover",
        "$pressed_title_texture" : "textures/ui/button_borderless_lightpressed",
        "$title_nineslice_size|default" : [ 0.0, 0.0, 0.0, 0.0 ],
        "$default_item_texture" : "textures/ui/button_borderless_light",
        "$hover_item_texture" : "textures/ui/button_borderless_lighthover",
        "$pressed_item_texture" : "textures/ui/button_borderless_lightpressed",
        "$item_nineslice_size|default" : [ 0.0, 0.0, 0.0, 0.0 ],
        "$scroll_background_texture" : "textures/ui/ScrollRail",
        "alpha" : 1.0,
        "anchor_from" : "center",
        "anchor_to" : "center",
        "clip_offset" : [ 0, 0 ],
        "clips_children" : false,
        "enabled" : true,
        "layer" : 0,
        "max_size" : [ 0, 0 ],
        "min_size" : [ 0, 0 ],
        "offset" : [ 0.0, 0.0 ],
        "priority" : 0,
        "propagate_alpha" : false,
        "size" : [ 120, 20 ],
        "type" : "panel",
        "visible" : true
    }
}
变量
解释
$content_size 下拉框整个弹出框的大小,默认值为[ "100.0%+0.0px", 100 ]
$item_size 下拉框单个下拉项相对于整个弹出框的大小,默认值为[ "100.0%+0.0px", "10.0%x+0.0px" ]
$title_label 下拉框标题文本控件引用,默认值为"combo_box.titleLabel"
$content_label 下拉框单个下拉项文本控件引用,默认值为"combo_box.label"。
$title_down_image 下拉框未展开弹出框时标题右侧小图标控件引用,默认值为"combo_box.dropdownImage"
$title_up_image 下拉框展开弹出框时标题右侧小图标控件引用,默认值为"combo_box.dropupImage"
$default_title_texture 下拉框标题默认状态图片路径,默认值为"textures/ui/button_borderless_light"
$hover_title_texture 下拉框标题悬浮状态图片路径,默认值为"textures/ui/button_borderless_lighthover"
$pressed_title_texture 下拉框标题按下状态图片路径,默认值为"textures/ui/button_borderless_lightpressed"
$default_item_texture 下拉框单个下拉项默认状态图片路径,默认值为"textures/ui/button_borderless_light"
$hover_item_texture 下拉框单个下拉项悬浮状态图片路径,默认值为"textures/ui/button_borderless_lighthover"
$pressed_item_texture 下拉框单个下拉项按下状态图片路径,默认值为"textures/ui/button_borderless_lightpressed"
$title_nineslice_size 下拉框标题图片九宫切图,默认值为[ 0.0, 0.0, 0.0, 0.0 ]
$item_nineslice_size 下拉框单个下拉项图片九宫切图,默认值为[ 0.0, 0.0, 0.0, 0.0 ]
$scroll_background_texture 下拉框弹出框背景图片,默认值为"textures/ui/ScrollRail"

向该下拉框添加内容、注册选中回调等操作均需要调用UIAPI详情请参考 NeteaseComboBoxUIControl

下图为网易版单选下拉框在游戏中的控件表现

网易版下拉框

UI编辑器暂时不支持编辑

MiniMap

该控件可以在UI上画小地图需要继承mini_map命名空间下的mini_map_wrapper控件。

其中官方封装了地图界面基类 MiniMapBaseScreen 供开发者扩展。

{
    "mainPanel@mini_map.mini_map_wrapper" : {
        "anchor_from" : "top_right",
        "anchor_to" : "top_right",
        "layer" : 1,
        "offset" : [ -10.0, 10.0 ],
        "$enable_live_update": false,
        "$live_update_interval": 5,
        "$use_default_face_icon": true,
        "$face_icon_size": [4,4],
        "$face_icon_bg_color": "white",
        "$highest_y": 0,
        // 如果希望小地图能够被裁剪请继承后修改controls如下:
        "controls":[
            {
                "mini_map_bg@mini_map.mini_map_bg": {}
            },
            {
                "netease_mini_map@mini_map.netease_mini_map": {
                    "allow_clipping":true,
                    "enable_scissor_test" : true
                }
            },
            {
                "icon@mini_map.icon": {}
            },
            {
                "head_lbl@mini_map.head_label": {}
            },
            {
                "text_lbl@mini_map.text_label": {}
            }
        ]
    }
}

相关字段说明:

变量
解释
$enable_live_update 是否开启方块变化更新到小地图上(简称“热更”)
$live_update_interval “热更”的时间间隔单位秒s不建议间隔太小更新太频繁在低端机器可能有性能问题
$use_default_face_icon 本地玩家是否使用默认的脸部作为标记icon
$face_icon_size 脸部icon的大小默认为[4,4]
$face_icon_bg_color 标记icon底部背景颜色默认为白色
$highest_y 绘制的高度最大值,默认当前区块的最大值,当该值为-1时表示最大高度值为玩家当前位置所在的高度
enable_scissor_test 超出父控件区域后是否裁剪默认为false, enable_scissor_test

颜色渐变控件gradientRenderer

该控件可以用于在ui上绘制渐变颜色

{
    "gradient": {    
        "color1": [1, 0, 1, 1],    
        "color2": [0, 0, 1, 1],    
        "gradient_direction": "vertical",    
        "renderer": "gradient_renderer",    
        "type": "custom" 
    }
}
变量 解释
color1 渐变起始颜色的RGBA
color2 渐变结束颜色的RGBA
gradient_direction 渐变方向,可选"vertical"或"horizontal"
renderer 需要指定为gradient_renderer
type 需要指定为custom
图片描述

下图为UI编辑器中颜色渐变控件的属性编辑面板

图片描述
变量 解释
渐变起始颜色 对应color1字段支持调整不透明度Alpha通道
渐变结束颜色 对应color2字段支持调整不透明度Alpha通道
渐变方向 对应gradient_direction字段可选“垂直排布”或“水平排布”

继承控件

继承控件允许开发者选择并继承目标控件,继承成功后该控件拥有目标控件的所有属性,并可以重写其中任何一个属性的数据。

继承写法简述

在界面json文件所有的编写技巧中最为好用和灵活的功能当属继承写法。当界面中有一个需求需要将若干个相同的控件按序排列除了可以通过复制粘贴出若干个控件副本外继承模板控件并只修改我们所需要修改的属性其他的属性依然沿用模板控件的数据才是最便捷也是最漂亮的写法。下面我们从一个简单的例子入手熟悉继承的写法从例子中我们可以快速熟悉继承技巧。

{
   "main" : {
      "absorbs_input" : true,
      "always_accepts_input" : false,
      "controls" : [
         {
            "label0@myInherit.label0" : {}
         },
         {
            "inheritor0@myInherit.label0" : {
               "offset" : [ 10.0, 0.0 ]
            }
         },
         {
            "inheritor1@myInherit.label0" : {
               "offset" : [ 20.0, 0.0 ]
            }
         }
      ],
      "force_render_below" : false,
      "is_showing_menu" : true,
      "render_game_behind" : true,
      "render_only_when_topmost" : true,
      "should_steal_mouse" : false,
      "type" : "screen"
   },
   "label0" : {
      "anchor_from" : "center",
      "anchor_to" : "center",
      "color" : [ 1, 1, 1 ],
      "font_scale_factor" : 1.0,
      "font_size" : "normal",
      "font_type" : "smooth",
      "layer" : 0,
      "offset" : [ 0, 0 ],
      "shadow" : false,
      "size" : [ 100, 100 ],
      "text" : "Hello World!",
      "text_alignment" : "center",
      "type" : "label",
      "visible" : true
   },
   "namespace" : "myInherit"
}

该段json描述了在main画布中创建了一个文本控件label0并使继承控件inherit0和inherit1均继承了label0控件并重写了offset属性在场景中就得到了三个文本控件这三个文本控件除了在场景中的位置因为重写而不同外其他的属性一模一样。但是要注意的是可以被继承的控件必须写在json文件的最外层和main处在同一层级即一个命名空间下有且仅有一个该名称的控件满足该条件的控件才可以被继承。

UI编辑器中的继承

新版的UI编辑器对继承提供了更可视化的方法请参考继承和自定义控件

Python编写说明

必要的属性

import mod.client.extraClientApi as clientApi
ViewBinder = clientApi.GetViewBinderCls()
ViewRequest = clientApi.GetViewViewRequestCls()
ScreenNode = clientApi.GetScreenNodeCls()
变量 解释
extraClientApi 我们开发的Client端Api接口文件
ViewBinder 用于绑定回调函数的类型和响应的方法
ViewRequest 用于返回绑定函数的返回值
ScreenNode UI的基类用于继承基类的方法和UI管理

UI界面初始化

import mod.client.extraClientApi as clientApi

ScreenNode = clientApi.GetScreenNodeCls()

class TestScreen(ScreenNode):
	def __init__(self, namespace, name, param):
		ScreenNode.__init__(self, namespace, name, param)

ScreenNode是我们的UI节点基类必须继承。

# Bind Type
class ViewBinder(object):
    ButtonFilter = 0x10000000
    BF_ButtonClickUp =	0 | ButtonFilter
    BF_ButtonClickDown = 1 | ButtonFilter
    BF_ButtonClick =  2 | ButtonFilter
    BF_ButtonClickCancel = 3
    BF_InteractButtonClick = 4
    BindFilter = 0x01000000
    BF_BindBool	= 5 | BindFilter
    BF_BindInt	= 6 | BindFilter
    BF_BindFloat = 7 | BindFilter
    BF_BindString = 8 | BindFilter
    BF_BindGridSize = 9 | BindFilter
    BF_BindColor = 10 | BindFilter
    EditFilter = 0x00100000
    BF_EditChanged = 11 | EditFilter
    BF_EditFinished = 12 | EditFilter
    ToggleFilter = 0x00010000
    BF_ToggleChanged = 13 | ToggleFilter
    
# Return Type
class ViewRequest(object):
    Nothing = 0
    Refresh = 1 << 0
    PointerHeldEventsRequest = 1 << 1
    PointerHeldEventsCancel = 1 << 2
    Exit = 1 << 3

UI绑定和返回

UI的绑定分为binding单个绑定和binding_collection集合绑定适合集合容器。

绑定类型 绑定方式 解释
BF_ButtonClickUp binding 绑定按钮的Up事件
BF_ButtonClickDown binding 绑定按钮的Down事件
BF_ButtonClick binding 同时绑定Up和Down事件
BF_ButtonClickCancel binding 绑定按钮的Cancel事件按钮down其他up
BF_InteractButtonClick binding 绑定游戏原生的按钮点击事件
BF_BindBool binding | binding_collection 绑定Bool变量
BF_BindInt binding | binding_collection 绑定Int变量
BF_BindFloat binding | binding_collection 绑定Float变量
BF_BindString binding | binding_collection 绑定String变量
BF_BindGridSize binding 绑定GridSize变量
BF_BindColor binding | binding_collection 绑定颜色变量
BF_EditChanged binding 绑定输入框输入改变事件
BF_EditFinished binding 绑定输入框输入完成事件
BF_ToggleChanged binding 开关状态改变事件

binding(bind_flag, binding_name = None)

bind_flag为上文中绑定类型binding_name为绑定名称。

binding_name为脚本绑定变量binding_name_override为引擎变量json格式如下

{
    "bindings": [
        {
            "binding_condition" : "always",
            "binding_name" : "#scoreboard_grid.item_count",
            "binding_name_override" : "#StackGridItemsCount"
        }
    ]
}

对应的Python代码如下

import mod.client.extraClientApi as clientApi

ViewBinder = clientApi.GetViewBinderCls()

@ViewBinder.binding(ViewBinder.BF_BindInt, "#scoreboard_grid.item_count")
def OnStarkGridResize(self):
    return len(self.scoreBoardList)

binding_collection(bind_flag, collection_name, binding_name = None)

bind_flag为上文中的绑定类型collection_name为集合名称binding_name为绑定的变量名称。

集合的json如下

{
    "collection_name" : "scoreboard_stackgrid"
}

在集合的子控件中binding_collection_name为集合名binding_condition为绑定条件binding_name为绑定名称binding_type为collection绑定property_bag设置他的初始值text为它的绑定值。

{
    "label_score_board" : {
        "bindings" : [
            {
                "binding_collection_name" : "scoreboard_stackgrid",
                "binding_condition" : "always",
                "binding_name" : "#label_score_board.text",
                "binding_type" : "collection"
            }
        ],
        "offset" : [ "0%+0 px", "0%+0px" ],
        "property_bag" : {
            "#label_score_board.text" : "666666666666"
        },
        "text" : "#label_score_board.text",
        "text_alignment" : "left",
        "type" : "label",
        "visible" : true
    }
}

对应的Python代码如下其中index表示在集合中的哪一元素。

import mod.client.extraClientApi as clientApi

ViewBinder = clientApi.GetViewBinderCls()

@ViewBinder.binding_collection(ViewBinder.BF_BindString, "scoreboard_stackgrid", "#label_score_board.text")
def OnRefreshScoreBoardLabel(self, index):
    return self.scoreBoardList[index] if len(self.scoreBoardList) > index else ""

接口调用说明

参数命名说明

@Mod.Binding(name = myModName, version = myModVersion)

参数 类型 解释
myModName str Mod名称
myModVersion str Mod版本

假设设置Mod名称为"myModName",示例:

from mod.common.mod import Mod
@Mod.Binding(name = "myModName", version = "0.1")
class MyModClass(object):
    def __init__(self):
        pass

界面创建流程及生命周期

界面在 UiInitFinished 事件发送之后就可以开始创建

创建UI的第一步是UI的注册通过调用 RegisterUI 接口将想开启UI的相关数据进行注册。同一UI只需要注册一次即可

注册完成之后就可以在需要的时候实例化UI可使用的接口有 CreateUI PushScreen 两种。使用 CreateUI 生成的界面都生成在操作UI下不同的生成参数UI层级不同而使用 PushScreen 生成的界面以堆栈管理的方式生成,该界面生成时上一个 PushScreen 生成的界面就会被隐藏。值得注意的是MC原生界面比如暂停界面背包界面等也是类似 PushScreen 的方式加载进来,并以堆栈管理。

在UI创建完成之后可以调用 GetUI 接口拿到UI对应的ScreenNode实例。 如果想获取MC原生界面的实例则需要监听原生界面Push进来的事件 PushScreenEvent ,然后在事件回调中调用接口 GetTopPushedUI

每个ScreenNode都有生命周期函数生命周期函数会被自动在以下情况下调用重写函数可以完成一些逻辑。

函数 作用
Create UI创建成功时调用
OnActive UI重新回到栈顶时调用
OnDeactive 栈顶UI有其他UI入栈时调用
Destroy UI销毁时调用

最后当UI需要销毁时可以调用ScreenNode实例的 SetRemove 接口,此外使用 PushScreen 接口创建的界面还可以使用 PopScreen 接口进行销毁。

手柄交互

1使用 PushScreen生成出的界面调出手柄光标有两步一是需要将底层Screen继承自common.base_screen二是将screen的"gamepad_cursor" 属性设置为 true如下格式

{
   "main@common.base_screen" : {
       ....
       "gamepad_cursor" : true
   },
   "namespace" : "Test"
}

2使用 CreateUI生成出的界面只支持手柄与创建UI时isHud参数设置为0的Screen中的按钮进行交互。

3使用 PushScreen生成出具有轮盘控件的UI时需要将底层screen的"gamepad_cursor_deflection_mode" 属性设置true否则将无法选中轮盘格子

4GamepadModDemo展示了两种UI创建如何与手柄交互以及一个基础的扳机使用方法。

UIDemoMod介绍

为了让开发者更好的了解各个UI控件的使用方法以及控件在mod界面中的应用我们开发了一个简单的UIDemoMod开发者可以在官网下载到它。该Demo包含了文本、文本输入框、滚动列表、网格、进度条、按钮、图片、开关、纸娃娃、道具渲染控件的操作与逻辑演示。下图为UIDemoMod菜单界面。

UIDemo菜单

例如我们想了解一下文本控件是如何使用的,点击“文本控件演示”按钮进入演示界面,如下图。

UIDemo菜单

由于功能相关以及方便演示我们将文本和文本输入框控件做在一个界面中共同演示。控件的演示界面中有待演示的UI控件、操作方法和返回菜单界面按钮。如操作方法描述的我们在文本输入框中输入文本上方的文本控件会根据文本输入框输入的内容发生对应的变化逻辑可以在UIDemoMod的脚本代码中查到如下图。

UIDemo菜单

还想了解其他控件的用法就下一个UIDemo看看吧

富文本控件介绍

富文本控件提供了一个支持文本、图片、按钮、超链接、序列帧的复合文本控件富文本控件接受按一定规则组成的字符串除去常规文本外定制化文本及非文本控件用html的标签写法隔开<button></button>,中间填写json格式数据。开发者可以在UI中引用该控件并将符合解析规则的字符串传入解析接口富文本控件会根据传入的字符串顺序排列生成富文本。以下详细介绍用法。

富文本支持定制化文本及非文本控件及写法

换行控件

2.6新增换行控件<br>,可在非标签的内容、定制化文本控件<label>的“text”变量按钮控件<button>的“button_label”变量中使用。

  • 非标签内的换行与常规换行类似,但是需要下一行有内容才会出现换行效果,所以在文本的首位两端使用<br>换行控件是没有任何效果的
  • 定制化文本控件<label>的“text”变量按钮控件<button>的“button_label”变量中使用<br>控件,只是对内部的内容进行换行,无法影响到外部的内容

使用方法如下所示

// 定制化文本控件
<label>
{"text" : "玩<br>家一", 
 "font" : "smooth", 
 "scale": 3, 
 "color": [1,0,0,1]}
</label>
// 在非标签的内容
Dear player, <br>welcome to Minecraft, <br>where you can build your own world
// 按钮控件
// 注意:如果按钮控件空间不足以显示该字符串,多余部分将以"..."显示
<button>
{"button_label": "1<br>2<br>3", 
 "press_texture" : "textures/ui/btn_pressed",
 "hover_texture" : "textures/ui/btn_hover",
 "default_texture" : "textures/ui/btn_light_default","x":50, "y":100}
</button>

例子及效果:

<label>{"text" : "玩<br>家一", "font" : "smooth", "scale": 3, "color": [1,0,0,1]}</label><br><button>{"button_label": "1<br>2<br>3", "press_texture" : "textures/ui/btn_pressed","hover_texture" : "textures/ui/btn_hover","default_texture" : "textures/ui/btn_light_default","x":50, "y":100}</button>:恭喜!<br>击杀了<link>{"text" : "末影人", "format_code":"§2"}</link>

rich_txt_br

定制化文本控件

在字符串中嵌入<label>"label_data"</label>样式文本会被解析成定制文本与常规文本不同的是定制化文本可以独立设置文字的字体、大小、颜色等丰富富文本的文本样式。label_data为特殊化数据以下所列属性为必须属性text为文本font为字体默认值为unicodescale为字体缩放倍率默认值为1.0color为字体颜色默认值为[1,1,1,1]。需要注意的是如果文本中存在中文字符则字体会被强制设置为unicode此外如果字体缩放倍率过大该段文本将不会被显示。

{
    "label_data": {
          "text" : "玩家一", 
          "font" : "smooth", 
          "scale": 3, 
          "color": [1,0,0,1]
    }
}

图片控件

在字符串中嵌入<image>"image_data"</image>样式文本会被解析成图片image_data为特殊化数据以下所列属性为必须属性texture为资源路径x为图片宽度y为图片高度

{
    "image_data": {
        "texture":"texture/ui/laugh",
        "x":30,
        "y":30
   }
}

按钮

在字符串中嵌入<button>"button_data"</button>样式会被解析成按钮button_data为特殊化数据开发者可以在其中添加符合json格式的自定义数据在点击富文本中对应按钮时会将button_data通过回调函数整个返回以下属性为必须属性press_texture为按钮按下贴图hover_texture为按钮鼠标悬浮贴图default_texture为默认状态下按钮贴图button_label为按钮上的问题x为按钮宽度y为按钮高度

{
    "button_data":{
        "press_texture": "",
        "hover_texture": "",
        "default_texture": "",
        "button_label": "",
        "x":20,
        "y":20
   }
}

超链接

在字符串中嵌入<link>"link_data"</link>样式会被解析成超链接外观和普通文本无异但可以被点击link_data为特殊化数据开发者可以在其中添加符合json格式的自定义数据在点击富文本中对应超链接时会将link_data通过回调函数整个返回以下属性为必须属性text表示显示文本format_code表示该段显示文本的样式代码注意基岩版的文本控件不支持下划线和删除线。

{
    "link_data":{
        "text":"末影人",
        "format_code":"§2"
    }
}

序列帧动画

在字符串中嵌入<sfx>"sfx_data"</sfx>样式文本会被解析成图片sfx_data为特殊化数据以下所列属性为必须属性texture为资源路径x为显示图片宽度y为显示图片高度uv_x为截取图片宽度uv_y为截取图片高度frame_count表示该序列帧的总帧数fps为每秒执行帧数。

{
    "sfx_data":{
        "texture": "textures/ui/eating_apple",
        "x":30,
        "y":30,
        "uv_x": 64,
        "uv_y": 64,
        "frame_count": 36,
        "fps": 10
   }
}

富文本成品范例

文本

'[玩家]<label>{"text" : "玩家一", "font" : "smooth", "scale": 3, "color": [1,0,0,1]}</label><button>{"press_texture" : "textures/ui/btn_pressed","hover_texture" : "textures/ui/btn_hover","default_texture" : "textures/ui/btn_light_default","x":20, "y":20}</button>:恭喜!<image>{"texture":"textures/ui/skin/ty_yuanshenghuli_0_0", "x":30, "y":30}</image>击杀了<link>{"text" : "末影人", "format_code":"§2"}</link><sfx>{"texture": "textures/ui/eating_apple","x":30, "y":30,"uv_x": 64,"uv_y": 64,"frame_count": 36,"fps": 10}</sfx>'

效果

富文本效果

如何使用富文本

UI文件编写

若需要使用富文本开发者只需要继承rich_text命名空间下的RichTextPanel控件它是一个panel控件也是单个富文本控件的根节点该panel的宽度决定了富文本宽度。我们开放了若干引用属性可供设置。

  • $rich_panel_bg

    开发者可以设置富文本的背景图片

  • $rich_panel_nineslice_size

    开发者可以设置背景图片的九宫切图,值为0.01代表开启微软版本的九宫切图且上下左右为切图像素为0.01,等价于[0.01,0.01,0.01,0.01]。

  • $rich_panel_font_size

    开发者可以设置富文本的文本字体大小可设置选项为small, normal, large其中一个默认值为normal

  • $rich_panel_font_scale_factor

    开发者可以设置富文本的文本字体缩放倍率,和$rich_panel_font_size一起影响富文本字体的最终大小默认值为1.0

  • $rich_panel_color

    开发者可以设置富文本的文本字体颜色,默认值为[1,1,1],白色

{
    "main" : {
        "absorbs_input" : true,
        "always_accepts_input" : false,
        "controls" : [
            {
                "RichTextPanel@RichText.RichTextPanel" : {}
            }
        ],
        "force_render_below" : false,
        "is_showing_menu" : true,
        "render_game_behind" : true,
        "render_only_when_topmost" : true,
        "should_steal_mouse" : false,
        "type" : "screen"
   },
   "RichTextPanel@rich_text.RichTextPanel" : {
        "$rich_panel_bg": "textures/ui/effect_background",
        "$rich_panel_nineslice_size": 0.01,
        "$rich_panel_font_size" : "large",
        "$rich_panel_font_scale_factor" : 2.0,
        "$rich_panel_color" : [1,1,1]
   }
}

python脚本编写

在需要创建富文本时调用UIAPI GetRichTextItem将富文本控件路径作为参数传入就能返回得倒一个RichTextItem实例就完成了富文本的初始化。

富文本提供了三个回调注册接口和一个设置文本接口。

registerLinkItemClickCallback

注册点击超链接回调函数参数为一个函数引用。超链接点击触发时会返回开发者给超链接设置的数据以及当前点击屏幕的坐标值touchX和touchY

registerButtonItemClickCallback

注册点击按钮回调函数参数为一个函数引用。按钮点击触发时会返回开发者给按钮设置的数据以及当前点击屏幕的坐标值touchX和touchY

registerRichTextFinishCallback

注册富文本创建完毕回调函数,由于富文本构成较为复杂,无法在一帧之内生成完毕,因此生成需要一点点时间,等富文本创建完毕后会调用该回调函数。

readRichText

创建富文本入口,接受一个符合格式的字符串,将其转变为富文本显示出来。

以下是示例

def CreateRichText(self):
    self.richTextPath = "/RichTextPanel"
    self.richTextItem = self.GetRichTextItem(self.richTextPath)
    self.richTextItem.registerLinkItemClickCallback(self.OnLinkItemClickCallback)
    self.richTextItem.registerButtonItemClickCallback(self.OnButtonItemClickCallback)
    self.richTextItem.registerRichTextFinishCallback(self.OnRichTextCreateFinishCallback)
    self.richTextItem.readRichText('[玩家]<label>{"text" : "玩家一", "font" : "smooth", "scale": 3, "color": [1,0,0,1]}</label><button>{"press_texture" : "textures/ui/btn_pressed","hover_texture" : "textures/ui/btn_hover","default_texture" : "textures/ui/btn_light_default","x":20, "y":20}</button>:恭喜!<image>{"texture":"textures/ui/skin/ty_yuanshenghuli_0_0", "x":30, "y":30}</image>击杀了<link>{"text" : "末影人", "format_code":"§2"}</link><sfx>{"texture": "textures/ui/eating_apple","x":30, "y":30,"uv_x": 64,"uv_y": 64,"frame_count": 36,"fps": 10}</sfx>')

def OnButtonItemClickCallback(self, data, touchX, touchY):
    print("---OnButtonItemClickCallback---", data, touchX, touchY)

def OnLinkItemClickCallback(self, data, touchX, touchY):
    print("---OnLinkItemClickCallback---", data, touchX, touchY)

def OnRichTextCreateFinishCallback(self):
    print("---OnRichTextCreateFinishCallback---")
使用事项
  • 富文本是python实现的一个复合控件在生成富文本后会有部分数据缓存在RichTextItem实例中因此不支持使用clone接口复制已创建完成的富文本但是clone没有调用过readRichText的富文本是可行的。
  • 我们在内部会缓存路径与RichTextItem实例的映射使用GetRichTextItem接口传入相同路径返回的RichTextItem实例也会是相同的。