Tôi cần chính xác cùng một tính năng được mô tả trong câu hỏi này. Đây là giải pháp và mã nguồn của tôi: https://github.com/laoyang/android-dynamic-view . Và bạn có thể xem bản demo video hoạt động tại đây: http://www.youtube.com/watch?v=4HeqyG6FDhQ
Bố trí
Về cơ bản, bạn sẽ có hai tệp bố cục xml:
- Chế độ xem hàng tuyến tính ngang dọc với a
TextEdit
, a Spinner
và ImageButton
xóa.
- Một khung nhìn container dọcLayout dọc chỉ với một nút Thêm mới .
Điều khiển
Trong mã Java, bạn sẽ tự động thêm và xóa các chế độ xem hàng vào vùng chứa, sử dụng lạm phát, addView, removeView, v.v. Có một số điều khiển khả năng hiển thị cho UX tốt hơn trong ứng dụng Android gốc. Bạn cần thêm Trình xem văn bản cho chế độ xem Chỉnh sửa trong mỗi hàng: khi văn bản trống, bạn cần ẩn nút Thêm mới và nút xóa. Trong mã của tôi, tôi đã viết một void inflateEditRow(String)
hàm trợ giúp cho tất cả logic.
Thủ đoạn khác
- Đặt
android:animateLayoutChanges="true"
trong xml để bật hình động
- Sử dụng nền trong suốt tùy chỉnh với bộ chọn nhấn để làm cho các nút trực quan giống như các nút trong ứng dụng Android gốc.
Mã nguồn
Mã Java của hoạt động chính (Điều này giải thích tất cả logic, nhưng khá nhiều thuộc tính được đặt trong các tệp bố cục xml, vui lòng tham khảo nguồn Github để biết giải pháp hoàn chỉnh):
public class MainActivity extends Activity {
// Parent view for all rows and the add button.
private LinearLayout mContainerView;
// The "Add new" button
private Button mAddButton;
// There always should be only one empty row, other empty rows will
// be removed.
private View mExclusiveEmptyView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.row_container);
mContainerView = (LinearLayout) findViewById(R.id.parentView);
mAddButton = (Button) findViewById(R.id.btnAddNewItem);
// Add some examples
inflateEditRow("Xiaochao");
inflateEditRow("Yang");
}
// onClick handler for the "Add new" button;
public void onAddNewClicked(View v) {
// Inflate a new row and hide the button self.
inflateEditRow(null);
v.setVisibility(View.GONE);
}
// onClick handler for the "X" button of each row
public void onDeleteClicked(View v) {
// remove the row by calling the getParent on button
mContainerView.removeView((View) v.getParent());
}
// Helper for inflating a row
private void inflateEditRow(String name) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View rowView = inflater.inflate(R.layout.row, null);
final ImageButton deleteButton = (ImageButton) rowView
.findViewById(R.id.buttonDelete);
final EditText editText = (EditText) rowView
.findViewById(R.id.editText);
if (name != null && !name.isEmpty()) {
editText.setText(name);
} else {
mExclusiveEmptyView = rowView;
deleteButton.setVisibility(View.INVISIBLE);
}
// A TextWatcher to control the visibility of the "Add new" button and
// handle the exclusive empty view.
editText.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
// Some visibility logic control here:
if (s.toString().isEmpty()) {
mAddButton.setVisibility(View.GONE);
deleteButton.setVisibility(View.INVISIBLE);
if (mExclusiveEmptyView != null
&& mExclusiveEmptyView != rowView) {
mContainerView.removeView(mExclusiveEmptyView);
}
mExclusiveEmptyView = rowView;
} else {
if (mExclusiveEmptyView == rowView) {
mExclusiveEmptyView = null;
}
mAddButton.setVisibility(View.VISIBLE);
deleteButton.setVisibility(View.VISIBLE);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
});
// Inflate at the end of all rows but before the "Add new" button
mContainerView.addView(rowView, mContainerView.getChildCount() - 1);
}