Android ofrece una API para que trabajemos con los Settings de una forma cómoda.
Vamos a mostrar tan solo un ejemplo en este post, y dejar algunos links a otros lugares que amplían el tema.
El objetivo es identificar los componentes principales:
Comencemos
Agregando nuestros propios settings
En Android tenemos unos activities especiales para los settings, se llaman PreferenceActivity, y podríamos decir que son similares a los layouts, pero hay que crearlas como un XML dentro de res/xml
Veamos con un ejemplo:
a) Creamos res/xml/settings.xml
dentro del directorio xml, con PreferenceScreen:
El contenido del archivo settings.xml es el siguiente:
Donde los valores de los string son definidos en el archivo strings.xml con el prefijo "pref_..."
ChessLab03-bOpen navigation drawerClose navigation drawerSettingsAboutIdiomaSeleccionar IdiomaIdioma de la aplicación
Luego, tenemos la clase que extiende al PreferenceActivity:
public class UserSettingsActivity extends PreferenceActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
}
}
Importante: Hay que agregar el activity al AndroidManifest.xml
Por último, capturamos el evento del click sobre R.id.action_settings para cargar el activity que contiene los settings
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
Intent intent = new Intent(this, UserSettingsActivity.class);
startActivityForResult(intent, RESULT_SETTINGS);
return true;
}
return super.onOptionsItemSelected(item);
}
Observemos el resultado, cuando se seleccionan los Settings, en donde se puede agregar el idioma:
Leyendo el archivo de preferencias
¿Como podemos verificar que valor fue grabado? ¿Donde se persiste el valor?
Vamos a avanzar un poco mas, para ver distintos estilos aplicados y como influyen en el Look&Feel de los settings. Esto se edita en el AndroidManifest.xml donde está declarado el Activity de los settings
Estilo: @style/AlertDialog.AppCompat.Light
Observemos que con este estilo, no es modo dialog, sino un activity:
Además podemos agregar el botón de Volver con este estilo. (Con los Diálogos pequeños, se produce el crash de la aplicación si queremos agregar el botón de volver):
Con este ejemplo, cerramos el post de Settings en Android, aunque dejamos un par de links para ampliar el tema:
En este post vamos a intentar hacer un menu con alguno íconos de ajedrez en Android.
Para esto vamos a crear un nuevo proyecto vacío llamado "ChessLab03"
Recordemos que ChessLab02 se utilizó para probar el manejo del layout y el intercambio de imágenes con diagramas de figuras de ajedrez con resultados muy buenos de acuerdo a nuestras expectativas, y ChessLab01 se utilizó para probar las fonts de ajedrez, con resultados aún muy pobres pero confiamos en que vamos a volver sobre este post y este aspecto
El objetivo de ChessLab03, es imitar en Android el siguiente menu que teníamos en la web:
Veremos que pasa con ChessLab03 y los menú en Android...
Comencemos
Paso 01: Creamos el Proyecto ChessLab03 y lo subimos a GitHub
Creamos un nuevo branch para "ChessLab03", y un nuevo proyecto en Android vacío:
Con el directorio de trabajo:
/Users/pabloin/Desktop/NoCuestaNada/Mob/GitHub-Android-Chess/ChessLab03
... estaba predispuesto a hacer el menú desde cero, tomando ejemplos desde los cursos e Internet, pero ya tenemos un Layout con un menú, así que vamos a empezar por ahí:
Estamos utilizando el Navigation Drawer:
Y ejecutamos el proyecto vacío, con el texto "Hola ChessLa03!"
Que contiene un menu como queríamos, que en el paso siguiente vamos a comenzar a customizarlo para que se adapte a nuestro proyecto "ChessLab03"
Y con esto configurado, estamos listos para comenzar
Paso 02: Modificamos el Navigation Drawer menu
La idea es incluir en el menú lo que anticipábamos en la vista web: Las opciones de "Mate en 1, 2, 3 y 4". Vamos a obviar lo obvio... por ejemplo, cambiar textos del menu en android (archivo activity_main_drawer.xml), y continuar con lo menos obvio, al menos para mi:
Observemos que en el proyecto las imágenes de la cámara, galería, tools... están representadas con un XML que es un vector. O sea, no es un PNG, ni un JPG, ni un GIF. Y acá es un punto que yo desconozco, así que vamos a averiguar esto:
¿Como cambiamos las imágenes?¿Que son los vectores? ¿Puedo hacer mis propios vectores de imágenes? ¿Cómo se generan?
Un buen lugar de referencia para obtener una buena respuesta a estar preguntas es la página oficial:
Y como es muy extensa la explicación vamos a copiar brevemente dos o tres ideas sobre los drawables.....
Parece que apareció con la versión Lollipop, los gráficos escalan mejor y hacen más livianas a las .apk. Una de las ventajas mas grandes de los Drawables es que se arman en tiempo de ejecución, con lo cual naturalmente escalan con el dispositivo a la adecuada densidad de la pantalla...
Afortunadamente, y después de no poco trabajo, pudimos lograr el objetivo de encontrar la forma de trabajar comodamente con las imágenes vectoriales, con el software open source incscape en el centro de la solución:
Que nos genera el siguiente drawable a partir del SVG:
El cual copiamos dentro del proyecto Android
Y en Android:
Y ahora agregamos la imagen Drawable, de un caballo
Y a continuación, veamos como se ve el caballo integrado en el menú de un Nexus:
Y de una tablet, manteniendo las proporciones:
Un poco de teoria
Repasemos un poco de teoría sobre las imágenes. En Android las imágenes se miden en "dp, px, pt", "mm, in". Donde dp (las mas interesante) son los mas comunes y básicamente significa:
– dp (Density-independent Pixels) Es una unidad abstracta que se basa en la densidad física de la pantalla. Esta unidad es equivalente a un píxel en una pantalla con una densidad de 160 dpi. Cuando se está ejecutando en una pantalla de mayor densidad, se aumentan el número de píxels utilizados para dibujar 1dp según los dpi’s de la pantalla. Por otro lado, si la pantalla es de menor densidad, el número de píxeles utilizados para 1dp se reducirán. Utilizar las unidades dp en lugar de píxeles es la solución más simple para tratar los diferentes tamaños de pantalla de los dispositivos.
Definición tomada del blog, del cual recomiendo leer el resto del post:
Con esta teoría, donde yo estuve utilizando imágenes SVG de 64dp, y que tiene definido espacios de 16 dp respecto a sus bordes y elementos adyacentes ¿Esto se puede medir y verificar en una imagen JPG creada con el GIMP?
Vamos a verificarlo: Con el GIMP vamos a recortar la imagen del Nexus que mostramos más arriba.
Es una imagens de 480x800 pixeles. El caballo grande, es el archivo PNG original que agregué en una nueva capa, para compararlo con el caballo pequeño que es el archivo SVG que android escal en unidades dp
Al abrirla con el GIMP, y poner algunas guías, quedan las distancias en pixeles que suponíamos:
Reducimos la escala del caballo grander PNG con el GIMP a una altura de 64 pixeles. Y como se observa en la imagen, quedó exactamente igual al caballo de la izquierda, que es la imagen SVG definida en 64dp para android.
Con esto damos por cerrado el post de insertar imágenes Drawables y SVG en Android
Quedaría pendiente agregar las secciones internas de los puntos del menu, para completar el ejercicio ChessLab03
GitHub
La versión exacta, como se ve en este post, es es siguiente Pre-Release:
En el Post anterior Android, Chess y Fonts - (Parte I) buscamos algunas fonts de ajedrez para utilizar en proyectos Android y probamos esas fonts, de diversas maneras.
Además, hicimos nuestra primera pantalla de Android, que se ve a continuación, con las jugadas de Ajedrez, pero sin utilizar la font de notación de ajedrez:
Hoy vamos a evolucionar este ejemplo, para que la font de ajedrez sea utilizada dentro de del proyecto android
Comencemos
Lo primero que vamos a hacer, es compartir el proyecto en GitHub desde el comienzo para poder mostrar el avance.
Con el proyecto esta creado, y agregadas las primeras jugadas, lo subimos a GitHub:
Vemos como las fonts se aplicaron sobre los textos:
Mas grande:
Chess Fonts y Unicode
Otra posibilidad distinta, es en vez de utilizar una chess font, es utilizar la tabla de unicode para ajedrez:
No se cual sería la ventaja/desventaja respecto a una chess font, pero por lo pronto dejo una tabla y también una pantalla del "ChessLab02" donde utlizé al Unicode para poner las jugadas:
La tabla de Unicode de Chess symbols es la siguiente:
2654 ♔ WHITE CHESS KING
2655 ♕ WHITE CHESS QUEEN
2656 ♖ WHITE CHESS ROOK
2657 ♗ WHITE CHESS BISHOP
2658 ♘ WHITE CHESS KNIGHT
2659 ♙ WHITE CHESS PAWN
265A ♚ BLACK CHESS KING
265B ♛ BLACK CHESS QUEEN
265C ♜ BLACK CHESS ROOK
265D ♝ BLACK CHESS BISHOP
265E ♞ BLACK CHESS KNIGHT
265F ♟ BLACK CHESS PAWN
Observemos la siguiente pantalla, donde la solución está escrita con Unicode de Chess Simbols:
Estamos persiguiendo el objetivo de hacer alguna aplicación sencilla con Android. En este sentido hay que solucionar varias cosas, por ejemplo:
Un backend, que lo estamos abordando con Heroku y Node.js
Una representación de los diagramas,
Que por ahora utilizaremos imágenes PGN
En un futuro esperamos poder parsear los archivos FEN
Un motor de ajedrez que soporte el protocolo UCI
La capacidad de hablar protocolo UCI
Una Font de Ajedrez para la notación de jugadas
Esto lo vamos a atacar hoy
Componentes de Interfaz de usuario (Menú, widgets, etc...
Esto también lo vamos a atacar hoy ...
Comencemos
Como vamos a atacar componentes sueltos, vamos a partir desde una aplicación de Android en blanco por se mas fácil de manejar, para aprender como integrar Fonts y algunas Widgets.
¿Como podemos escribir las jugadas de la solución con las figuras?
"solution":"1. Nb5+ cxb5 2. Nb7#",
Deberíamos buscar un font de Ajedrez
Después de Googlear muy poco, encontré un link de recopilación de fonts de Ajedrez:
http://www.enpassant.dk/chess/fonteng.htm
http://www.enpassant.dk/chess/fonfaqen.htm
De esta colección voy a elegir a:
Chess Mérida
Freeware. True Type Font by Armando H. Marroquin for diagrams and figurine notation. A classic font named after the city Mérida on Yacatan. Frame with co-ordinates possible. View pieces.
Download Chess Mérida (27 KB)
También desargue las siguientes fuentes (todas de ajedrez) tomadas de:
En el post anterior hacíamos una botonera de navegación para el ejercicio "ChessLab02", y de esa manera explorábamos los íconos de google de material design.
En este post, vamos a ver un componente que al menos a mi me pareció divertido y apropiado para incluir en layout: se trata de SeekBar, que es simplemente una ProgressBar, con un comportamiento similar.
La SeekBar permite deslizarse entre un rango de valores, desde 0 hasta un máximo. Similar a cuando nos movemos entre los videos de YouTube. También podemos customizarla, agregando una imagen que se desplaza.
En nuestro caso, desplazaremos un peón a medida que se avanza sobre la secuencia de ejercicios.
El objetivo de hoy es agregarle la progress bar llamada "SeekBar" para acompañar la barra de navegación del progreso.
Comencemos
La secuencia sería la siguiente:
1. Agregar una SeekBar entre 0 y 9 que son la cantidad de problemas que tenemos.
2. Cada evento de la botonera (primero, anterior, siguiente, último) moverá la SeekBar
3. Reemplazaremos la imagen por un peón.
Paso 01: Agregar SeekBar
Vamos como quedó la SeekBar agregada, cosa que es muy sencillo: simplemente un componente SeekBar en el layout y un listener en el Activity que "escucha" el movimiento del progreso.
Los eventos de "escucha" son:
new SeekBar.OnSeekBarChangeListener() {
onStartTrackingTouch ... // Evento cuando comienzan a mover la SeekBar
onProgressChanged ... ... // Evento cuando se esta moviendo la SeekBar
onStopTrackingTouch ... // Evento cuando se suelta la SeekBar
}
Por ahora, solo muestro la imagen con el resultado, y el código lo comparo un poco mas abajo del post, porque me gustaría mostrar vincular el movimiento de la SeekBar con el cambio de imagen del problema de ajedrez
Observemos que cuando se mueve la SeekBar también se actualiza el contenido del TextView, diciendo "2/11"
Paso 02: Cambiar los problemas cuando cambia la SeekBar
Al final este paso fué mas sencillo de lo que me imaginaba, asique comienzo compartiendo el código:
En el Layout, la SeekBar se define con:
En el Main Activity la SeekBar se implementa con:
public class MainActivity extends AppCompatActivity {
public static String TAG = MainActivity.class.getName();
private static int MAX_MateEn1 = 13;
private static int MAX_MateEn2 = 11;
private static int MAX_MateEn3 = 15;
private static int MAX_MateEn4 = 12;
ImageView image;
TextView chessSolution;
int idx = 0;
private SeekBar seekBar;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
image = (ImageView) findViewById(R.id.chess_board_image);
seekBar = (SeekBar) findViewById(R.id.seekBar1);
textView = (TextView) findViewById(R.id.seekBar1_text);
// Initialize the textview with '0'.
textView.setText("Ejercicio: " + seekBar.getProgress() + "/" + seekBar.getMax());
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
int progress = idx;
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// Toast.makeText(getApplicationContext(), "Started tracking SeekBar", Toast.LENGTH_SHORT).show();
}
@Override
public void onProgressChanged(SeekBar seekBar, int progresValue, boolean fromUser) {
progress = progresValue;
// Cambio el problema mientras se desliza la SeekBar
idx = progresValue;
navigateMateEn2();
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
textView.setText("Ejercicio: " + progress + "/" + seekBar.getMax());
// Cambio el problema cuando se suelta la seekBar
idx = progress;
navigateMateEn2();
}
});
}
.....
}
El método navigateMateEn2() se puede ver implementado en el post anterior o bien en GitHub
La aplicación se ve como cambia de imágenes:
Y podemos ver en acción tanto la SeekBar como la barra de navegación incorporada en el post anterior en el siguiente video:
Lo último que nos quedaría sería customizar la NavBar
Paso 03: Un peón en la SeekBar
Veamos primero el resultado:
Y nuevamente mostramos en un video la demo funcionando:
Con esto damos por cerrado el post, y finalizamos la serie de:
Android, Chess y Layout - (Parte I, II y III)
Hemos recorrido entre otras cosas, la creación de una aplicación sencilla de Android, que toma imágenes almacenadas localmente en la aplicación, y es capaz de intercambiar las imágenes de forma dinámica.
También vimos el uso de los iconos de Material Design de Google, los componentes básicos, donde el último fué como SeekBar
En el post anterior comenzamos con el proyecto de Android ChessLab02 (Compartido en GitHub) que se enfoca en el layout de Android y en la parte gráfica de una posible aplicación de Ajedrez.
Hoy vamos a intentar evolucionar ese componente agregando lo siguiente:
- Botones de Anterior, Siguiente, Primero, Ultimo
- Botón de ver solución
- ProgressBar que indique en que progreso, con una imagen
Para el post siguiente quedará la posibilidad de ver las soluciones, lo que nos obligará a trabajar con un archivo en formato Json, que relacionará los ejercicios con las soluciones.
Comencemos
Paso 01: Buscamos Botones de Anterior, Siguiente, Primero, Ultimo
Podría agregar cuatro botones del tipo Buton con los eventos, pero obviamente esto va a quedar muy tosco visualmente. La alternativa es utilizar cuatro imágenes típicas del avanzar y retroceder.
Y aquí es donde viene la primera pregunta importante, que nos invita a pensar antes de empezar a hacer las cosas de la primera forma que se nos viene a la mente.
¿De donde vamos sacamos la imágenes para la botonera de la aplicación?
Las primeras alternativas son, de google images, de algún proyecto de GitHub, las hacemos nosotros, de la primera página que nos aparezca en google.... o también podría ser de las guías de material design oficiales de google
Y además de ser la guía oficial, nos permite descargar todo el conjunto de iconos. La última versión de la colección de íconos de Material design que me descargué de esa página de google es un archivo de 60 MB.
Y, en seguida nos llevamos la grata sorpresa, que tiene los iconos exactamente que necesitábamos, con los nombres exactos, y con sus distintas resoluciones, y listos para utilizarlos en el proyecto Android.
Dice el refrán, "para muestra sobra un botón" y vamos a ver entonces el botón de "último":
El único problema, sería para los desarrolladores/diseñadores que buscarían diferenciarse con su aplicación (no es nuestro caso), ya que si utilizan los ícono de esta colección les van a quedar las aplicaciones igual a la de todo el mundo.
Lo interesante, y que me causa curiosidad es el directorio drawable-anydpi-v21
Donde representa a la imagen en modo de vector.
Aún no se cuál es el sentido, pero googleando rápido pareciera que es para versiones mas nuevas de android que lo soporta, y permite escalar mejor la imagen... disculpen la ignoracia...
Paso 02: Copiamos Botones de Anterior, Siguiente, Primero, Ultimo
Y finalmente, los métodos "onClick" se pueden ver mejor en el post anterior, pero igualmente voy a compartir lo que agregué en este ejercicio para tener "anterior, siguiente, primero, último" sin demasiado copy&paste:
public void firstMateEn2(View view) {
Log.d(TAG, "firstMateEn2" + idx);idx = 0;navigateMateEn2(view);}
public void lastMateEn2(View view) {
Log.d(TAG, "lastMateEn2" + idx);idx = 11;navigateMateEn2(view);}
public void prevMateEn2(View view) {
Log.d(TAG, "prevMateEn2" + idx);idx --;navigateMateEn2(view);}
public void nextMateEn2(View view) {
Log.d(TAG, "nextMateEn2" + idx);idx ++;navigateMateEn2(view);}
private void navigateMateEn2(View view) {
Log.d(TAG, "NETX - navigateMateEn2 " + idx); if (idx < 0) {
idx = 0;}
if (idx > 11) {
idx = 0;}
if (idx == 0) {
image.setImageResource(R.drawable.chess_mate2_00000);}
if (idx == 1) {
image.setImageResource(R.drawable.chess_mate2_00001);}
if (idx == 2) {
image.setImageResource(R.drawable.chess_mate2_00002);}
if (idx == 3) {
image.setImageResource(R.drawable.chess_mate2_00003);}
if (idx == 4) {
image.setImageResource(R.drawable.chess_mate2_00004);}
if (idx == 5) {
image.setImageResource(R.drawable.chess_mate2_00005);}
if (idx == 6) {
image.setImageResource(R.drawable.chess_mate2_00006);}
if (idx == 7) {
image.setImageResource(R.drawable.chess_mate2_00007);}
if (idx == 8) {
image.setImageResource(R.drawable.chess_mate2_00008);}
if (idx == 9) {
image.setImageResource(R.drawable.chess_mate2_00009);}
if (idx == 10) {
image.setImageResource(R.drawable.chess_mate2_00010);}
if (idx == 11) {
image.setImageResource(R.drawable.chess_mate2_00011);}
// Toast.makeText(this, "Boton Click", Toast.LENGTH_SHORT);}
Básicamente, muevo el puntero del ejercicio actual. En la app están las 11 imágenes con los ejercicios de Mate en 2
Para cerrar el post, agrego otra imagen de la App, donde en la solución utiliza un unicode de ajedrez:
La tabla de Unicode de Chess symbols es la siguiente:
2654 ♔ WHITE CHESS KING
2655 ♕ WHITE CHESS QUEEN
2656 ♖ WHITE CHESS ROOK
2657 ♗ WHITE CHESS BISHOP
2658 ♘ WHITE CHESS KNIGHT
2659 ♙ WHITE CHESS PAWN
265A ♚ BLACK CHESS KING
265B ♛ BLACK CHESS QUEEN
265C ♜ BLACK CHESS ROOK
265D ♝ BLACK CHESS BISHOP
265E ♞ BLACK CHESS KNIGHT
265F ♟ BLACK CHESS PAWN
Comparto un video subido a YouTube con el ejemplo de la aplicación funcionando. Este video tiene incorporada la SeekBar que se desarrolla en el siguiente post, de la Parte III
El código fuente, como siempre, queda compartido en GitHub