界面設計本應是創意工作,卻常淪為座標計算的苦力。根因在於設計概念(高層語義)與實作語言(低層座標)間存在巨大語義鴻溝:
現有方案皆治標不治本:
我們不將設計概念「降級」為座標,而是構建一種直接表達高層布局語義的語言。設計師用代碼「寫出」布局規格,語言內部自動編譯為座標。
ComponentRectangle。Container 才能顯示。Button().title("OK").at(0,0,100,30).in(panel)Empty佔位用,不渲染任何視覺內容,僅佔據空間,實現「留白」語義。
beside(left, right, ratio)水平並排:left 佔 ratio 比例,right 佔 1-ratio。回傳新 Component(閉包性)。
above(up, down, ratio)垂直堆疊:up 佔 ratio,down 佔 1-ratio。同樣回傳 Component。
利用 Java 方法封裝組合邏輯,構建可複用的「布局詞彙」:
center(comp, hRatio, vRatio)public Component center(Component cp, float hRatio, float vRatio) {
float s1 = (1 - 2*hRatio) / (1 - hRatio);
float s2 = (1 - 2*vRatio) / (1 - vRatio);
Component u = above(Empty(), above(cp, Empty(), s2), vRatio);
return beside(Empty(), beside(u, Empty(), s1), hRatio);
}
// 使用:center(Button("OK"), 0.1f, 0.1f).at(0,0,200,50).in(panel);
h_seq / v_seqpublic Component h_seq(Component[] cps) {
if (cps.length == 1) return cps[0];
return beside(cps[0], h_seq(tail(cps)), 1.0f/cps.length);
}
// 使用:h_seq(buttons).at(0,0,400,50).in(panel);
block / block_with_marginpublic Component block(Component[] cps, int rows, int cols) {
Component[][] grid = formalize(cps, rows, cols); // 不足補 Empty
Component[] rowComps = new Component[rows];
for (int i=0; i center(cp, h, v))
.toArray(Component[]::new);
return block(wrapped, r, c);
}
Component[] keys = {
btn("0"), btn("1"), btn("2"), btn("+"),
btn("3"), btn("4"), btn("5"), btn("-"),
btn("6"), btn("7"), btn("8"), btn("*"),
btn("9"), btn("="), btn("%"), btn("/")
};
Component opLayout = block_with_margin(keys, 4, 4, 0.02f, 0.02f); // 2% 留白
above(
above( TextField(),
beside( btn("Backspace"), btn("C"), 0.5f ), 0.5f ),
opLayout, 0.3f
).at(0,0,300,400).in(frame);
修改留白只需改一行:將 block 換成 block_with_margin —— 領域變更最小,代碼變更最小,健壯性體現無遺。
at, in, beside, above)。center, h_seq, block...)。每層只依賴下層提供的原語,修改某層不影響他層。
所有 setter 回傳 this,方法命名服務於「句子流暢度」:
public class Button implements Component {
private JButton btn = new JButton();
public Component title(String t) { btn.setText(t); return this; }
public Component at(int x,int y,int w,int h) { btn.setBounds(x,y,w,h); return this; }
public Component in(Container c) { c.add(btn); return this; }
}
public class Beside implements Component {
private Component left, right; private float ratio;
public Beside(Component l, Component r, float ratio) { ... }
public Component at(int x,int y,int w,int h) {
left.at(x, y, (int)(w*ratio), h);
right.at(x + (int)(w*ratio), y, w - (int)(w*ratio), h);
return this;
}
public Component in(Container c) { left.in(c); right.in(c); return this; }
}
佈局語言僅負責「顯示」。為分離控制邏輯,引入擁有者概念:
Button().title("Submit").ownBy(submitController);
submitController 處理所有事件與狀態,佈局代碼零邏輯 —— 這是 MVP (Model-View-Presenter) 模式的自然落地。
當布局變成可編程的語言,UI 開發才真正回歸創造本質。