En la primera parte de este artículo terminamos de explicar un poquillo por encima las activities y los layouts y terminamos de maquetar nuestra primera pantalla. Ahora es el momento de conectar dicha interfaz con nuestra clase.
Conectando la vista al código
Lo primero que haremos será referencias nuestros componentes (en este caso el editText y el botón) en el código. Para ello, Kotlin lo hace de un modo muy sencillo, simplemente tenemos que usar la id que le asignamos a cada uno de los componentes en el capítulo anterior.
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) btnChangeActivity.setOnClickListener { checkValue() } } fun checkValue(){ if(etName.text.toString().isEmpty()){ Toast.makeText(this, "El nombre no puede estar vacío", Toast.LENGTH_SHORT).show() }else{ //Iremos a otra pantalla } }
Lo primero que hemos hecho ha sido llamar al botón, y diciéndole que cuando se produzca el evento del pulsado sobre él que lance el método checkValue(). Esto lo hemos hecho con la función setOnClickListener que es el encargado de estar «escuchando» hasta que el botón haya sido pulsado.
El método checkValue() será el encargado de comprobar si el campo nombre está vacío. Si lo está, lanzará un toast diciendo que no debe estar vació, sino iremos a la nueva pantalla, pasándole el nombre, pero primero crearemos dicha pantalla.
Generando nuestra segunda activity
Ahora vamos a generar una segunda pantalla que será la que se abrirá cuando hayamos escrito un nombre. Podríamos hacerlo en la misma pantalla, pero quiero hablaros de como pasar información entre activities así que manos a la obra.
Para ello vamos a la ruta app/nombreDelPaquete/ y hacemos click derecho sobre él. New/Activity/Empty Activity.
Nos saldrá una pantalla igual a la imagen y la dejaremos así, le hemos cambiado el nombre, tenemos marcado que nos genere el layout y seleccionando el lenguaje Kotlin. Pulsamos en Finish.
Una vez creada vamos a empezar maquetando la pantalla. Esta será muy sencilla para no alargar mucho la entrada.
Lo primero que vamos a hacer será cambiar el ConstrantLayout por un RelativeLayout como hicimos con la otra vista, le pondremos un fondo y en el centro habrá un texto dándonos la bienvenida. En la parte inferior un botón para volver a la otra pantalla.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.cursokotlin.helloworld.ShowNameActivity" android:background="@color/dark_blue"> <TextView android:id="@+id/tvGreeting" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/white" android:text="@string/welcome" android:layout_centerInParent="true" android:textSize="30sp"/> <Button android:id="@+id/btnBack" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/back" android:layout_centerHorizontal="true" android:layout_alignParentBottom="true"/> </RelativeLayout>
Aunque sea muy sencillo, he añadido algunas cositas que quiero comentar. Para empezar, el padre tiene un atributo android:background=»@Color/dark_blue» que si lo ponéis os va a dar error. Eso se debe a que el color «dark_blue» lo he creado en el archivo colors, y será lo que tengáis que hacer ahora, porque aunque se pueda meter el color ahí directamente (en código hexadecimal) lo correcto es hacerlo en dicho fichero por si un día tenemos que cambiar el color base de una app no tengamos que hacerlo en cada una de las pantallas, sino cambiando solo el color desde ahí. Así que vamos a app/res/values/colors y añadimos los dos colores que he creado.
<color name="dark_blue">#dc3157ff</color> <color name="white">#ffffff</color>
Para poder cambiar el color solo hay que cambiar el código hexadecimal, la forma más fácil es haciendo click en el cuadradito del lateral izquierdo que contiene cada recurso, y desde ahí seleccionar el nuevo color.
Y al igual que ha pasado con los colores los textos están referenciados en el archivo String, de esto hablaremos más adelante, pero voy a explicar lo básico.
Vamos a app/res/values/strings.xml y tendremos que añadir cada uno de los textos que usemos con una etiqueta que será la referencia. Quedaría así.
<string name="welcome">welcome %s</string> <string name="back">volver</string>
Os estaréis preguntando que significa el %s que hay en la string «welcome». Ese parámetro vale para que Android entienda que el %s será sustituido por un texto que todavía desconocemos. Así que cuando estemos en la segunda pantalla y se esté creando la vista, se lo tenemos que pasar.
Comunicación entre pantallas
Ahora volvamos a la clase MainActivity.kt
En el método checkValue(), en la condición else, iremos a nuestra nueva actividad y para ello usaremos un Intent. Un Intent es un objeto que contiene instrucciones con las cuales android se comunica.
fun checkValue(){ if(etName.text.toString().isEmpty()){ Toast.makeText(this, "El nombre no puede estar vacío", Toast.LENGTH_SHORT).show() }else{ val intent = Intent(this, ShowNameActivity::class.java) intent.putExtra("name", etName.text.toString()) startActivity(intent) } }
Vamos a explicar un poquito más a fondo que hemos
val intent = Intent(this, ShowNameActivity::class.java)
Aquí creamos el intent, le tenemos que pasar el contexto (this) y luego la pantalla a la que queremos ir, en este caso ShowNameActivity.
intent.putExtra("name", etName.text.toString())
El intent tiene la posibilidad de añadirle «extras», que no son más que datos para recuperar en otra parte de la aplicación. Para poder recuperarlos hay que ponerles una clave a dichos datos. En este caso estoy pasando el nombre que el usuario escribió ( etName.text.toString() ) y lo estoy pasando con la clave name. con esto hacemos que cuando llegue el intent a la otra pantalla, solo tenga que buscar si hay algún valor con la clave name, y nos devolverá el nombre.
Para finalizar llamamos a la función starActivity(intent) que nos lanzará la actividad declarada en el intent que le pasamos.
Recuperando valores del intent
Ya tenemos casi acabada nuestra aplicación, ahora debemos ir a ShowNameActivity.kt, recuperar el nombre y pintarlo.
class ShowNameActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_show_name) getAndShowName() btnBack.setOnClickListener { onBackPressed() } } fun getAndShowName(){ val bundle = intent.extras val name = bundle.get("name") tvGreeting.text = getString(R.string.welcome, name) } }
Cuando se lanza esta actividad hará dos cosas, la primera será llamar al método que hemos creado getAndshowName() que sacará del bundle (un objeto dentro del intent donde almacena la información) el nombre a través de la clave «name«.
Ahora que tenemos el nombre, accedemos al TextView y le ponemos el texto que deseamos, en este caso, como es una String necesitaremos la función getString(R.string.nombreDeNuestraString) y recordad que tenía el %s por lo que añadimos una coma y el valor por el que queremos sustituirlo, en este caso el nombre.
Para finalizar al botón le hemos añadido otro listener que ejecutará la función onBackPresses() cuando se pulse, que lo que hace es volver a la actividad anterior.
Ahora basta con ir a run/run ‘app’ para lanzar nuestra aplicación. Nos saldrá una imagen similar a esta, donde podremos seleccionar un emulador (trae alguno por defecto, sino lo crearemos) o algún móvil si lo tenemos configurado y conectado.
Seleccionamos el que queremos y ya tendremos nuestra primera aplicación lista.
Continúa con el curso: Capítulo 14 – Data classes en Kotlin
Hola! intento usar la funcion checkValue pero kotlin no la reconoce, cual seria la otra manera de validar que mis editText no esten vacios?
La función checkValue no la reconoce porque la tenemos que crear nosotros. Si te fijas en el código anterior está hecha.
fun checkValue(){
if(etName.text.toString().isEmpty()){
Toast.makeText(this, «El nombre no puede estar vacío», Toast.LENGTH_SHORT).show()
}else{
val intent = Intent(this, ShowNameActivity::class.java)
intent.putExtra(«name», etName.text.toString())
startActivity(intent)
}
}
Como haria para que en lugar de tener un boton «Volver» este Activity tenga un contador interno que a los «x» segundos regrese automaticamente a la pantalla anterior?
Buenas, sería tan sencillo como crear una variable del objeto countDownTimer
var countdown = object: CountDownTimer(1000, 100) {
override fun onTick(l: Long) {
}
override fun onFinish() {
finish()
}
}
Donde 1000 son los milisegundos para que pase por el método onFinish() y 100 son los milisegundos que tardará cada vez en pasar por el método onTick().
Eso irá en la parte superior junto a las variables (fíjate que dentro del onFinish está puesto que se cierre la activity).
Para terminar en la función onCreate de dicha activity solo tenemos que llamar a la variable e inicializarla.
countdown.start()
Saludos
Hola Aris, llevo un buen rato intentando, si éxito, utilizar el código para iniciar una nueva Activity pero desde una nueva clase, no desde la principal.
El editor me marca un error en el comando Intent y startActivity.
package com.example.pablo.myapplication
import android.content.Intent
class justaclass {
fun Start_Activity() {
val intent = Intent(this, Main2Activity::class.java)
startActivity(intent)
}
}
Tengo entendido que se debe a que mi clase no implementa un contexto ¿a que se refiere?
Gracias por tu tiempo!
Buenos días! Parece que lo que has creado es una clase y no una activity. Recuerda que una activity después del nombre de la clase extiende de AppCompatActivity así que deberías cambiar «class justaclass {» por «class justaclass : AppCompatActivity(){»
Y recuerda que tendrás que meter el método onCreate.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
Saludos
Muchas Gracias ARIS, mejor que Stack Overflow!
Saludos!
hola,
puedes detallar todo el programa completo del activity main y activity show name?
me da error al darle al run.
Muchas gracias.
Buenas compi, puedes poner el error?
El error a aparecido al generar la activity.show.name.xml
AAPT2 error: check logs for details
con la activiry.main.xml sola, funciona perfectamente.
Necesito ver el error del log compi!
Hola, buenos dias excelente tutorial, presento la version de Android studio 3.0.1 amigo tengo errores que me arroja el MainActivity.kt
package com.example.leon.primera
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun checkValue(){
if(etName.text.toString().isEmpty()){
Toast.makeText(this, «El nombre no puede estar vacío», Toast.LENGTH_SHORT).show()
}else{
val intent = Intent(this, ShowNameActivity::class.java)
intent.putExtra(«name», etName.text.toString())
startActivity(intent)
}
}
}
me coloca en rojo el etName diciendo Unresolved reference: etName
Toast Unresolved reference: Toast y en Intent igual Unresolved reference: Intent
Verifique y tengo bien declarado el etName.
PD: soy absolutamente nuevo en esto amigo, gracias si puede ayudarme y de nuevo excelente material de aprendizaje
Buenas, tienes que importar las dependencias, para ello porte encima de las palabras en rojo, e importa su dependencia (alt+intro o cmd+intro dependiendo de tu sistema operativo).
Saludos!
Hola Aris.
En mi caso me sale en rojo, pero no me da la opción de importar. Sin embargo en tu video alcanzo a ver que importa «import kotlinx.android.synthetic.main_activity.*» pero no me reconoce el Id del boton ni del Edit Text, que podría ser? En el MainActivity.kt no me reconoce ningun elemento del activity_main.xml
Agradezco tu ayuda
package com.migueagelo87.twoactivitiestutorial
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.* //Este lo vi en tu video
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnMostrarNombre.setOnClickListener {} //Esto está en rojo, no me reconcoe es ID
}
}
Muchas gracias por tomarte tu tiempo y realizar estos tutoriales. Tengo años programando en android y me decidi aprender kotlin para dar el salto y tus tutoriales son los mejores que he visto hasta ahora. Gracias
Hola, excelente tutorial, quiero empezar mi primera app nativa con Kotlin, tengo la ultima versión de androd studio (v3.1), mi pregunta muy de novatos es la siguiente.
– Cree un nuevo proyecto con una actividad vacia
Al nuevo proyecto agregue 3 actividades: Tabbed Activity, Navigation Drawer Activity, Botton Navigation Activity
Mi pregunta es como hago para que aparezcan en la pantalla del proyecto o actividad principal estas 3 nuevas actividades?
Muchas gracias por la gran ayuda.
Buenas, dado que eso no es de este capítulo (todavía no hemos llegado) no puedo detallarlo en un solo comentario.
Un saludo
Hola, Aris. Ojalá me puedas dar una respuesta a mi problema (estoy comenzando con Kotlin). Necesito abrir un archivo de texto y usar su contenido para rellenar un array, pero Android Studio (modo emulador, Linux) no parece encontrar el archivo («No such file or directory»):
1) no importa en dónde lo ponga
2) no importa si uso toda la ruta (path) o sólo el nombre del archivo
3) no importa qué metodo use (inputStream, BufferedReader, etc.)
3) no importa qué código de ejemplo haya encontrado en Internet
Te agradeceré enormemente tu colaboración.
Buenas, sin ver el código fuente me es imposible determinar el fallo, pero el fichero al que quieres acceder debería estar en la carpeta assets del proyecto.
Un saludo.
Saludos, si quisiera pasar una clase como lo haría ?
Buenas, a que te refieres con pasar una clase? Porque creo que tienes un concepto equivocado 🙂
muchas gracias por compartir tus conocimientos, acabo de terminar mi primera aplicación en android y se siente muy bien
hola! felicidades por tu trabajo….
en el parrafo «Conectando la vista al código» ese código va en la Mainactivity.kt.. es así? lo dice en algún sitio que va ahí?
Buenas Quim. Exacto, ese código permitirá realizar lógica usando los componentes de la vista.
Un saludo
Hola Aris
He tenido un problema en el ShowNameActivity.kt del tipo
Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Bundle?
He tenido que cambiar el código en la definición de la variable «name» y ponerla así:
val name = bundle?.get(«name»)
Con la interrogación después del bundle.
Nadie ha tenido ese problema??
De ese modo, ya funciona la app.
Muchas gracias.
Eso es porque tu onCreate() recibe un «bundle?». Puedes quitarle el nullable ahí si sabes que nunca será null, pero como no lo sabes, lo que has hecho sería más correcto que lo mío, así que felicidades 🙂
Buenas tardes, te hago una consulta, lo que yo quiero implementar es que a través de presionar un botón se pase de una pantalla principal a la siguiente. Entonces el codigo que escribi fue el siguiente:
package com.example.myapplication
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.content.pm.ActivityInfo
import android.view.View
import android.widget.Button
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
button_identificar.setOnClickListener{ it: View? ->
val intent =Intent( this, SecondaryActivity::class.java)
startActivity(intent)
}
}
}
Si bien compila bien lo que sucede es que cuando presiono el boton la aplicacion se cierra, como que falla. Me podrias ayudar a solucionarlo? Gracias!
Hola Aris. Excelente tutorial.
Me ha servido para vcrear mi primera app en android. Despues me he puesto a trastear e intentar modificar algunas cosas.
He intentado hacer que cuando retorna a la pantalla principal el campo tvName se limpie, pero no lo consigo. He probado con
override fun onBackPressed() {
tvName.setText(«»)
super.onBackPressed()
}
En el segundo activity, pero la app se para.
Tambien probé con
override fun onResume() {
tvName.setText(«»)
super.onResume()
}
en el MainActivity pero no hace nada.
¿Como puedo hacerlo?
Gracias
Gracias Aris por estos dos capítulos!
Gracias por este contenido , nos ayuda a todos. Sigue asi!!! 🙂
Buenas, Tenga un problema con un editext. Es para una clave numerica de acceso, Meto la clave numérica, la paso a string y la comparo con la clave de entrada pero no me la reconoce. La he convertido a string, tambien a Int m, pero el If en un setOnclicklistener , no me reconoce los numeros que le introduzco . En Java era mas fácil, pero aqui no me sale , Muchas gracias
El setOnClickListener solo te avisa si el editText ha sido pulsado, no si has escrito texto o no, para ello necesitas otro listener
editTextSample.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) {}
override fun beforeTextChanged(s: CharSequence, start: Int,
count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int,
before: Int, count: Int) {
}
}
Y se llamara a onTextChanged cada vez que se introduzca un caracter
Muchisimas gracias!!!!!!!!!
, Pero esto solo es en kotlin?. en java lohice sin esto y funcionaba.
Claro, todo aquí es en Kotlin 🙂
Hola Aris, como estas?
Primeramente felicitaciones por tu maravilloso curso..! es un exito y lo estoy disfrutando.
Te escribo por lo siguiente, al correr la app la misma hace crash ya que no veo en donde referencias los componentes en la clase .kt
te mostrare donde los referencio yo pero igual me hace crash.
class MainActivity : AppCompatActivity(){
// Aca es donde Referencio los componentes
val etName=findViewById(R.id.etName)
val btnChangeActivity=findViewById(R.id.btnChangeActivity)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnChangeActivity.setOnClickListener { checkValue() }
}
fun checkValue() {
if (etName.text.toString().isEmpty()) {
Toast.makeText(this, «El nombre no puede estar vacío !», Toast.LENGTH_SHORT).show()
} else {
val intento1 = Intent(this, ShowNameActivity::class.java)
intento1.putExtra(«name», etName.text.toString())
startActivity(intento1)
}
}
}
Hola Ari, como estas?
Corri el codigo pero hace crash, en tu codigo no vi las referencias de los componentes, podrias por favor indicar si hay otra manera aparte de esta? ya que esta manera que la venia haciendo la app no corre y se cierre al instante.
class MainActivity : AppCompatActivity(){
//Referenciar nuestros componentes
val etName=findViewById(R.id.etName)
val btnChangeActivity=findViewById(R.id.btnChangeActivity)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnChangeActivity.setOnClickListener { checkValue() }
}
private fun checkValue() {
if (etName.text.toString().isEmpty()) {
Toast.makeText(this, «El nombre no puede estar vacío !», Toast.LENGTH_SHORT).show()
} else {
val intento1 = Intent(this, ShowNameActivity::class.java)
intento1.putExtra(«name», etName.text.toString())
startActivity(intento1)
}
}
}