Necesito exactamente la misma característica descrita en esta pregunta. Aquí está mi solución y código fuente: https://github.com/laoyang/android-dynamic-views . Y puede ver la demostración de video en acción aquí: http://www.youtube.com/watch?v=4HeqyG6FDhQ
Diseño
Básicamente tendrás dos archivos de diseño xml:
- A LinearLayout horizontal vista fila con un
TextEdit
, una Spinner
y una ImageButton
para su eliminación.
- Una vista de contenedor LinearLayout vertical con solo un botón Agregar nuevo .
Controlar
En el código Java, agregará y eliminará vistas de fila en el contenedor dinámicamente, utilizando inflar, agregarVista, eliminarVista, etc. Hay algunos controles de visibilidad para una mejor experiencia de usuario en la aplicación de Android. Debe agregar un TextWatcher para la vista EditText en cada fila: cuando el texto está vacío, debe ocultar el botón Agregar nuevo y el botón Eliminar. En mi código, escribí una void inflateEditRow(String)
función auxiliar para toda la lógica.
Otros trucos
- Establecer
android:animateLayoutChanges="true"
en xml para habilitar la animación
- Use un fondo transparente personalizado con el selector presionado para hacer que los botones sean visualmente iguales a los de la aplicación de Android.
Código fuente
El código de Java de la actividad principal (esto explica toda la lógica, pero se establecen bastantes propiedades en los archivos de diseño xml, consulte la fuente de Github para obtener una solución completa):
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);
}