使用者點擊「新增」按鈕動態建立 Button,每個 Button 有獨立 ID;點擊任一動態 Button 可將其移除。
public class DynamicButtonActivity extends AppCompatActivity {
private RelativeLayout container;
private EditText inputEditText;
private Button addBtn;
private int nextId = 1000; // 起始 ID,避免與靜態視圖衝突
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dynamic_button);
container = findViewById(R.id.button_container);
inputEditText = findViewById(R.id.input_edittext);
addBtn = findViewById(R.id.add_btn);
addBtn.setOnClickListener(v -> addButton());
}
private void addButton() {
String text = inputEditText.getText().toString().trim();
if (text.isEmpty()) return;
Button btn = new Button(this);
btn.setId(View.generateViewId()); // API 17+ 自動產生唯一 ID
btn.setText(text);
btn.setTextColor(Color.WHITE);
btn.setTextSize(14);
btn.setBackgroundResource(R.drawable.custom_button);
// 佈局參數:RelativeLayout 需設定規則
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT
);
// 簡單排版:換行排列(實際可用 FlowLayout/FlexboxLayout)
int childCount = container.getChildCount();
if (childCount > 0) {
View lastChild = container.getChildAt(childCount - 1);
params.addRule(RelativeLayout.BELOW, lastChild.getId());
params.addRule(RelativeLayout.ALIGN_LEFT, lastChild.getId());
params.topMargin = 16;
} else {
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
}
params.leftMargin = 16;
btn.setLayoutParams(params);
// 點擊移除自身
btn.setOnClickListener(v -> {
// v 就是被點擊的 Button,直接從父容器移除
ViewGroup parent = (ViewGroup) v.getParent();
if (parent != null) {
parent.removeView(v);
}
});
// 長按可編輯/複製等進階操作
btn.setOnLongClickListener(v -> {
// 顯示選單...
return true;
});
container.addView(btn);
inputEditText.setText("");
}
}
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="@+id/input_area">
<EditText
android:id="@+id/input_edittext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="輸入按鈕文字" />
<Button
android:id="@+id/add_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="新增" />
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/input_area">
<RelativeLayout
android:id="@+id/button_container"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
</RelativeLayout>
// 在 OnClickListener 中
btn.setOnClickListener(v -> {
ViewGroup parent = (ViewGroup) v.getParent(); // 取得父容器
if (parent != null) {
parent.removeView(v); // 直接移除自己
}
});
findViewByIdv 參數就是被點擊的視圖getParent() 返回持有該視圖的 ViewGroup
btn.setId(View.generateViewId()); // API 17+ (Android 4.2+)
nextId++ 避免溢位或衝突
// 新增時
btn.setTag(new ButtonData(itemId, itemName, createTime));
// 移除時取得業務資料
btn.setOnClickListener(v -> {
ButtonData data = (ButtonData) v.getTag();
// 執行刪除 API、資料庫操作等
deleteItem(data.itemId);
((ViewGroup) v.getParent()).removeView(v);
});
添加依賴:implementation 'com.google.android.flexbox:flexbox:3.0.0'
<com.google.android.flexbox.FlexboxLayout
android:id="@+id/button_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
app:flexWrap="wrap"
app:alignItems="flex_start"
app:justifyContent="flex_start">
</com.google.android.flexbox.FlexboxLayout>
新增 Button 時無需手動計算位置:
FlexboxLayout.LayoutParams params = new FlexboxLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
params.setMargins(8, 8, 8, 8);
btn.setLayoutParams(params);
container.addView(btn);
@Override
protected void onDestroy() {
super.onDestroy();
// 移除所有動態視圖的監聽器(雖然 removeView 會自動處理,但明確清理更安全)
for (int i = 0; i < container.getChildCount(); i++) {
View child = container.getChildAt(i);
child.setOnClickListener(null);
child.setOnLongClickListener(null);
}
container.removeAllViews();
}
動態 Button 管理核心三點:
new Button(context) → 設定屬性 → container.addView()v.getParent().removeView(v)(在點擊監聽器中)View.generateViewId() + setTag()/getTag()建議使用 FlexboxLayout 替代 RelativeLayout 獲得自動換行、自適應排版,減少手動計算錯誤。