- José Enrique Amaro Soriano
- Android
- index_split_014.html
10. IMÁGENES
10.1. Insertar una
imagen en el layout
El sistema
Android soporta imágenes en formato png, jpg y gif. Para insertar
una imagen en una aplicación hay que copiar el fichero con la
imagen en la carpeta res/drawable. Por
defecto, hay tres carpetas, drawble-hdpi, drawable-ldpi y
drawable-mdpi, correspondientes
a resolución alta, baja y media, respectivamente, que serán
seleccionadas por la aplicación dependiendo de la resolución de
pantalla del dispositivo que se utilice. En el siguiente
ejemplo, creamos una nueva aplicación y copiamos nuestra
imagen portada.jpg en la
carpeta res/drawable-hdpi. A continuación, modificamos el
fichero main.xml, añadiendo
una etiqueta ImageView de la
siguiente forma:
<?xml
version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#ddffdd"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:text="ANDROID
ESENCIAL"
android:layout_gravity="center"/>
<ImageView
android:layout_height="wrap_content"
android:src="@drawable/portada"
android:layout_width="wrap_content"
android:id="@+id/imageView1">
</ImageView>
</LinearLayout>
Con esta
estructura, la imagen se añade al layout y no es necesario hacer
nada más. Al ejecutar la aplicación la imagen se muestra en la
pantalla como en la figura 10.1.
![](/epubstore/S/J-E-Soriano/Android/OEBPS/Images/00088.jpg)
Figura
10.1. Imagen insertada en un layout.
10.2. Controlando
las imágenes en Java
La siguiente
actividad construye un album de fotos. Copiaremos cuatro fotos en
la carpeta res/drawable-hdpi.
Diseñamos el layout en main.xml incluyendo
la primera de las fotos. Definimos dos botones para pasar las fotos
adelante y atrás.
<?xml
version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ddddbb"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:textColor="#000000"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="ALBUM DE
FOTOS. Pulsa los botones para verlas"
/>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#999999"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<Button
android:text="Anterior"
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
<Button
android:text="Siguiente"
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
<TextView
android:textColor="#000000"
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Mi
bisabuelo"
/>
</LinearLayout>
<ImageView
android:layout_height="wrap_content"
android:src="@drawable/bisabuelo"
android:layout_width="wrap_content"
android:id="@+id/imageView1"></ImageView>
</LinearLayout>
A continuación
modificamos el fichero Java de la actividad. Cada fichero
foto.jpg
tiene una id llamada R.drawable.foto. Para
modificar la foto mostrada primero se define una
variable ImageView y luego se define la imagen a mostrar
mediante setImageResource(id):
foto=(ImageView)
findViewById(R.id.imageView1);
foto.setImageResource(id)
Las Ids de las
cuatro fotos las introducimos en un array de enteros. Al pulsar un
botón se avanza o se retrocede el índice de la fotografía a
mostrar. El programa queda como sigue:
![](/epubstore/S/J-E-Soriano/Android/OEBPS/Images/00091.jpg)
Figura
10.2. Controlando las imágenes en
Java.
import
android.app.Activity;
import
android.os.Bundle;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.widget.Button;
import
android.widget.ImageView;
import
android.widget.TextView;
public class
FotosActivity extends Activity implements
OnClickListener{
ImageView foto;
TextView tv; //
para escribir el texto de la foto
int[] fotoId =
{R.drawable.bisabuelo,
R.drawable.farmacia,
R.drawable.fernando_amaro,
R.drawable.tres_damas};
String[]
texto={"Bisabuelo","Abuelo","Tio","Abuela"};
int
i=0; //
numero de foto
int total; // numero
total de fotos
/** Called when the activity is first
created. */
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button
anterior=(Button) findViewById(R.id.button1);
Button
siguiente=(Button) findViewById(R.id.button2);
anterior.setOnClickListener(this);
siguiente.setOnClickListener(this);
tv=(TextView)
findViewById(R.id.textView1);
foto=(ImageView)
findViewById(R.id.imageView1);
total
= fotoId.length;
}
public void onClick(View v)
{
int
id=v.getId();
// boton2
adelanta el numero de foto
if(id==R.id.button2){
i++;
if
(i == total) i=0;
}
// boton1
atrasa el numero de foto
if(id==R.id.button1){
i--;
if
(i == -1) i=total-1;
}
foto.setImageResource(fotoId[i]);
tv.setText("Mi
"+texto[i]);
}
}
El resultado
del album de fotos se ve en las figuras 10.2
y10.3.
![](/epubstore/S/J-E-Soriano/Android/OEBPS/Images/00094.jpg)
Figura
10.3. Controlando las imágenes en
Java.
10.3. Botones con
imágenes
Un
ImageButton
es un tipo especial de View que es un botón con una imagen superpuesta. La forma de
definir un ImageButton en xml es
la siguiente:
<ImageButton
android:background="#00000000"
android:scaleType="centerCrop"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/boton1"
android:id="@+id/imageButton1"></ImageButton>
Al hacer el
fondo transparente no se verá el botón de fondo. Sólo la
imagen:
android:background="#00000000"
Existen
distintos tipos de escala que se pueden aplicar a la imagen
como center o
centerCrop. Esta
última escalará la imagen a la anchura total disponible y cortará
los márgenes.
android:scaleType="centerCrop"
En el
siguiente ejemplo definimos cuatro botones con cuatro
fotografías.
![](/epubstore/S/J-E-Soriano/Android/OEBPS/Images/00096.jpg)
Figura
10.4. Uso de ImageButton.
<?xml
version="1.0" encoding="utf-8"?>
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:stretchColumns="*"
android:background="#ffeecc"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TableRow>
<TextView
android:layout_span="2"
android:textSize="20sp"
android:textColor="#000000"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Forjadores
de la Física Cuántica"
/>
</TableRow>
<TableRow>
<ImageButton
android:background="#00000000"
android:scaleType="centerCrop"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/boton1"
android:id="@+id/imageButton1"></ImageButton>
<ImageButton
android:background="#00000000"
android:scaleType="centerCrop"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/boton2"
android:id="@+id/imageButton2"></ImageButton>
</TableRow>
<TableRow>
<ImageButton
android:background="#00000000"
android:scaleType="centerCrop"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/boton3"
android:android:id="@+id/imageButton3"></ImageButton>
<ImageButton
android:background="#00000000"
android:scaleType="centerCrop"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/boton4"
android:id="@+id/imageButton4"></ImageButton>
</TableRow>
<TableRow>
<TextView
android:id="@+id/caption"
android:layout_span="2"
android:textSize="20sp"
android:textColor="#000000"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Toque
una foto para más info"
/>
</TableRow>
</TableLayout>
La imagen a
mostrar debe estar en una de las carpetas res/drawable
y se especifica mediante drawable/boton1,
etc. Esta variable podría referirse a un
fichero de imagen, por ejemplo boton1.png. Pero, en este caso, se
refiere a un fichero boton1.xml que hemos creado en el directorio
res/drawable-hdpi conteniendo un selector:
<?xml
version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_pressed="true"
android:drawable="@drawable/bohr_sepia"
/>
<item
android:drawable="@drawable/bohr" />
</selector>
este selector a
su vez enlaza con los ficheros bohr.jpg (la imagen mostrada por
defecto) y bohr_sepia.jpg (la imagen mostrada al pulsar el botón).
Análogamente hemos creado otros ficheros llamados boton2.xml,
boton3.xml y boton4.xml, conteniendo referencias a otros pares de
imágenes que queremos mostrar.
La siguiente
actividad utiliza el fichero main.xml anterior y muestra un mensaje al pulsar cada
botón.
package
es.ugr.amaro.fisicoscuanticos;
import
android.app.Activity;
import
android.graphics.Color;
import
android.os.Bundle;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.widget.TextView;
public class
FisicosCuanticosActivity extends Activity
implements
OnClickListener{
TextView
caption;
String[] texto={"
",
"Niels Bohr (1885-1962)."
+
"Contribuyó a la
comprensión de la estructura del átomo."+
"Premio Nobel
1922",
"Max Plank (1858-1947). "
+
"Sentó las bases de la
teoría Cuántica de la materia " +
"e introdujo la constante
de Planck." +
"Premio Nobel
1918",
"Pauli. Principio de
exclusión. Matrices de Pauli.",
"Schrodinger (1887-1961)
Ecuación de Schrödinger, " +
"Modelo atómico de
Schrödinger y Efecto Túnel."+
"Premio Nobel
1933"};
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
caption=(TextView)
findViewById(R.id.caption);
View
boton1=findViewById(R.id.imageButton1);
boton1.setOnClickListener(this);
View
boton2=findViewById(R.id.imageButton2);
boton2.setOnClickListener(this);
View
boton3=findViewById(R.id.imageButton3);
boton3.setOnClickListener(this);
View
boton4=findViewById(R.id.imageButton4);
boton4.setOnClickListener(this);
}
@Override
public void onClick(View
v) {
int
i=0;
int
id=v.getId();
if(id ==
R.id.imageButton1) i=1;
else if(id ==
R.id.imageButton2) i=2;
else if(id ==
R.id.imageButton3) i=3;
else if(id ==
R.id.imageButton4) i=4;
caption.setTextColor(Color.BLUE);
caption.setText(texto[i]);
}
}
Vease captura
de pantalla en la figura 10.4. En este
caso, cada vez que se pulsa una imagen, ésta cambia momentaneamente
a color sepia y se muestra un texto explicativo sobre el personaje
de la fotografía.
10.4. Insertar
imágenes en un canvas
Otra forma de
insertar imágenes es "dibujarlas" directamente en un canvas, dentro
del método onDraw() de una clase View. De esta forma, tenemos
control total sobre el posicionamiento, el tamaño y se pueden
realizar manipulaciones gráficas. Para dibujar una imagen primero
se declara un objeto de tipo Drawable:
Drawable
imagen;
y luego debe
definirse la referencia al fichero con la
imagen:
imagen=context.getResources().getDrawable(
R.raw.fichero_imagen);
Esto se hará
en el constructor de la clase View que definamos. La imagen se dibuja en el método
onDraw(), pero antes
es indispensable definir sus dimensiones:
imagen.setBounds(x1,y1,x2,y2);
imagen.draw(canvas);
donde
(x1,y1)
y (x2,y2) son los
vértices opuestos del rectángulo que contiene la imagen. Si estos
puntos no se definen, la imagen no se verá en pantalla, pues se le
asignarán dimensiones nulas. Para obtener las dimensiones reales de
la imagen se usan los métodos getIntrinsicWidth(),
getIntrinsicHeight(). En el
siguiente ejemplo ilustramos esto dibujando en un canvas una imagen
jpg, con sus dimensiones reales (ver figura
10.5).
![](/epubstore/S/J-E-Soriano/Android/OEBPS/Images/00099.jpg)
Figura
10.5. Insertar imágenes en un canvas.
import
android.app.Activity;
import
android.content.Context;
import
android.graphics.Canvas;
import
android.graphics.Color;
import
android.graphics.Paint;
import
android.graphics.drawable.Drawable;
import
android.os.Bundle;
import
android.view.View;
public class
DibujarImagen extends Activity {
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
Pintura
miPintura = new Pintura(this);
setContentView(miPintura);
}
public class Pintura extends
View{
Drawable
imagen;
public Pintura(Context
context) {
super(context);
int
indiceImagen=R.drawable.actor_small;
imagen=context.getResources().getDrawable(
indiceImagen);
}
@Override
public void onDraw(Canvas
canvas){
Paint
p=new Paint();
p.setColor(Color.WHITE);
canvas.drawPaint(p);
int
anchura= imagen.getIntrinsicWidth();
int
altura= imagen.getIntrinsicHeight();
imagen.setBounds(0,0,anchura,altura);
imagen.draw(canvas);
}
}
}
El rectángulo
que contiene la imagen es arbitrario y la copia se ampliará o
reducirá para caber en él. La relación anchura/altura de la imagen
sólo se mantendrá si aplicamos la misma escala a las dos
dimensiones. La misma imagen se puede dibujar múltiples veces con
distintas manipulaciones gráficas. Por ejemplo, en el anterior
programa podemos dibujar dos copias de la misma imagen con
distintas dimensiones y posiciones, sustituyendo el método onDraw()
por el siguiente:
@Override
public void
onDraw(Canvas canvas){
Paint p=new
Paint();
p.setColor(Color.WHITE);
canvas.drawPaint(p);
imagen.setBounds(0,0,400,200);
imagen.draw(canvas);
imagen.setBounds(100,200,300,700);
imagen.draw(canvas);
}
El resultado
se ve en la figura 10.6.
![](/epubstore/S/J-E-Soriano/Android/OEBPS/Images/00101.jpg)
Figura
10.6. Imágenes distorsionadas.
10.5. Ajustar imagen
a las dimensiones de la pantalla
Las imágenes
que pongamos en la carpeta res/drawable y
dibujemos por el método anterior no pueden tener cualquier tamaño,
sino que este debe mantenerse inferior a cierta cantidad que
dependerá del dispositivo utilizado. En general, se
recomienda que la imagen no supere los 2 Megapixeles, lo que
corresponde aproximadamente a una imagen de 1200 pixeles de ancho
por 1600 de alto (que contiene unos 1.9 Megapixeles). Si se supera
esta cantidad, la línea de código:
Drawable
image=getResources().getDrawable(R.drawable.file);
puede producir
un error al ejecutarse de tipo NullPointerException. Conviene pues reducir el tamaño de las
imágenes lo más posible, teniendo en cuenta además que la
resolución de las pantallas de los dispositivos móviles, incluso
tablets, todavía es inferior a los 2 Megapíxeles. Por ejemplo, el
tablet Motorola
Xoom con pantalla de 10
pulgadas, tiene una resolución de 800 x 1280 píxeles,
correspondiente a 150 pixeles por pulgada.
En cualquier
caso, nuestra imagen siempre podrá reescalarse para ajustarse lo
más posible a la pantalla. En el siguiente ejemplo mostramos una
forma de hacerlo. Modificamos la clase Pintura del ejemplo anterior para leer una imagen que es mayor
que la resolución de la pantalla. La imagen se reescala dependiendo
de la razón altura/anchura de la imagen, comparada con la relación
anchura/altura de la pantalla. Si la primera razón es menor que la
segunda, se ajusta el ancho de la imagen al de la pantalla y, en
caso contrario, se ajusta la altura de la imagen a la altura de la
pantalla.
public class
Pintura extends View{
int
indiceImagen=R.drawable.jerry_garcia1000;
Drawable
imagen=getResources().getDrawable(indiceImagen);
public Pintura(Context context)
{
super(context);
}
@Override
public void onDraw(Canvas
canvas){
Paint p=new
Paint();
p.setColor(Color.WHITE);
canvas.drawPaint(p);
int
bottom=getBottom();
int
right=getRight();
float ratioScreen=(float)
bottom/right;
int anchuraIm=
imagen.getIntrinsicWidth();
int alturaIm=
imagen.getIntrinsicHeight();
float ratio= (float)
alturaIm/anchuraIm;
int
anchura,altura;
// ajusta el
ancho
if(ratio<ratioScreen){
anchura=right;
altura=
(int) (anchura*ratio);
} else {
altura=bottom;
anchura=(int)(altura/ratio);
}
imagen.setBounds(0,0,anchura,altura);
imagen.draw(canvas);
p.setColor(Color.RED);
p.setTextSize(30);
p.setShadowLayer (1, -3,
2, Color.BLACK);
canvas.drawText(""+anchuraIm+"x"+alturaIm+"
ratio:"+
ratio, 50,
50, p);
canvas.drawText(""+right+"x"+bottom+"
ratio:"+
ratioScreen,50,90,p);
canvas.drawText(""+anchura+"x"+altura,50,130,p);
}
}
}
El resultado
se ve en la figura 10.7. Vemos
también, en este ejemplo, que se puede dibujar o escribir sobre la
imagen como cualquier otro objeto gráfico. En este caso, escribimos
en rojo las dimensiones de la imagen, de la pantalla y de la imagen
reescalada. Ilustramos también el uso del método
setShadowLayer(blur,
dx,dy,Color) de la clase
Paint, que permite
dibujar la sombra, en este caso del texto, para mejorar su
contraste con la imagen de fondo. En la figura 10.8
vemos cómo se ajusta el alto
automáticamente, en lugar del ancho, al girar el dispositivo
(Ctrl-F11 en el emulador).
![](/epubstore/S/J-E-Soriano/Android/OEBPS/Images/00103.jpg)
Figura
10.7. Ajustar una imagen en la pantalla y escribir
texto sombreado encima.
![](/epubstore/S/J-E-Soriano/Android/OEBPS/Images/00106.jpg)
Figura
10.8. Ajustar una imagen en la pantalla en modo
horizontal.