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 en MainActivity.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 a extends en Java).
  • AppCompatActivity() → Clase base que da a nuestra app funciones de actividad.

Variables globales

private var operacionActual = ""
private var primerNumero: Double = Double.NaN

  • private → 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: DecimalFormat

  • lateinit → Inicialización diferida (se asigna después en onCreate).
  • 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.
  • Bundle es 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 (View a Button).
  • when → Condicional múltiple, similar a switch.

Función calcular

fun calcular() {
    if (operandoCalculadora.text.isEmpty()) return
    val valor = operandoCalculadora.text.toString().toDoubleOrNull() ?: return

  • if → Condicional básico.
  • toDoubleOrNull() → Convierte texto a número o devuelve null.
  • ?: (operador Elvis) → Si es null, 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 (evita NullPointerException).
  • ?: → operador Elvis (valor alternativo).
  • ! → negación lógica.

Clases y objetos:

  • AppCompatActivity es una clase base.
  • MainActivity hereda de ella.
  • Uso de as para casting de tipos (ViewButton).

Strings y números:

  • .toString() convierte a texto.
  • .toDoubleOrNull() convierte texto a número.
  • DecimalFormat → formatea números.