Construcción de la clásica “calculadora” en Android Studio y Kotlin

En este laboratorio vamos a construir la clásica calculadora básica usando Android Studio y Kotlin
1. AndroidManifest.xml
Este archivo es como el “acta de nacimiento” de tu aplicación. Android lo usa para saber qué contiene tu app.
Código relevante
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.Calculadora">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
Conceptos importantes:
application→ Contenedor principal de tu app.android:icon→ Icono en el celular.android:label→ Nombre que aparece bajo el icono.android:theme→ Estilo visual global.activity→ Representa una pantalla. Aquí solo tenemos MainActivity.intent-filter→ Define cómo se abre la app:MAIN→ Actividad principal.LAUNCHER→ Aparece en el menú del dispositivo.
2. vista_principal.xml
Este archivo define la interfaz gráfica. Android usa XML para estructurar cómo se verá la pantalla.
Contenedor
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">ConstraintLayout→ Permite organizar vistas con restricciones.match_parent→ El elemento ocupa todo el espacio disponible.
TextView de entrada y resultado
<TextView
android:id="@+id/operandoCalculadora"
android:textSize="48sp"/>
<TextView
android:id="@+id/resultadoCalculadora"
android:textSize="60sp"/>TextView→ Texto que se muestra en pantalla.id→ Identificador único para enlazarlo con Kotlin (findViewById).sp→ Unidad recomendada para texto (escala con accesibilidad).
Teclado con GridLayout
<GridLayout
android:columnCount="4">GridLayout→ Organiza los botones en una cuadrícula 4×4.
Ejemplo de botón:
<com.google.android.material.button.MaterialButton
android:text="7"
android:onClick="seleccionarNumero"
app:backgroundTint="#FF3D00"
app:cornerRadius="40dp"/>Propiedades clave:
text→ El número u operador que muestra el botón.onClick→ Llama a un método enMainActivity.kt.backgroundTint→ Color de fondo.cornerRadius→ Bordes redondeados.
El atributo onClick="seleccionarNumero" conecta el botón con la función Kotlin seleccionarNumero().
3. MainActivity.kt
Este es el cerebro de la app. Aquí controlamos cómo responden los botones.
Encabezado
class MainActivity : AppCompatActivity() {class→ Declara una clase.MainActivity→ Nombre de nuestra pantalla principal.:→ Herencia en Kotlin (similar aextendsen Java).AppCompatActivity()→ Clase base que da a nuestra app funciones de actividad.
Variables globales
private var operacionActual = ""
private var primerNumero: Double = Double.NaNprivate→ Solo accesible dentro de esta clase.var→ Variable mutable (puede cambiar).Double.NaN→ “Not a Number”, indica que aún no hay número válido.
private lateinit var operandoCalculadora: TextView
private lateinit var resultadoCalculadora: TextView
private lateinit var formatoDecimal: DecimalFormatlateinit→ Inicialización diferida (se asigna después enonCreate).TextView→ Referencia a la vista XML.DecimalFormat→ Sirve para dar formato a los resultados.
Método onCreate
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.vista_principal)override→ Sobrescribe un método de la clase padre.onCreate→ Se ejecuta al iniciar la actividad.setContentView→ Vincula el XML con el código Kotlin.
Guardar estado
override fun onSaveInstanceState(outState: Bundle) {
outState.putDouble("primerNumero", primerNumero)
}- Guarda datos si se gira la pantalla.
Bundlees como un diccionario (clave–valor).
Función auxiliar
private fun tienePrimerNumero() = !primerNumero.isNaN()- fun → Declara una función.
- = → Función de una sola expresión.
- Devuelve true si ya hay un número válido.
Función cambiarOperador
fun cambiarOperador(v: View) {
val boton = v as Button
calcular()
operacionActual = when (boton.text.toString().trim()) {
"X" -> "*"
"÷" -> "/"
else -> boton.text.toString().trim()
}
}val→ Variable inmutable (no cambia después de asignarse).as→ Conversión de tipo (ViewaButton).when→ Condicional múltiple, similar aswitch.
Función calcular
fun calcular() {
if (operandoCalculadora.text.isEmpty()) return
val valor = operandoCalculadora.text.toString().toDoubleOrNull() ?: returnif→ Condicional básico.toDoubleOrNull()→ Convierte texto a número o devuelvenull.?:(operador Elvis) → Si esnull, retorna inmediatamente.
if (operacionActual == "/" && valor == 0.0) {
resultadoCalculadora.text = "Error"
return
}- Manejo de división por cero.
Función seleccionarNumero
fun seleccionarNumero(v: View) {
val texto = (v as Button).text.toString()
operandoCalculadora.text = operandoCalculadora.text.toString() + texto
}- Concatenación de texto en Kotlin con
+.
Función igual
fun igual(v: View) {
calcular()
if (!primerNumero.isNaN()) {
resultadoCalculadora.text = formatoDecimal.format(primerNumero)
}
operacionActual = ""
}!→ Negación lógica (NOT).- Muestra el resultado en formato decimal.
Función borrar
fun borrar(v: View) {
val etiqueta = (v as Button).text.toString().trim()
if (etiqueta == "C") {
val s = operandoCalculadora.text.toString()
if (s.isNotEmpty()) {
operandoCalculadora.text = s.dropLast(1)
} else {
primerNumero = Double.NaN
operacionActual = ""
resultadoCalculadora.text = ""
}
} else if (etiqueta == "CA") {
primerNumero = Double.NaN
operacionActual = ""
operandoCalculadora.text = ""
resultadoCalculadora.text = ""
}
}isNotEmpty()→ Comprueba si el texto no está vacío.dropLast(1)→ Quita el último carácter.
Conceptos de Kotlin aplicados en este proyecto
Variables:
val→ inmutable.var→ mutable.lateinit→ inicialización diferida.
Funciones:
fun nombre()→ define una función.override→ sobrescribir funciones de clases padres.- Funciones de una sola línea con
=.
Condicionales:
if/else.when(switch mejorado).
Operadores útiles:
?.→ llamada segura (evitaNullPointerException).?:→ operador Elvis (valor alternativo).!→ negación lógica.
Clases y objetos:
AppCompatActivityes una clase base.MainActivityhereda de ella.- Uso de
aspara casting de tipos (View→Button).
Strings y números:
.toString()convierte a texto..toDoubleOrNull()convierte texto a número.DecimalFormat→ formatea números.
