Android动态布局增删问题求助:删错行、数据存储与数量限制
Hey there! Let's work through your three main issues step by step. I'll provide updated code and explain each change so you understand why it works.
1. Fixing the Wrong Row Deletion Problem
The root cause here is that you were using findViewById(R.id.button2) directly in the Add click listener, which always grabs the first Delete button in your layout instead of the one belonging to the newly inflated row. You need to find the Delete button within the specific row view you just created.
Here's the corrected code snippet for the Add button click listener, plus a helper method to keep row numbers accurate:
add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Check max row limit first (covered in point 3) if (data.getChildCount() >= 20) { Toast.makeText(MainActivity.this, "Maximum 20 rows allowed", Toast.LENGTH_SHORT).show(); return; } try { LayoutInflater li = LayoutInflater.from(MainActivity.this); final View view = li.inflate(R.layout.tryandtest, data, false); // Attach to parent properly data.addView(view); // Set spinner adapter for this row Spinner s = view.findViewById(R.id.spinner); s.setAdapter(adapter2); // Find Delete button INSIDE the current row view Button delete = view.findViewById(R.id.button2); delete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Check min row limit before deleting if (data.getChildCount() <= 1) { Toast.makeText(MainActivity.this, "At least 1 row must remain", Toast.LENGTH_SHORT).show(); return; } data.removeView(view); // Update row numbers after deletion updateRowNumbers(data); } }); // Update row numbers after adding a new row updateRowNumbers(data); } catch (Exception e) { e.printStackTrace(); Log.d("inflate exception", e.toString()); } } });
Helper method to keep row labels (like "1", "2") up-to-date:
private void updateRowNumbers(LinearLayout parentLayout) { for (int i = 0; i < parentLayout.getChildCount(); i++) { View row = parentLayout.getChildAt(i); TextView rowNumber = row.findViewById(R.id.textView); rowNumber.setText(String.valueOf(i + 1)); } }
2. Saving All Group IDs to ArrayList on Start Button Click
First, add a Start button to your UI XML if you haven't already:
<Button android:id="@+id/button_start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start" android:layout_gravity="center_horizontal"/>
Then, set up the click listener to collect all selected Group IDs:
Button startBtn = findViewById(R.id.button_start); startBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ArrayList<String> groupIdsList = new ArrayList<>(); LinearLayout dataLayout = findViewById(R.id.leanierLayout_test); for (int i = 0; i < dataLayout.getChildCount(); i++) { View row = dataLayout.getChildAt(i); Spinner spinner = row.findViewById(R.id.spinner); String selectedGroupId = spinner.getSelectedItem().toString(); groupIdsList.add(selectedGroupId); } // Use the list as needed (example: log or show toast) Log.d("Group IDs", "Saved IDs: " + groupIdsList.toString()); Toast.makeText(MainActivity.this, "Saved " + groupIdsList.size() + " group IDs", Toast.LENGTH_SHORT).show(); } });
3. Implementing Add/Delete Limits
We already added these checks in the code above, but let's recap:
- Max 20 rows: Before inflating a new row, check
data.getChildCount() >= 20and show a toast if true. - Min 1 row: Before deleting a row, check
data.getChildCount() <= 1and show a toast if true.
These checks prevent users from exceeding your row limits and ensure you never end up with zero rows.
Full Updated onCreate Method
Here's the complete onCreate method with all fixes included:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ap_auto_start_test); // Assuming groupId is your existing list of spinner options ArrayAdapter<String> adapter2 = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, groupId); adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); Button add = findViewById(R.id.button1); final LinearLayout data = findViewById(R.id.leanierLayout_test); // Add initial row (since we need at least 1 row) addInitialRow(data, adapter2); add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (data.getChildCount() >= 20) { Toast.makeText(MainActivity.this, "Maximum 20 rows allowed", Toast.LENGTH_SHORT).show(); return; } try { LayoutInflater li = LayoutInflater.from(MainActivity.this); final View view = li.inflate(R.layout.tryandtest, data, false); data.addView(view); Spinner s = view.findViewById(R.id.spinner); s.setAdapter(adapter2); Button delete = view.findViewById(R.id.button2); delete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (data.getChildCount() <= 1) { Toast.makeText(MainActivity.this, "At least 1 row must remain", Toast.LENGTH_SHORT).show(); return; } data.removeView(view); updateRowNumbers(data); } }); updateRowNumbers(data); } catch (Exception e) { e.printStackTrace(); Log.d("inflate exception", e.toString()); } } }); Button startBtn = findViewById(R.id.button_start); startBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ArrayList<String> groupIdsList = new ArrayList<>(); for (int i = 0; i < data.getChildCount(); i++) { View row = data.getChildAt(i); Spinner spinner = row.findViewById(R.id.spinner); groupIdsList.add(spinner.getSelectedItem().toString()); } Log.d("Group IDs", "Saved: " + groupIdsList); Toast.makeText(MainActivity.this, "Saved " + groupIdsList.size() + " entries", Toast.LENGTH_SHORT).show(); } }); } private void addInitialRow(LinearLayout parent, ArrayAdapter<String> adapter) { LayoutInflater li = LayoutInflater.from(this); View view = li.inflate(R.layout.tryandtest, parent, false); parent.addView(view); Spinner s = view.findViewById(R.id.spinner); s.setAdapter(adapter); Button delete = view.findViewById(R.id.button2); delete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (parent.getChildCount() <= 1) { Toast.makeText(MainActivity.this, "At least 1 row must remain", Toast.LENGTH_SHORT).show(); return; } parent.removeView(view); updateRowNumbers(parent); } }); updateRowNumbers(parent); } private void updateRowNumbers(LinearLayout parentLayout) { for (int i = 0; i < parentLayout.getChildCount(); i++) { View row = parentLayout.getChildAt(i); TextView rowNumber = row.findViewById(R.id.textView); rowNumber.setText(String.valueOf(i + 1)); } }
A few extra notes:
- I changed
getApplicationContext()toMainActivity.thisin the LayoutInflater to avoid potential context issues. - Added
addInitialRowto ensure your layout starts with at least one row (since we can't delete all rows). - Used
li.inflate(R.layout.tryandtest, data, false)instead ofnullto properly attach the row to the parent layout while avoiding immediate layout passes.
内容的提问来源于stack exchange,提问作者Shubham Chander

