Мені потрібна точно та сама особливість, описана в цьому запитанні. Ось моє рішення та вихідний код: https://github.com/laoyang/android-dynamic-views . А ви можете переглянути демонстрацію відео тут: http://www.youtube.com/watch?v=4HeqyG6FDhQ
Макет
В основному ви маєте два файли розмітки xml:
- Горизонтальний вигляд рядка LinearLayout з a
TextEdit
, a Spinner
та anImageButton
для видалення.
- Вертикальний вигляд контейнера LinearLayout із лише кнопкою Додати нову .
Контроль
У коді Java ви будете динамічно додавати та видаляти представлення рядків у контейнер, використовуючи надуваючи, addView, RemoveView тощо. У додатку Android є деякий контроль видимості для кращої UX. Вам потрібно додати TextWatcher для перегляду EditText у кожному рядку: коли текст порожній, потрібно приховати кнопку Додати нову та кнопку видалення. У своєму коді я написав функцію void inflateEditRow(String)
помічника для всієї логіки.
Інші хитрощі
- Встановіть
android:animateLayoutChanges="true"
у xml, щоб увімкнути анімацію
- Використовуйте спеціальний прозорий фон із натиснутим селектором, щоб кнопки були візуально такими, як кнопки в додатку Android.
Вихідний код
Код основної діяльності Java (Це пояснює всю логіку, але в файлах макета xml встановлено досить багато властивостей; для повного рішення зверніться до джерела Github):
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);
}