Páginas

Redimensionar mesas de trabajo en Illustrator

Una de las tareas más tediosas cuando se desarrolla para Android es la de crear los recursos gráficos (iconos, imágenes, etc.) para las distintas densidades de pantalla.

He hecho algunas pruebas con Adobe Illustrator CS6, y el uso de las mesas de trabajo o artboards puede ayudar mucho, ya que a la hora de exportar el trabajo a png, cada mesa de trabajo genera un archivo independiente.

El gran problema viene cuando tengo todo lo que necesito para la aplicación, y toca generar las versiones para cada densidad de pantalla. La idea es muy simple, selecciono todos los elementos del ficheros, y aplico el factor de escala necesario. El primer problema que surge es que esta transformación no afecta a las mesas de trabajo, y no existe (que yo conozca), un método para redimensionarlas por grupos. Así que toca ir una a una dándoles el tamaño correcto. Esto, cuando se trabaja con montones de imágenes, y con al menos 3 densidades de pantalla, resulta inasumible.

Por suerte Illustrator permite realizar scripts (secuencias de comandos) con los que automatizar estas tareas. Así, podríamos usar el siguiente script para redimensionar varias mesas de trabajo de una vez.

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
if (app.documents.length > 0) {
 var idoc = app.activeDocument;

 var fromArtBoard = idoc.artboards.length + 1;
 var toArtBoard = idoc.artboards.length + 1;

 while (fromArtBoard < 0 || toArtBoard < 0 || fromArtBoard > idoc.artboards.length || toArtBoard > idoc.artboards.length) {
  fromArtBoard = Number(Window.prompt ("Enter the first artboard to resize", 1)) - 1;
  toArtBoard = Number(Window.prompt ("Enter the last artboard to resize", idoc.artboards.length)) - 1;
 }

 var width = Number(Window.prompt ("Enter new Artboard width", "new width"));
 var height = Number(Window.prompt ("Enter new Artboard height", "new height"));
 
    for (i=fromArtBoard; i<=toArtBoard; i++) {
        var abBounds = idoc.artboards[i].artboardRect;// left, top, right, bottom
 
        var ableft = abBounds[0];
        var abtop = abBounds[1];
        var abwidth = abBounds[2] - ableft;
        var abheight = abtop - abBounds[3];
        
        var abctrx = abwidth/2+ableft;
        var abctry = abtop-abheight/2;
             
        var ableft = abctrx-width/2; 
        var abtop = abctry+height/2;
        var abright = abctrx+width/2; 
        var abbottom = abctry-height/2;
        
        idoc.artboards[i].artboardRect = [ableft, abtop, abright, abbottom];
    }
}

Pero aquí no acaban los problemas. Si usamos este script y redimensionamos nuestras imágenes con la transformación de escala, seguramente nos encontraremos que la posición de las imágenes ya no coincide con la de sus respectivas mesas de trabajo. De nuevo tendríamos que ir recolocándolas una a una en su posición. Para evitarlo, tendríamos que generar un script que se encargase de redimensionar tanto las mesas de trabajo como las imágenes, de forma que se mantuviesen en la misma posición. Podría ser algo así.


1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
if (app.documents.length > 0) {
 var idoc = app.activeDocument;

 var factor = Number(Window.prompt ("Enter scale factor as percentage", 100));
 
 var ilayer = idoc.activeLayer;
 
 /* Recorremos todos los grupos de objetos escalando */
 for(i = 0; i < idoc.groupItems.length; i++) {
  if (idoc.groupItems[i].parent == ilayer) {
   idoc.groupItems[i].resize(factor,factor,true,true,true,true, factor, Transformation.CENTER);
  }
    }
 
 /* Recorremos todas las mesas de trabajo escalando*/
    for (i=0; i<idoc.artboards.length; i++) {
        var abBounds = idoc.artboards[i].artboardRect;
 
        var ableft = abBounds[0];
        var abtop = abBounds[1];
        var abwidth = abBounds[2] - ableft;
        var abheight = abtop - abBounds[3];
        
        var abctrx = abwidth/2+ableft;
        var abctry = abtop-abheight/2;
             
  var width = abwidth * factor / 100;
  var height = abheight * factor / 100;
        var ableft = abctrx-width/2; 
        var abtop = abctry+height/2;
        var abright = abctrx+width/2; 
        var abbottom = abctry-height/2;
        
        idoc.artboards[i].artboardRect = [ableft, abtop, abright, abbottom];
    }
}
 else  {
        alert ("there are no open documents");
}

Hay un tema importante a tener en cuenta. Lo que hace el script es redimensionar todas las agrupaciones de objetos que se encuentran directamente en la capa activa del documento. Lo he hecho así porque en mis pruebas trabajé con una única capa, con todos los elementos de una mesa de trabajo en un único grupo, por lo que es el funcionamiento que necesitaba. Si trabajas con varias capas puedes modificar el script para recorrerlas todas, o para que te pida qué capas procesar. Si no agrupas los elementos tendrás que modificar el script para recorrer todos los elementos del documento, en lugar de los grupos.

Activar opciones de desarrollo

Una de las decisiones que ha tomado la gente de Android en las últimas versiones (creo que desde la 4.2), es la de ocultar por defecto las opciones de desarrollo.

Acceder a estas opciones es imprescindible si queremos empezar a utilizar nuestro teléfono para probar nuestras aplicaciones porque, entre otras muchas cosas, nos permiten habilitar la depuración por usb.

La activación es muy simple. Sólo tenemos que acceder al menú ajustes, meternos en información del teléfono, y pulsar 7 veces sobre el número de compilación. Sí, es un poco extraño. Estos de Android...

Si todo ha ido bien, verás un mensaje en el que tu teléfono te nombra oficialmente desarrollador, y podrás acceder a las opciones bajo el menú de ajustes.

Ya podemos empezar a cacharrear.

Splash Screen

Un clásico de cualquier aplicación móvil son las splash screen, o pantallas de bienvenida. No son más que pantallas de transición que se muestran a los usuarios antes de darles acceso a la aplicación. Algunas veces se aprovechan para hacer cosas en segundo plano, como cargar recursos, y otras simplemente sirven para mostrar tu logo y meterle a los usuarios tu marca.

Hacer una splash screen en Android es muy simple. Primero necesitamos una activity cuyo layout muestre tu logo. Por ejemplo:

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    tools:context=".JVelActivity" 
    android:onClick="onClick"
    android:background="#0C416F">

<ImageView android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:contentDescription="@string/jvel"
    android:src="@drawable/jvel"/>

</LinearLayout>

Y en el código de la misma podemos hacer algo como esto:

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class JVelActivity extends FullScreenActivity {
 
 private boolean gone = false;
 
 private Thread waitThread;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_jvel);
  
  waitThread = new Thread()
     {
         public void run()
         {
             try
             {
                 //Mostramos la pantalla durante tres segundos, una vez terminados, vamos a la pantalla principal
                 sleep(3000);
             }
             catch (InterruptedException e) 
             {}
             finally
             {   
                 toMainActivity();
             }
         }
     };
     waitThread.start();
 }
 
 private void toMainActivity() {
  if (!gone) {
  Intent intent = new Intent(this, MenuActivity.class);
         startActivity(intent);
         gone = true;
         finish();
  }
 }
 
 public void onClick(View view) {
  toMainActivity();
 }
}

Lo único que hace la actividad es crear un hilo que se duerme durante 3 segundos y, pasado ese tiempo, envía la aplicación a la verdadera pantalla principal (MenuActivity en este caso). También se contempla la posibilidad de que el usuario se harte de esperar, y toque la pantalla. En ese caso pasará inmediatamente al menú, gracias al método onClick, que se ha añadido como oyente para el LinearLayout de fondo.

Lógicamente la actividad debe ser la inicial de la aplicación. Ya sabéis que podéis configurarla como tal en el manifest:

1
2
3
4
5
6
7
8
<activity
            android:name="jvel.android.game.calculator.JVelActivity"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

Puedes ver una implementación de esta pantalla (con el espectacular logo de jVel) en cualquiera de mis juegos. En algunos casos se complementa con una carga de recursos en segundo plano, y un mensaje informativo. Eso para otro día.