Java/Kotlin 代碼中動態添加 View 到 LinearLayout 時,必須使用對應容器的 LayoutParams 子類(即 LinearLayout.LayoutParams),否則 gravity、margin、weight 等屬性失效,只生效 width/height。這是新手最易踩的坑。
// ❌ 錯誤:導入 android.view.ViewGroup.LayoutParams
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER; // 無效!
linearLayout.addView(textView, lp);
// ✅ 正確:導入 android.widget.LinearLayout.LayoutParams
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
lp.gravity = Gravity.CENTER; // 生效!
linearLayout.addView(textView, lp);
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 根佈局
LinearLayout root = new LinearLayout(this);
root.setOrientation(LinearLayout.VERTICAL);
root.setLayoutParams(new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));
setContentView(root);
// 按鈕:置中
LinearLayout.LayoutParams btnParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
btnParams.gravity = Gravity.CENTER_HORIZONTAL;
Button btn = new Button(this);
btn.setText("Button");
root.addView(btn, btnParams);
// 文字:置中
LinearLayout.LayoutParams tvParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
tvParams.gravity = Gravity.CENTER_HORIZONTAL;
TextView tv = new TextView(this);
tv.setText("TextView");
root.addView(tv, tvParams);
}
}
| 容器類 | 對應 LayoutParams | 特有屬性 |
|---|---|---|
| LinearLayout | LinearLayout.LayoutParams | gravity, weight, margin* |
| RelativeLayout | RelativeLayout.LayoutParams | addRule (ALIGN_PARENT_LEFT 等), margin* |
| FrameLayout | FrameLayout.LayoutParams | gravity, margin* |
| ConstraintLayout | ConstraintLayout.LayoutParams | constraint*, bias, margin*, dimensionRatio |
| GridLayout | GridLayout.LayoutParams | rowSpec, columnSpec, gravity |
| CoordinatorLayout | CoordinatorLayout.LayoutParams | behavior, anchorId, insetEdge |
// 定義擴展
inline fun LinearLayout.addView(
view: View,
width: Int = LayoutParams.WRAP_CONTENT,
height: Int = LayoutParams.WRAP_CONTENT,
gravity: Int = Gravity.NO_GRAVITY,
margins: IntArray = intArrayOf(0,0,0,0),
weight: Float = 0f,
init: LinearLayout.LayoutParams.() -> Unit = {}
) {
val lp = LayoutParams(width, height).apply {
this.gravity = gravity
if (margins.size == 4) setMargins(margins[0], margins[1], margins[2], margins[3])
this.weight = weight
init()
}
addView(view, lp)
}
// 使用
linearLayout.addView(button) { gravity = Gravity.CENTER_HORIZONTAL }
linearLayout.addView(textView) {
gravity = Gravity.CENTER_HORIZONTAL
weight = 1f
setMargins(0, 16, 0, 0)
}
<!-- XML 自動處理 LayoutParams 類型 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
XML 由 LayoutInflater 根據父容器自動實例化正確的 LayoutParams 子類,代碼中需開發者顯式指定。
layout_weight 不生效 → 必須用 LinearLayout.LayoutParams 並設置 weight > 0,且 width=0dp (即 MATCH_PARENT 配合 weight)。layout_margin 不生效 → 同理,需正確子類。FrameLayout.LayoutParams 加入 LinearLayout → 僅 width/height 生效,gravity/margin 失效。鐵律:addView 時的 LayoutParams 類型,必須與父容器類型完全匹配。這是 Android 視圖系統「佈局參數屬於父容器」設計哲學的直接體現。