-
Notifications
You must be signed in to change notification settings - Fork 5
Addon IPhonePage
首页 | 附属接口文档 | 下一页:IAppSource / AppInfo
把界面画在手机屏幕内部所需的三个类型。
com.november.mcphone.api.client.ui.IPhonePage 一页界面
com.november.mcphone.api.client.ui.PhoneCanvas 一帧的绘制上下文
com.november.mcphone.api.client.ui.PhoneStyle 手机当前的配色
| 项 | 值 |
|---|---|
| 端 | 仅客户端 |
| 起于 | 1.2.13 |
| 入口 |
IPhoneApp.openPage() 返回一个 IPhonePage
|
不使用本接口时,App 被点开只能 Minecraft.getInstance().setScreen(...) 整个跳出手机:状态栏、导航栏、壁纸消失,返回键须自行实现,关闭后回到何处也须自行记录。内建的聊天、记事本、相册均为手机屏幕内的一页。
由 MCphone 负责、实现方不必处理的部分:状态栏、导航栏、壁纸、手机外壳;导航栏返回键 ◁ 的默认行为(退回主屏);ESC 关机;页面切走时调用 onClose()。
| 方法 | 默认 | 说明 |
|---|---|---|
void render(PhoneCanvas canvas) |
必须实现 | 每帧调用 |
boolean mouseClicked(double mouseX, double mouseY, int button) |
false |
屏幕绝对坐标 |
boolean mouseScrolled(double mouseX, double mouseY, double amount) |
false |
同上 |
boolean keyPressed(int keyCode, int scanCode, int modifiers) |
false |
ESC 不会走到这里 |
boolean charTyped(char codePoint, int modifiers) |
false |
输入法提交的汉字与 Ctrl+V 粘贴走这里 |
boolean capturesKeyboard() |
false |
有输入框时必须返回 true
|
boolean onBack() |
false |
导航栏 ◁ |
void onOpen() |
空 | 这一页刚被打开 |
void onClose() |
空 | 这一页被切走,一定会被调到 |
只有 render 是必须实现的。 其余全为 default。按兼容承诺第一条,此后向本接口新增能力也只会新增 default 方法,实现类不会因 MCphone 升级而编译不过。
public final class CalculatorApp implements IPhoneApp {
@Override
public IPhonePage openPage() { return new CalculatorPage(); }
@Override
public void onPress() { } // 覆盖了 openPage,这里不会被调到
// getId / getDisplayName / getIconTexture 略
}
public final class CalculatorPage implements IPhonePage {
@Override
public void render(PhoneCanvas c) {
c.graphics().drawString(c.font(), "1 + 1 = 2",
c.x() + 4, c.y() + 4, c.style().bodyColor(), false);
}
}每帧调用。在 canvas.x() / y() / width() / height() 给出的矩形内绘制,状态栏与导航栏已经扣除。
⚠ 不要保存
canvas引用,它只在本次调用内有效。见坑 · PhoneCanvas 只活一帧。
坐标是屏幕绝对坐标,与 PhoneCanvas.x() 同一套。返回 true 表示已处理,不再向下传递。
⚠ 页面内的空点击应返回
true。返回false会落到 MCphone 的默认处理,而默认处理中"点手机外面 = 关机"。 见坑 · 空点击返回 false 会关机。
charTyped 接收输入法提交的字符与粘贴内容。
ESC 不会走到 keyPressed:它由 MCphone 统一处理为直接关机。该键不开放给页面拦截,也不允许页面改写其含义——玩家按了退出却什么都没发生是最糟的一种失败。退出前的收尾写在 onClose()。
声明本页是否含输入框。
| 返回 | 效果 |
|---|---|
true |
按键先给本页,不再落到原版按键判定上 |
false(默认) |
按键照常参与原版判定 |
⚠ 有输入框却不返回
true:原版背包键默认为E,玩家打拼音必然按到e,手机当场关闭、内容全丢。 ⚠ 没有输入框却返回true:背包键被吃掉,玩家无法用它关闭手机。 见坑 · capturesKeyboard 两个方向都会错。
MCphone 自身的设备命名、聊天输入、笔记编辑三处均返回 true。
玩家按下导航栏 ◁ 时调用。
| 返回 | 效果 |
|---|---|
true |
实现方自行处理(例如页面内还有一层要退),MCphone 不动 |
false(默认) |
本页到此为止,退回主屏 |
onOpen():本页刚被打开,用于拉取数据、重置状态。
onClose():本页被切走,用于释放资源与保存草稿。一定会被调用——从 ◁ 退出、按 ESC、关闭手机、断线,都会走到这里。
⚠ 收尾逻辑写在
onClose(),不是onBack()。见坑 · 收尾写在 onClose 而非 onBack。
每个回调均被兜住:本页抛出异常只会使该页被关闭并记录一条日志,不会拖垮手机界面,更不会崩溃游戏。
这是兜底,不是设计。被兜掉的异常对玩家而言就是"点开这个 App 自己弹回去了"。
一帧的绘制上下文,由 MCphone 构造并传入 render。
| 方法 | 返回 |
|---|---|
GuiGraphics graphics() |
原版绘制句柄 |
Font font() |
手机界面用字体 |
int x() |
内容区左边界(屏幕绝对坐标) |
int y() |
内容区上边界(已扣掉状态栏) |
int width() |
内容区宽度 |
int height() |
内容区高度(已扣掉状态栏与导航栏) |
int mouseX() / int mouseY()
|
鼠标位置,与上面同一套坐标 |
float partialTick() |
本帧插值系数 |
PhoneStyle style() |
手机当前配色 |
boolean hovered(int rx, int ry, int rw, int rh) |
鼠标是否在该矩形内 |
boolean hoveredContent() |
鼠标是否在整个内容区内 |
void clipped(int x, int y, int w, int h, Runnable body) |
带裁剪地绘制,见下 |
坐标是屏幕绝对坐标,可直接传给 GuiGraphics,无须再加偏移。
hovered的参数名带r是历史遗留,它收的仍是绝对坐标,不是相对内容区的偏移。
每帧新建一个,只在该帧内有效。
⚠ 不要保存它。保存下来的对象里,鼠标位置与
GuiGraphics下一帧即过期,用它绘制的后果是画在错误的位置,或对着已经关闭的渲染状态操作。
void clipped(int x, int y, int w, int h, Runnable body)在一个矩形内绘制,越界部分裁掉。用于可滚动的列表与长文本。
canvas.clipped(canvas.x(), canvas.y(), canvas.width(), canvas.height(), () -> {
int y = canvas.y() - scrollPx;
for (String line : lines) {
canvas.graphics().drawString(canvas.font(), line, canvas.x(), y, color, false);
y += canvas.font().lineHeight;
}
});| 行为 | 说明 |
|---|---|
| 坐标 | 屏幕绝对坐标,与 x() 同一套 |
| 嵌套 | 可以,内外两层取交集,与原版裁剪栈一致 |
| 矩形退化(宽或高 ≤ 0) | 什么都不画,但 body 照样执行——其中顺手做的测量不会停摆 |
body 抛异常 |
裁剪照样收回,异常继续上抛,由 MCphone 关闭该页 |
⚠ 不要自行调用
graphics().enableScissor(...)。 原版该方法收窗口坐标且不看 PoseStack,而玩家可在「设置 → 界面大小」把整个手机缩放到 75%–300%。见坑 · 裁剪必须走 clipped。
本方法只提供作用域写法、没有配对的 enable / disable,是刻意的:裁剪是全局状态,enable 之后未能走到 disable,该帧其余全部内容都会被切在那个框里。
玩家可把整个手机缩放到 75%–300%。页面无须为此做任何改动:缩放是渲染时套的一层 pose,PhoneCanvas 给出的 x / y / 宽高与送入 mouseClicked / mouseScrolled 的鼠标坐标位于同一套未缩放坐标系中,两边一起换算过了。
两种写法会出错:
- 自行从
Minecraft.getInstance().mouseHandler取鼠标位置 —— 那是屏幕原始坐标,未经换算。 - 自行调用
enableScissor—— 见上。
手机当前的配色。全部为 ARGB(0xAARRGGBB),可直接传给 fill 与 drawString。
| 方法 | 用途 |
|---|---|
int titleColor() |
标题、当前选中项。最亮的一档 |
int bodyColor() |
正文。绝大多数文字 |
int subtleColor() |
次要信息:说明、时间戳、占位提示 |
int accentColor() |
强调色:价格、数字、需要一眼看到的东西 |
int screenBackground() |
屏幕底色。整页铺底时用它 |
int pressedOverlay() |
悬停或按下时垫在下面的半透明层 |
int buttonColor() |
可点按钮底色 |
int buttonHoverColor() |
按钮悬停底色 |
int buttonDisabledColor() |
点不动的按钮底色 |
int buttonDisabledTextColor() |
点不动的按钮上的文字颜色 |
为什么是接口而不是一组
public static final int:常量会被编译器内联进调用方的 class 文件。附属编译时的配色会被固定下来,MCphone 之后更换配色,附属拿到的仍是编译当天的值,且没有任何迹象表明何处不对。接口是一次真实调用,永远拿到当下的值,也为将来的主题切换留了门。
首页 | 附属接口文档 | 下一页:IAppSource / AppInfo