Inicio Android Interfaz de usuario en Android: Controles personalizados (II)

Interfaz de usuario en Android: Controles personalizados (II)

por sgoliver

Ya vimos cómo Android ofrece tres formas diferentes de crear controles personalizados para nuestras aplicaciones y dedicamos el artículo anterior a comentar la primera de las posibilidades, que consistía en extender la funcionalidad de un control ya existente.

En este segundo artículo sobre el tema vamos a centrarnos en la creación de controles compuestos, es decir, controles personalizados construidos a partir de varios controles estandar, combinando la funcionalidad de todos ellos en un sólo control reutilizable en otras aplicaciones.

Como ejemplo ilustrativo vamos a crear un control de identificación (login) formado por varios controles estándar de Android. La idea es conseguir un control como el que se muestra la siguiente imagen esquemática:

Esquema control login android

A efectos didácticos, y para no complicar más el ejemplo, vamos a añadir también a la derecha del botón Login una etiqueta donde mostrar el resultado de la identificación del usuario (login correcto o incorrecto).

A este control añadiremos además eventos personalizados, veremos como añadirlo a nuestras aplicaciones, y haremos que se pueda personalizar su aspecto desde el layout XML de nuestra interfaz utilizando también atributos XML personalizados.

Empecemos por el principio. Lo primero que vamos a hacer es construir la interfaz de nuestro control a partir de controles sencillos: etiquetas, cuadros de texto y botones. Para ello vamos a crear un nuevo layout XML en la carpeta \res\layout con el nombre «control_login.xml«. En este fichero vamos a definir la estructura del control como ya hemos visto en muchos artículos anteriores, sin ninguna particularidad destacable. Para este caso quedaría como sigue:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="8dp">

    <TextView android:id="@+id/lblUsuario"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/usuario"
        android:textStyle="bold" />

    <EditText android:id="@+id/txtUsuario"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:inputType="text" />

    <TextView android:id="@+id/lblPassword"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/contrasena"
        android:textStyle="bold" />

    <EditText android:id="@+id/txtPassword"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:inputType="textPassword" />

    <LinearLayout android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/btnAceptar"
            android:text="@string/login"
            android:paddingLeft="20dp"
            android:paddingRight="20dp" />

        <TextView android:id="@+id/lblMensaje"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingLeft="10dp"
            android:textStyle="bold" />
    </LinearLayout>
</LinearLayout>

A continuación crearemos su clase kotlin asociada donde definiremos toda la funcionalidad de nuestro control. Dado que nos hemos basado en un LinearLayout para construir el control, esta nueva clase deberá heredar también de la clase LinearLayout de Android. Añadiremos como miembros de la clase las referencias a todos los controles que incluirá nuestro control compuesto y redefiniremos además los tres constructores básicos:

class ControlLogin : LinearLayout {
    private lateinit var txtUsuario : EditText
    private lateinit var txtPassword : EditText
    private lateinit var btnLogin : Button
    private lateinit var lblMensaje : TextView

    constructor(ctx: Context) : super(ctx) {
        inicializar()
    }

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) {
        inicializar()
    }

    constructor(ctx: Context, attrs: AttributeSet, defStyleAttr: Int) : super(ctx, attrs, defStyleAttr) {
        inicializar()
    }
}

Como se puede observar, todo el trabajo lo dejamos para el método inicializar(). En este método inflaremos el layout XML que hemos definido, obtendremos las referencias a todos los controles y asignaremos los eventos necesarios. Todo esto ya lo hemos hecho en otras ocasiones, por lo que tampoco nos vamos a detener mucho. Veamos como queda el método completo:

fun inicializar() {
    //Utilizamos el layout 'control_login' como interfaz del control
    val li = LayoutInflater.from(context)
    li.inflate(R.layout.control_login, this, true)

    //Obtenemos las referencias a los distintos controles
    txtUsuario = findViewById(R.id.txtUsuario) as EditText
    txtPassword = findViewById(R.id.txtPassword) as EditText
    btnLogin = findViewById(R.id.btnAceptar) as Button
    lblMensaje = findViewById(R.id.lblMensaje) as TextView

    asignarEventos()
}

Dejaremos por ahora a un lado el método asignarEventos(), volveremos sobre él más tarde.

Con esto ya tenemos definida la interfaz y la funcionalidad básica del nuevo control por lo que ya podemos utilizarlo desde otra actividad como si se tratase de cualquier otro control predefinido. Para ello haremos referencia a él utilizando la ruta completa del paquete java utilizado, en nuestro caso quedaría como net.sgoliver.android.controlpers2.ControlLogin. Vamos a insertar nuestro nuevo control en la actividad principal de la aplicación:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <net.sgoliver.android.controlpers2.ControlLogin
        android:id="@+id/ctlLogin"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#EDEDED" />

</LinearLayout>

Dado que estamos heredando de un LinearLayout podemos utilizar en principio cualquier atributo permitido para dicho tipo de controles, en este caso hemos establecido por ejemplo los atributos layout_width, layout_height y background. Si ejecutamos ahora la aplicación veremos cómo ya hemos conseguido gran parte de nuestro objetivo.

Vamos a añadir ahora algo más de funcionalidad. En primer lugar, podemos añadir algún método público exclusivo de nuestro control. Como ejemplo podemos añadir un método que permita modificar el texto de la etiqueta de resultado del login. Esto no tiene ninguna dificultad:

fun setMensaje(msg: String) {
    lblMensaje.text = msg
}

En segundo lugar, todo control que se precie debe tener algunos eventos que nos permitan responder a las acciones del usuario de la aplicación. Así por ejemplo, los botones tienen un evento OnClick, las listas un evento OnItemSelected, etc. Pues bien, nosotros vamos a dotar a nuestro control de un evento personalizado, llamado OnLogin, que se lance cuando el usuario introduce sus credenciales de identificación y pulsa el botón «Login».

Para ello, lo primero que vamos a hacer es concretar los detalles de dicho evento, creando una interfaz java para definir su listener. Esta interfaz tan sólo tendrá un método llamado onLogin() que devolverá los dos datos introducidos por el usuario (usuario y contraseña). Vemos cómo queda:

package net.sgoliver.android.controlpers2

interface OnLoginListener {
    fun onLogin(usuario: String, password: String)
}

A continuación, deberemos añadir un nuevo miembro de tipo OnLoginListener a la clase ControlLogin, y un método público setOnLoginListener() que permita suscribirse al nuevo evento. A modo de ejemplo, añado dos versiones del método setOnLoginListener(), el primero de ellos recibiendo directamente un objeto que implementa la interfaz que hemos creado, y otro recibiendo una lambda. Cualquiera de las dos opciones es igual de válida, aunque la segunda nos permitirá implementar más fácilmente el evento cuando vayamos a hacerlo más tarde.

class ControlLogin : LinearLayout {

    var listener: OnLoginListener? = null;

    //...

    fun setOnLoginListener(l: OnLoginListener) {
        listener = l
    }

    fun setOnLoginListener(login: (String, String) -> Unit) {
        listener = object:OnLoginListener {
            override fun onLogin(usuario: String, password: String) {
                login(usuario, password)
            }
        }
    }
}

Con esto, la aplicación principal ya puede suscribirse al evento OnLogin y ejecutar su propio código cuando éste se genere. ¿Pero cuándo se genera exactamente? Dijimos antes que queremos lanzar el evento OnLogin cuando el usuario pulse el botón «Login» de nuestro control. Pues bien, para hacerlo, volvamos al método asignarEventos() que antes dejamos aparcado. En este método vamos a implementar el evento OnClick del botón de Login para lanzar el nuevo evento OnLogin del control. ¿Confundido?. Intento explicarlo de otra forma. Vamos a aprovechar el evento OnClick() del botón Login (que es un evento interno a nuestro control, no se verá desde fuera) para lanzar hacia el exterior el evento OnLogin() (que será el que debe capturar y tratar la aplicación que haga uso del control).

Control de Login - Eventos

Para ello, implementaremos el evento OnClick como ya hemos hecho en otras ocasiones y como acciones generaremos el evento OnLogin de nuestro listener pasándole los datos que ha introducido el usuario en los cuadros de texto «Usuario» y «Contraseña»:

fun asignarEventos() {
    btnLogin.setOnClickListener {
        listener?.onLogin(txtUsuario.text.toString(), txtPassword.text.toString())
    }
}

Con todo esto, la aplicación principal ya puede implementar el evento OnLogin de nuestro control, haciendo por ejemplo la validación de las credenciales del usuario y modificando convenientemente el texto de la etiqueta de resultado:

private lateinit var ctlLogin : ControlLogin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    ctlLogin = findViewById(R.id.ctlLogin)

    ctlLogin.setOnLoginListener { usuario, password ->
        if(usuario == "demo" && password == "demo")
            lblMensaje.text = "Login correcto!"
        else
            lblMensaje.text = "Vuelve a intentarlo"
    }
}

Veamos lo que ocurre al ejecutar ahora la aplicación principal e introducir las credenciales correctas:

Nuestro control está ya completo, en aspecto y funcionalidad. Hemos personalizado su interfaz y hemos añadido métodos y eventos propios. ¿Podemos hacer algo más? Pues sí.

Cuando vimos cómo añadir el control de login al layout de la aplicación principal dijimos que podíamos utilizar cualquier atributo XML permitido para el contenedor LinearLayout, ya que nuestro control derivaba de éste. Pero vamos a ir más allá y vamos a definir también atributos XML exclusivos para nuestro control. Como ejemplo, vamos a definir un atributo llamado login_text que permita establecer el texto del botón de Login desde el propio layout XML, es decir, en tiempo de diseño.

Primero vamos de declarar el nuevo atributo y lo vamos a asociar al control ControlLogin. Esto debe hacerse en el fichero \res\values\attrs.xml. Para ello, añadiremos una nueva sección <declare-styleable> asociada a ControlLogin dentro del elemento <resources>, donde indicaremos el nombre (name) y el tipo (format) del nuevo atributo.

<resources>
    <declare-styleable name="ControlLogin">
        <attr name="login_text" format="string"/>
    </declare-styleable>
</resources>

En nuestro caso, el tipo del atributo será string, dado que contendrá una cadena de texto con el mensaje a mostrar en el botón.

Con esto ya tendremos permitido el uso del nuevo atributo dentro del layout de la aplicación principal. Ahora nos falta procesar el atributo desde nuestro control personalizado. Este tratamiento lo podemos hacer en el constructor de la clase ControlLogin. Para ello, obtendremos la lista de atributos asociados a ControlLogin mediante el método obtainStyledAttributes() del contexto de la aplicación, obtendremos el valor del nuevo atributo definido (mediante su ID, que estará formado por la concatenación del nombre del control y el nombre del atributo, en nuestro caso «ControlLogin_login_text«) y modificaremos el texto por defecto del control con el nuevo texto.

constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) {
    inicializar()

    context.theme.obtainStyledAttributes(
        attrs,
        R.styleable.ControlLogin, 0, 0).apply {
            try {
                btnLogin.text = getString(R.styleable.ControlLogin_login_text)
            } finally {
                recycle()
            }
        }
}

Ya sólo nos queda utilizarlo. Para ello debemos primero declarar un nuevo espacio de nombres (namespace) local para el paquete java utilizado, que en nuestro caso he llamado «sgo». Tras esto, sólo queda asignar el valor del nuevo atributo precedido del nuevo namespace, por ejemplo con el texto «Entrar»:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <net.sgoliver.android.controlpers2.ControlLogin
        xmlns:sgo="http://schemas.android.com/apk/res-auto"
        android:id="@+id/ctlLogin"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#EDEDED"
        sgo:login_text="Entrar" />

</LinearLayout>

Con esto, conseguiríamos el mismo efecto que los ejemplos antes mostrados, pero de una forma mucho más fácilmente personalizable, con el texto del botón controlado directamente por un atributo del layout XML

Como resumen, en este artículo hemos visto cómo construir un control android personalizado a partir de otros controles estándar, componiendo su interfaz, añadiendo métodos y eventos personalizados, e incluso añadiendo nuevas opciones en tiempo de diseño añadiendo atributos xml exclusivos.

Puedes consultar y/o descargar el código completo de los ejemplos desarrollados en este artículo accediendo a la pagina del curso en GitHub.

Espero que os sea útil y que sigáis los artículos que quedan por venir.

También te puede interesar

43 comentarios

Jose 23/12/2010 - 21:41

Genial!!

Muchísimas gracias por tus artículos!! Están muy bien explicados y son muy fáciles de entender.

Responder
Tweets that mention Interfaz de usuario en Android: Controles personalizados (II) | sgoliver.net blog -- Topsy.com 23/12/2010 - 21:41

[…] This post was mentioned on Twitter by Leonardo Moyano . Leonardo Moyano said: RT @apps_droid: Interfaz de usuario en Android: Controles personalizados (II …: Ya vimos cómo Android ofrec… http://bit.ly/gFEpCJ #a … […]

Responder
roberto carlos 04/01/2011 - 9:39

La verdad que es un lujo, el que gente como tu, hagan este tipo de tutoriales.
Muchas gracias por todo.

Responder
Barney2144 07/01/2011 - 21:06

Esta genial es lo que andaba buscando, pero tengo un problema. He creado la clase Button_View que hereda de View para crear botones para un juego y lo defino en el xml dentro de un LinearLayout indicando la ruta del paquete y todo pero me tira un error al ejecutar, en cambio pongo cualquier componente como un Button y funciona.
Este es el codigo que utilizo pa implementar mi botón en el xml:

¿Tienes alguna idea de que podria pasar?

Responder
Desarrollo en Android | sgoliver.net blog 24/01/2011 - 12:57

[…] Interfaz de usuario en Android: Controles personalizados (II) […]

Responder
Interfaz de usuario en Android: Controles personalizados (III) | sgoliver.net blog 10/02/2011 - 11:39

[…] En artículos anteriores ya comentamos dos de las posibles vías que tenemos para crear controles personalizados en Android: la primera de ellas extendiendo la funcionalidad de un control ya existente, y como segunda opción creando un nuevo control compuesto por otros más sencillos. […]

Responder
Alf 22/02/2011 - 13:43

Me quito el sombrero. Deberías escribir un libro con estos temas.

Responder
Sergio 31/03/2011 - 9:29

Hola, tengo una duda,
cuando en la clase control login, el metodo de inicializar, inflas el layoyt con «li.inflate(R.layout.control_login, this, true);», en la clase R se debe de haber creado la variable control_login, pero a mi no se me crea.¿que debo de haber para que se me cree? o ¿la creo yo?¿pero a que la inicializo?

Un saludo y gracias

Responder
silvia 08/04/2011 - 12:21

como se haria para que salgan puntos o asteriscos en vez de letras o numeros en la contraseña?

Responder
alberto 25/04/2011 - 16:37

Enorabuena por la guia de desarrollo!!!

Empece hace poco con el desarrollo de aplicaciones android y gracias a vosotros puedo avanzar mas .

Me gustaria saber donde puedo encontrar ams informacion acerca de «Context» (asi como el «LAYOUT_INFLATER_SERVICE») y «AttributeSet» pues no logro entender del todo su uso.

Gracias de antemano y enorabuena de nuevo por la guia!!

Responder
Salva 07/05/2011 - 10:02

Una pregunta de novato, al declararlos en el xml, los id’s se generan en la clase R.
Si utilizo varias veces un control personalizado en una misma activity, ¿no dará problemas que los los id’s sean los mismos para todos? Imagino que no…

Responder
Diego 23/09/2011 - 9:08

Magnifico curso. Es el sitio donde está mas claramente explicado de los que he visto (y no solo en castellano)

Muchas gracias

Responder
salo 18/01/2012 - 19:23

Excelente curso. Como puedo validar la autentificación de los datos ingresados por el usuario contra una base de datos almacenada en postgres?

Responder
Pepe 24/02/2012 - 19:38

Gracias por la información, pero no haces las cosas mas complicadas de lo que realmente pueden ser?

Responder
admin 24/02/2012 - 21:29

Hola Pepe, ¿qué crees exactamente que se podría hacer más fácil?

Responder
Esther 01/03/2012 - 12:56

Hola! gracias por los tutoriales! ayudan mucho. Una pregunta ¿cómo se puede hacer para que aparezcan asteriscos al escribir la contraseña en lugar de mostrar la palabra que estamos escribiendo?

Responder
Esther 01/03/2012 - 14:30

vale con txtPassword.setTransformationMethod(new PasswordTransformationMethod());

Responder
Diego 08/03/2012 - 20:16

Hola, Felicidades por esta serie de tutoriales. Lo que he leido hasta el momento es de una excelente calidad didáctica.

Me gustaría saber dos cosas:
Primero con que programa has hecho los mockups de este artículo.
Y segundo si hay planeada una tercera versión del PDF, para cuando está planeada su salida, y que cambios va a contener (uso de contactos quizá?)

Responder
admin 09/03/2012 - 12:26

Hola Diego,

Los mockups de este artículo los dibujé con un plugin de Firefox llamado Pencil (http://code.google.com/p/evoluspencil/).

En cuanto a la tercera parte del curso… aún queda. No pretendo publicar un nuevo PDF hasta que no cuente con material suficiente para generar un documento de tamaño similar a los anteriores, y como puedes comprobar por el momento tan sólo hay 5 artículos nuevos en el curso.

Saludos.

Responder
marcelo 02/04/2012 - 8:22

Hola unna consulta… ami no me anda el codigo que subiste… me sale el error «The application… has stoped…» que es lo que puede ser? yo lo estoy personalizando al login con otras funcionalidades y me da el mismo error. mi codigo es el siguiente

@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.login);

ctlLogin = (login)findViewById(R.id.BtnAceptar);
ctlLogin.setOnLoginListener(new OnLoginListener()
{
@Override
public void onLogin(String usuario, String password)
{
//Validamos el usuario y la contraseña
if (usuario.equals(«demo») && password.equals(«demo»))
{
ctlLogin.setMensaje(«Login correcto!»);
// accede al menu
setContentView(R.layout.menu);
}
else
ctlLogin.setMensaje(«Vuelva a intentarlo.»);
}
});
}

Por lo que llegue a probar el error me da a partir de la funcion ctlLogin.setOnLoginListener(new OnLoginListener() {});

Desde ya muchas gracias por su ayuda!

Responder
Fernando 26/04/2012 - 13:36

Hola,
Me surge una duda con respecto a los Controles Compuestos, supongamos que tengo varias aplicaciones que emplearan el control de login.
¿Como puedo importar el control personalizado desde otro proyecto? y asi usarlo en el.

Responder
Elver Florez 11/07/2012 - 17:16

Me funciona bien pero la pregunta es: si al validar el usuario quiero abrir orto layout, como lo muestro? Agradeceria la ayuda

Responder
vimanel 15/09/2012 - 20:02

que tal!

Buena guia!

Una duda…para hacer q al comprobar el usuario y la pass, en caso de q coincidan, como se haria para lanzar una segunda ventana en lugar del mensaje de login correcto?
He intentado pero no puedo jeje..
ojala

Responder
Hardroide 25/09/2012 - 18:56

Muchisimas gracias, realmente muy clara la explicación.

Responder
Luis Alejandro 21/01/2013 - 23:58

Hola quisiera que me ayudaran a resolver una duda, tengo entendido que cada control o elemento de interfaz tiene su método constructor por defecto, en el anterior articulo se indico el constructor de el editText que cuenta con 3 constructores o fragmentos de código, porque viene con 3 de estos, y porque acá para crear un nuevo control hacemos esto
public ControlLogin(Context context) {
super(context);
inicializar();
}

public ControlLogin(Context context, AttributeSet attrs) {
super(context, attrs);
inicializar();
}

este es el constructor para crear nuevos controles??, que significan los parametros??, gracias.

Responder
Interfaz de usuario en Android: Fragments | sgoliver.net blog 27/01/2013 - 19:50

[…] debe conocer qué fragments componen su interfaz. ¿Cómo hacemos esto? Pues de forma análoga a cuando definimos eventos personalizados para un control. Definimos una interfaz con el método asociado al evento, en este caso llamada CorreosListener con […]

Responder
Paco García 23/09/2013 - 8:26

Es un gustazo aprender así. Gracias ;)

Responder
Arturo 22/12/2013 - 3:52

Los tutoriales están muy bien, pero tengo dos dudas puntuales:

1.-¿A que hora se ejecutan los constructores de la clase ControlLogin?

Se supone que un constructor se ejecuta al crear un objeto de la clase, pero en ningún momento se está haciendo, por ejemplo: new ControlLogin(contexto)

2.- La sentencia : listener.onLogin(txtUsuario.getText().toString(),txtPassword.getText().toString());
¿Qué es lo que hace exactamente? Por que bueno, se podría decir que está ejecutando el método de la interfaz, pero el método de la interfaz carece de funcionalidad, ¿como está eso? Definitivametne su lógica debe de tener, pero no la hallo. Gracias

Responder
Joule 27/08/2014 - 6:24

Hola alguien sabe por que en el momento de cargar ingresa un xml diferente, ingresé el codigo linea a linea, copie y pegue, cambié de Linear a RelativeLayout, creé diferentes xml y clases y todas presentan el mismo error, lo unico que cambia es el xml que muestra.

Responder
Jonathan 16/09/2014 - 19:16

Buenas tardes, quisiera saber como puedo acceder a otra actividad después del login, trate con este código pero no me da.

ctlLogin.setOnLoginListener(new OnLoginListener() {
public void onLogin(String usuario, String password) {
// Validamos el usuario y la contraseńa
if (usuario.equals(«demo») && password.equals(«demo»)) {
ctlLogin.setMensaje(«Login correcto!»);
Intent i = new Intent();
i.setClass(MainActivity.this, principal.class);
startActivity(i);
} else
ctlLogin.setMensaje(«Vuelva a intentarlo.»);
}
});

Responder
George Camilo 12/12/2014 - 17:08

Muchas gracias por este gran aporte, Esta de lujo, espero pronto poder retribuir este esfuerzo tuyo.
desde lima peru. Graciaaaaaaaaaas!!!

Responder
Interfaz de usuario en Android: Controles personalizados (I) | sgoliver.net blog 01/03/2015 - 19:49

[…] el siguiente artículo veremos cómo crear un control personalizado utilizando la segunda de las opciones expuestas, es […]

Responder
Interfaz de usuario en Android: Controles personalizados (III) | sgoliver.net blog 18/03/2015 - 19:25

[…] En artículos anteriores del curso ya comentamos dos de las posibles vías que tenemos para crear controles personalizados en Android: la primera de ellas extendiendo la funcionalidad de un control ya existente, y como segunda opción creando un nuevo control compuesto por otros más sencillos. […]

Responder
Erick 05/04/2015 - 0:41

Tengo un error y no logro comprender que ocurre, puse mi teléfono en modo depuración y me aparece la aplicación como detenida, al revisar el código, me aparece error en

setContentView(R.layout.activity_main);

cosa que no logro comprender, simplemente la aplicación se detiene, incluso ya copie y pegue todos los documentos que se editan y no logro ejecutar la aplicación en mi teléfono. ¿Que puede ser lo que ocurre?

Responder
yanet 25/05/2015 - 10:35

muchas gracias por los aportes, es el mejor tutorial sobre Android que he encontrado en la red

Responder
Curso Programación Android por Salvador Gómez – Indice de Contenidos | Miguel Moyetones 17/06/2015 - 21:24

[…] Interfaz de usuario en Android: Controles personalizados (II) [v3] [Actualizado] […]

Responder
Pedkoz 11/07/2015 - 22:45

Hola,

Primero magnifico curso. He de coentar que hay algunos errores que he notado, pero son solucionables sin problema. Por ejemplo la definici’on de las variables de los controles como el edittext o textview no los pones, por lo que un principiante en programaci’n se puede quedar tonto sin saber por que se queja al pegar el codigo…pero me encanta toda la informacion que compartis. Gracias.

Tengo una duda. He seguido todo de este post y he terminado, consegui hacer mi control, pero al llamarlo desde el activity_main pues no se por qué cuando puso el login no sucede nada, no llega a hacer el login y el proyecto lo construye perfecto. No he cambiado nada, salvo definir algnas variables que vuestro codigo no definia y hacer algun import que se necesitaba, pero no me hace el login. He intentado depurar y parece que no ejecuta el codigo.

Un saludo y gracias,

Responder
Pedkoz 11/07/2015 - 23:02

ya resolvi mi problema, pero me dio otro, la solucio fue que en controlLogin como habiamos puesto un asignareventos sin codigo, daba un error y lo comente, fue descomentarlo y lo intenta, pero al intentarlo me cierra la app, da una excepci’on no s’e por qu’e….voy a indagar a ver…

Saludos

Responder
Pedkoz 11/07/2015 - 23:45

Desconozco el motivo del crash que me ace es como si la llamada al control estuviera mal…pero lo corregi haciendo la comprobacion del login desde la clase de controllogin dentro de asociarevento envez de llamar al listener desde el activity_main como un control.

Saludos y gracias:)

Responder
Karol Kenneth Campos Rubalcava 21/04/2016 - 20:00

Pregunta URGENTE!!, como puedo quitar la plantilla que pone por default Android Studio, quiero poner un linear layput o un relative layout solamente con un fondo pero por fuerza me pide que ponga xmlns:android=»http://schemas.android.com/apk/res/android»
pero yo no quiero que aparezca la platilla con el nombre del proyecto la quiero elinimar pero no se como

Responder
junior 22/05/2017 - 2:37

buenas noches, interzante pero dime, sabras alguna forma de ponerle clave al aplicativo, como una clave antes de instalar el aplicativo

Responder
Amanda 30/10/2017 - 14:04

Buenas.
Lo primero enhorabuena por la página es de gran ayuda. Con respecto a los bloques funcionales me gustaría saber como conseguir que a partir del bloque si la opción es correcta haga una acción u otra.
Saludos.

Responder
Interfaz de usuario en Android: Controles personalizados (I) | sgoliver.net 28/06/2020 - 13:08

[…] el siguiente artículo veremos cómo crear un control personalizado utilizando la segunda de las opciones expuestas, es […]

Responder

Dejar un comentario

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información. Aceptar Más Información

Política de Privacidad y Cookies