PDM Avanzado Captura de Vídeo / Imaxes

De MediaWiki
Saltar a: navegación, buscar

Introdución

As clases que interveñen na gravación son:

  • Clase Camera: danos acceso á cámara, as súas características. Usarémola se facemos unha aplicación na que queiramos xestionar a cámara por nos mesmos.
  • Clase SurfaceView: para previsualizar o que imos gravar.
  • Clase MediaRecorder: permítenos gravar vídeo dende a cámara.


Para facer uso da cámara para gravar un vídeo podemos utilizar un Intent, evitándonos ter que deseñar a aplicación para xestionar a cámara.


Permisos necesarios a engadir no arquivo AndroidManifest.xml:

  • Permiso de lectura sobre a tarxeta SD Externa (no caso de utilizar un dispositivo cunha API 23 ou superior).
  1. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>


  • Permiso para facer uso da cámara:
  1. <uses-permission android:name="android.permission.CAMERA" />


Nota: Se usamos a opción de chamar á cámara cun Intent non necesitamos dito permiso.

  • Permiso para indicar que a nosa aplicación fai uso da cámara:
  1. <uses-feature android:name="android.hardware.camera" required="true"/>

Se queremos facer uso doutras ‘características’, tanto da cámara coma doutro hardware que ten o dispositivo móbil, consultar: http://developer.android.com/guide/topics/manifest/uses-feature-element.html#hw-features

Desta forma Google Play impedirá que se instale á aplicación se o dispositivo non ten o hardware necesario coas características especificadas.

Neste caso, a nosa aplicación está requirindo ó uso da cámara, pero pode ocorrer que non a necesite para que funcione (podemos limitar a funcionalidade da nosa aplicación se o dispositivo non ten cámara, por exemplo). Para indicar isto temos que poñer:

  1. <uses-feature android:name="android.hardware.camera" android:required="false" />
  • Permiso de almacenamento: se a aplicación vai gardar os datos nunha tarxeta SD externa:
  1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


  • Permiso para capturar audio (se é o caso):
  1. <uses-permission android:name="android.permission.RECORD_AUDIO" />



IMPORTANTE: A partires da API 23 (Android 6), Android incorpora outro nivel de seguridade, de tal forma que agora, a maiores, teremos que solicitar dito permiso a nivel de programación. Máis información de como facelo neste enlace.


Captura de Vídeo / Audio

Neste manual imos aprender como facer uso das aplicacións que nos proporciona o S.O. Android para sacar unha foto ou vídeo.

Nos chamaremos a unha destas aplicacións e recolleremos o resultado de volta (que será a foto / vídeo sacado).



Nota: Facer esta parte utilizando o emulador é extremadamente lenta.

Cando prememos o botón de gravar temos que agardar ata que o rectángulo do interior da pantalla se poña vermello:

PDM Avanzada Multimedia Gravacion 1.jpg



Os pasos a seguir son:

  • Crear un Intent que sexa dun destes tipo:
  1. Intent intento = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);


Neste momento o S.O. lanzará unha aplicación para recoller a imaxe ou vídeo.
Lembrar que con esta forma de chamar a unha activity, esperamos un resultado (a foto ou vídeo sacado).
  1. startActivityForResult(intento, REQUEST_CODE_GRAVACION_OK);
Cando chamamos a actitivity que lanza a aplicación de sacar foto ou gravar vídeo, podemos enviarlle como parámetros (no obxecto Bundle) unha serie de datos extras, como a calidade da foto, a calidade de vídeo, o tamaño máximo de gravación,onde queremos gardar a foto/vídeo...
Máis información en http://developer.android.com/reference/android/provider/MediaStore.html#EXTRA_OUTPUT.

Nota: Para asinar un nome único a cada imaxe / vídeo capturado imos facer uso da clase Date. Cando importemos dita clase lembrar escoller á que se atopa no paquete util:

PDM Avanzada Multimedia Gravacion 2.jpg

No caso de non enviar como información extra ó Intent onde queremos gardar o vídeo /foto, estes van vir no obxecto Intent dentro do método onActivityResult():

No caso das imaxes, a imaxe ven no campo "data" dentro de getExtras do obxecto Bundle:
  1. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  2.  
  3.   Bitmap bitMap= data.getExtras().get("data"));
  4.   .........
  5. }
Unha vez temos o BitMap podemos visualizalo nun control ImageView da seguinte forma:
  1. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  2.  
  3.   Bitmap bitMap= data.getExtras().get("data"));
  4.   imgView.setImageBitmap(bitMap);
  5. }
Sendo imgView un obxecto da clase ImageView.


No caso do vídeo, obtemos o vídeo chamando ó método getData() do obxecto bundle. Isto devolve a URI do vídeo.
  1. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  2.  
  3.   Uri uri = data.getData();
  4.   .........
  5. }
Para visualizalo necesitamos un obxecto da clase VideoView.
  1. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  2.  
  3.         vidView.setVideoURI(data.getData());
  4.         vidView.start();
  5. }
Sendo vidView un obxecto da clase VideoView.

Accedendo ó Vídeo / Foto

Cando chamamos a activity que vai sacar a foto / vídeo podemos non indicar onde gardar esa foto

Neste punto imos ver como podemos acceder ó vídeo / foto que ven no Intent dentro do método onActivityResult().


Caso Práctico

O obxectivo desta práctica é visualizar nun control ImageView / VideoView a imaxe / vídeo obtida dende a aplicación do S.O. Android.

PDM Avanzada Multimedia Gravacion 3.jpg

Nesta aplicación, debaixo do botón, se atopa un control ImageView e un control VideoView.

Dependendo da opción escollida no RadioButton, un deles estará invisible (propiedade visibility="gone").


Creamos a Activity

  • Nome do proxecto: UD6_04_MultimediaFotoVideo
  • Nome da activity: UD6_04_MultimediaFotoVideo.java


Código do layout xml

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.    xmlns:tools="http://schemas.android.com/tools"
  3.    android:layout_width="match_parent"
  4.    android:layout_height="match_parent" >
  5.  
  6.     <RadioGroup
  7.        android:id="@+id/UD6_04_rgrpOpcions"
  8.        android:layout_width="match_parent"
  9.        android:layout_height="wrap_content"
  10.        android:layout_alignParentLeft="true"
  11.        android:layout_alignParentTop="true"
  12.        android:gravity="center_horizontal"
  13.        android:orientation="horizontal" >
  14.        
  15.             <RadioButton
  16.                 android:id="@+id/UD6_04_rbtnFoto"
  17.                 android:layout_width="wrap_content"
  18.                 android:layout_height="wrap_content"
  19.                 android:text="Sacar Foto"
  20.                 android:textSize="15sp"
  21.                 android:checked="true" />
  22.        
  23.             <RadioButton
  24.                 android:id="@+id/UD6_04_rbtnVideo"
  25.                 android:layout_width="wrap_content"
  26.                 android:layout_height="wrap_content"
  27.                 android:textSize="15sp"
  28.                 android:text="Sacar Vídeo" />
  29.         </RadioGroup>
  30.     <Button
  31.        android:id="@+id/UD6_04_btnGravarVideoFoto"
  32.        android:layout_width="match_parent"
  33.        android:layout_height="wrap_content"
  34.        android:layout_alignParentLeft="true"
  35.        android:layout_below="@+id/UD6_04_rgrpOpcions"
  36.        android:textSize="14sp"
  37.        android:text="Lanzar Aplicación" />
  38.  
  39.  
  40.      <FrameLayout
  41.         android:layout_width="match_parent"
  42.         android:layout_height="match_parent"
  43.         android:layout_alignParentLeft="true"
  44.         android:layout_below="@+id/UD6_04_btnGravarVideoFoto">
  45.  
  46.          <ImageView
  47.             android:id="@+id/UD6_04_imgvwFoto"
  48.             android:layout_width="match_parent"
  49.             android:layout_height="match_parent"
  50.             android:contentDescription="foto a sacar"
  51.                  android:layout_gravity="center"
  52.             android:src="@drawable/ic_launcher" />
  53.  
  54.          <VideoView
  55.             android:id="@+id/UD6_04_vidvwVideo"
  56.             android:layout_width="match_parent"
  57.             android:layout_height="match_parent"
  58.             android:layout_gravity="center"
  59.             android:visibility="gone" />
  60.  
  61.      </FrameLayout>
  62.  
  63.  </RelativeLayout>


Código da clase UD6_04_MultimediaFotoVideo
Obxectivo: Comprobar como capturar unha imaxe / vídeo e visualizala nun control ImageView / VideoView

  1. import android.app.Activity;
  2. import android.content.Intent;
  3. import android.graphics.Bitmap;
  4. import android.os.Bundle;
  5. import android.provider.MediaStore;
  6. import android.view.View;
  7. import android.view.View.OnClickListener;
  8. import android.widget.Button;
  9. import android.widget.ImageView;
  10. import android.widget.RadioButton;
  11. import android.widget.RadioGroup;
  12. import android.widget.RadioGroup.OnCheckedChangeListener;
  13. import android.widget.Toast;
  14. import android.widget.VideoView;
  15.  
  16. public class UD6_04_MultimediaFotoVideo extends Activity {
  17.  
  18.         /**
  19.          * Código para verificar que o resultado ven do intent de gravación
  20.          */
  21.         private final int REQUEST_CODE_GRAVACION_OK = 1;
  22.        
  23.        
  24.         /**
  25.      * Obtemos a imaxe ou video que ven da aplicacion Android
  26.      */
  27.         protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  28.                 if (requestCode == REQUEST_CODE_GRAVACION_OK) {
  29.                         if (resultCode == RESULT_OK) {
  30.  
  31.                                 if (data == null) {
  32.                                         Toast.makeText(getApplicationContext(), "NON HAI IMAXE/VIDEO A GARDAR", Toast.LENGTH_LONG).show();
  33.                                         return;
  34.                                 }
  35.  
  36.                                 RadioButton rb = (RadioButton) findViewById(R.id.UD6_04_rbtnFoto);
  37.                                 if (rb.isChecked()) { // Saca foto
  38.                                         ImageView imgview = (ImageView) findViewById(R.id.UD6_04_imgvwFoto);
  39.                                         imgview.setImageBitmap((Bitmap) data.getExtras()
  40.                                                         .get("data"));
  41.                                 } else { // Saca vídeo
  42.                                         VideoView vidview = (VideoView) findViewById(R.id.UD6_04_vidvwVideo);
  43.                                         vidview.setVideoURI(data.getData());
  44.                                         vidview.start();
  45.                                 }
  46.  
  47.                         } else if (resultCode == RESULT_CANCELED) {
  48.                                 // Video ou Foto cancelada
  49.                         } else {
  50.                                 // Fallo na captura do Video ou foto.
  51.                         }
  52.                 }
  53.         }
  54.    
  55.         /**
  56.      * Programa o código dos click´s os botóns
  57.      */
  58.         private void xestionarEventos(){
  59.                 Button gravar = (Button)findViewById(R.id.UD6_04_btnGravarVideoFoto);
  60.                 gravar.setOnClickListener(new View.OnClickListener(){
  61.  
  62.                         @Override
  63.                         public void onClick(View arg0) {
  64.                                 // TODO Auto-generated method stub
  65.                                 RadioButton rb = (RadioButton)findViewById(R.id.UD6_04_rbtnFoto);
  66.  
  67.                                
  68.                                 if (rb.isChecked()){    // Saca foto
  69.                                        
  70.                                         Intent intento = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  71.                                         startActivityForResult(intento, REQUEST_CODE_GRAVACION_OK);
  72.                                        
  73.                                 }
  74.                                 else {  // Grava vídeo
  75.                                         Intent intento = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
  76.                                         startActivityForResult(intento, REQUEST_CODE_GRAVACION_OK);
  77.                                
  78.                                 }
  79.                                
  80.                         }
  81.                        
  82.                 });
  83.  
  84.                 RadioGroup rgroup = (RadioGroup)findViewById(R.id.UD6_04_rgrpOpcions);
  85.                 rgroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
  86.                        
  87.                         @Override
  88.                         public void onCheckedChanged(RadioGroup group, int checkedId) {
  89.                                 // TODO Auto-generated method stub
  90.                                 ImageView imgview;
  91.                                 VideoView videoview;
  92.                                
  93.                                 switch(checkedId){
  94.                                         case R.id.UD6_04_rbtnFoto:      // OCULTAMOS O VIDEO
  95.                                                 imgview = (ImageView)findViewById(R.id.UD6_04_imgvwFoto);
  96.                                                 imgview.setVisibility(View.VISIBLE);
  97.                                                 videoview = (VideoView)findViewById(R.id.UD6_04_vidvwVideo);
  98.                                                 videoview.setVisibility(View.GONE);
  99.                                                 break; 
  100.                                         case R.id.UD6_04_rbtnVideo:     // OCULTAMOS AS FOTOS
  101.                                                 imgview = (ImageView)findViewById(R.id.UD6_04_imgvwFoto);
  102.                                                 imgview.setVisibility(View.GONE);
  103.                                                 videoview = (VideoView)findViewById(R.id.UD6_04_vidvwVideo);
  104.                                                 videoview.setVisibility(View.VISIBLE);
  105.                                                 break;
  106.                                 }
  107.                         }
  108.                 });
  109.         }
  110.        
  111.        
  112.         @Override
  113.         protected void onCreate(Bundle savedInstanceState) {
  114.                 super.onCreate(savedInstanceState);
  115.                 setContentView(R.layout.activity_ud6_04__multimedia_foto_video);
  116.                
  117.                 xestionarEventos();
  118.         }
  119. }
  • Liñas 38-39: Nestas liñas obtemos a foto da aplicación do S.O. e a visualiza no ImageView.
  • Liñas 42-44: Nestas liñas obtemos o vídeo do Intent e o cargamos no VideoView e comezamos a reprodución.
  • Liñas 70-71: Evento click sobre o botón. Se está a opción do RadioButton de sacar unha foto lanzamos o Intent ACTION_IMAGE_CAPTURE, esperando o resultado.
  • Liñas 75-76: Evento click sobre o botón. Se está a opción do RadioButton de sacar un vídeo lanzamos o Intent ACTION_VIDEO_CAPTURE, esperando o resultado.

Gardando o Vídeo / Foto

Neste punto imos facer unha modificación da práctica anterior e imos enviar ao Intent información sobre onde debe gardar a foto / vídeo.

Neste caso, o Intent do método onActivityResult NON DEVOLVERÁ NINGÚN DATO.


Caso Práctico

O obxectivo desta práctica é visualizar nun control ImageView / VideoView a imaxe / vídeo obtida dende a aplicación do S.O. Android PERO GARDANDO NA TARXETA SD O RESULTADO DE SACAR ESE VÍDEO / FOTO.

PDM Avanzada Multimedia Gravacion 3.jpg


Neste caso as fotos gardadas se almacenan na tarxeta SD no cartafol PICTURES e os vídeos no cartafol MOVIES.


Creamos a Activity

  • Nome do proxecto: UD6_05_MultimediaFotoVideo
  • Nome da activity: UD6_05_MultimediaFotoVideo.java
  • O código do layout vai ser o mesmo que na activity anterior.


Código da clase UD6_05_MultimediaFotoVideo
Obxectivo: Variación da práctica anterior no que indicamos como dato extra a enviar ó intent que obtén a foto / vídeo onde queremos que o garde.

  1. import java.io.File;
  2.  
  3. import android.app.Activity;
  4. import android.content.Intent;
  5. import android.graphics.Bitmap;
  6. import android.graphics.BitmapFactory;
  7. import android.net.Uri;
  8. import android.os.Bundle;
  9. import android.os.Environment;
  10. import android.provider.MediaStore;
  11. import android.view.View;
  12. import android.view.View.OnClickListener;
  13. import android.widget.Button;
  14. import android.widget.ImageView;
  15. import android.widget.RadioButton;
  16. import android.widget.RadioGroup;
  17. import android.widget.RadioGroup.OnCheckedChangeListener;
  18. import android.widget.VideoView;
  19.  
  20. public class UD6_05_MultimediaFotoVideo extends Activity {
  21.  
  22.         /**
  23.          * Código para verificar que o resultado ven do intent de gravación
  24.          */
  25.         private final int REQUEST_CODE_GRAVACION_OK = 1;
  26.  
  27.         final private String nomeVideo="video.mp4";
  28.         final private String nomeFoto="foto.jpg";
  29.  
  30.        
  31.         /**
  32.      * Obtemos a imaxe ou video que ven da aplicacion Android
  33.      */
  34.         protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  35.                 if (requestCode == REQUEST_CODE_GRAVACION_OK) {
  36.                         if (resultCode == RESULT_OK) {
  37.  
  38.                                 RadioButton rb = (RadioButton) findViewById(R.id.UD6_04_rbtnFoto);
  39.                                 if (rb.isChecked()) { // Saca foto
  40.                                         File ruta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
  41.                                         File arquivo = new File(ruta,nomeFoto);
  42.                                         if (!arquivo.exists()) return;          // Non hai foto
  43.                                        
  44.                                         ImageView imgview = (ImageView) findViewById(R.id.UD6_04_imgvwFoto);
  45.                                         Bitmap bitmap = BitmapFactory.decodeFile(arquivo.getAbsolutePath());
  46.                                         imgview.setImageBitmap(bitmap);
  47.                                        
  48.                                 } else { // Saca vídeo
  49.                                         File ruta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
  50.                                         File arquivo = new File(ruta,nomeVideo);
  51.                                         if (!arquivo.exists()) return;          // Non hai foto
  52.  
  53.                                         VideoView vidview = (VideoView) findViewById(R.id.UD6_04_vidvwVideo);
  54.                                         vidview.setVideoURI(Uri.fromFile(arquivo));
  55.                                         vidview.start();
  56.                                 }
  57.  
  58.                         } else if (resultCode == RESULT_CANCELED) {
  59.                                 // Video ou Foto cancelada
  60.                         } else {
  61.                                 // Fallo na captura do Video ou foto.
  62.                         }
  63.                 }
  64.         }
  65.    
  66.         /**
  67.      * Programa o código dos click´s os botóns
  68.      */
  69.         private void xestionarEventos(){
  70.                 Button gravar = (Button)findViewById(R.id.UD6_04_btnGravarVideoFoto);
  71.                 gravar.setOnClickListener(new OnClickListener(){
  72.  
  73.                         @Override
  74.                         public void onClick(View arg0) {
  75.                                 // TODO Auto-generated method stub
  76.                                 RadioButton rb = (RadioButton)findViewById(R.id.UD6_04_rbtnFoto);
  77.  
  78.                                
  79.                                 if (rb.isChecked()){    // Saca foto
  80.                                         File ruta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
  81.                                         File arquivo = new File(ruta,nomeFoto);
  82.                                        
  83.                                         Intent intento = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  84.                                         intento.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(arquivo));
  85.                                         startActivityForResult(intento, REQUEST_CODE_GRAVACION_OK);
  86.                                        
  87.                                 }
  88.                                 else {  // Grava vídeo
  89.                                         File ruta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
  90.                                         File arquivo = new File(ruta,nomeVideo);
  91.  
  92.                                         Intent intento = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
  93.                                         intento.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(arquivo));
  94.  
  95.                                         startActivityForResult(intento, REQUEST_CODE_GRAVACION_OK);
  96.                                
  97.                                 }
  98.                                
  99.                         }
  100.                        
  101.                 });
  102.  
  103.                 RadioGroup rgroup = (RadioGroup)findViewById(R.id.UD6_04_rgrpOpcions);
  104.                 rgroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {
  105.                        
  106.                         @Override
  107.                         public void onCheckedChanged(RadioGroup group, int checkedId) {
  108.                                 // TODO Auto-generated method stub
  109.                                 ImageView imgview;
  110.                                 VideoView videoview;
  111.                                
  112.                                 switch(checkedId){
  113.                                         case R.id.UD6_04_rbtnFoto:      // OCULTAMOS O VIDEO
  114.                                                 imgview = (ImageView)findViewById(R.id.UD6_04_imgvwFoto);
  115.                                                 imgview.setVisibility(View.VISIBLE);
  116.                                                 videoview = (VideoView)findViewById(R.id.UD6_04_vidvwVideo);
  117.                                                 videoview.setVisibility(View.GONE);
  118.                                                 break; 
  119.                                         case R.id.UD6_04_rbtnVideo:     // OCULTAMOS AS FOTOS
  120.                                                 imgview = (ImageView)findViewById(R.id.UD6_04_imgvwFoto);
  121.                                                 imgview.setVisibility(View.GONE);
  122.                                                 videoview = (VideoView)findViewById(R.id.UD6_04_vidvwVideo);
  123.                                                 videoview.setVisibility(View.VISIBLE);
  124.                                                 break;
  125.                                 }
  126.                         }
  127.                 });
  128.         }
  129.        
  130.        
  131.         @Override
  132.         protected void onCreate(Bundle savedInstanceState) {
  133.                 super.onCreate(savedInstanceState);
  134.                 setContentView(R.layout.activity_ud6_05__multimedia_foto_video);
  135.                
  136.                 xestionarEventos();
  137.         }
  138. }


  • Liñas 40-42: Obtemos un obxecto File que apunta ó nome da imaxe gardada. Este dato foi enviado como dato extra ó intent cando lanzamos a aplicación de obter unha foto.
  • Liña 45: Obtemos un obxecto da clase BitMap a partires do obxecto File.
  • Liñas 49-51: Obtemos un obxecto File que apunta ó nome do vídeo gardado. Este dato foi enviado como dato extra ó intent cando lanzamos a aplicación de obter o vídeo.
  • Liña 54: Obtemos a Uri a partires do obxecto File.
  • Liña 84: Enviamos como información extra no Intent a ruta onde debe gardar a foto sacada.
  • Liña 93: Enviamos como información extra no Intent a ruta onde debe gardar o vídeo sacado.


Importante: Como xa comentamos antes, getData() no Intent do método onActivityResult() non trae nada.

Información Extra

Como comentamos antes podemos enviar o Intent diversa información (como a ruta onde gardar a foto / vídeo).

Outra información que podemos enviar:

  • No caso de captura de fotos, podemos pasarlle o Intent (chamando o método putExtra da clase Intent):
MediaStore.EXTRA_OUTPUT : Directorio e arquivo (URI) onde se vai gardar a foto. Se non se especifica, o Intent gardará o imaxe cun nome e directorio por defecto que ven especificado no intent de retorno Intent.getData().
  • No caso do vídeo, algúns dos datos que podemos enviarlle a Intent son:
MediaStore.EXTRA_OUTPUT : Directorio e arquivo (URI) onde se vai gardar o vídeo.
Se non se especifica, o Intent gardará o imaxe cun nome e directorio por defecto que ven especificado no intent de retorno Intent.getData().
MediaStore.EXTRA_VIDEO_QUALITY: Calidade da imaxe. Se valor 0 sería calidad baixa (para mms) e se vale 1 calidade alta.
MediaStore.EXTRA_DURATION_LIMIT: Nº de segundos máximos para gravación.
MediaStore.EXTRA_SIZE_LIMIT: Tamaño máximo do arquivo en bytes.


Control para o VideoView

  • Cando creamos o layout e arrastramos o VideoView ó mesmo, podemos facer uso doutro control asociado ó mesmo que permite ter as opcións de 'Pause', 'Stop',...
Este control denomínase MediaController.


  • Para asocialo a un VideoView:
  1. MediaController controller = new MediaController(this);
  2. VideoView videoview = (VideoView)findViewById(R.id.vidvwVideo);
  3.  
  4. videoview.setMediaController(controller);


  • Se o aplicamos á nosa práctica:
  1.        import android.widget.MediaController;
  2.  
  3.         private void controlVideo(){
  4.                 MediaController controller = new MediaController(this);
  5.                 VideoView videoview = (VideoView)findViewById(R.id.UD6_04_vidvwVideo);
  6.                 videoview.setMediaController(controller);
  7.  
  8.         }
  9.        
  10.         @Override
  11.         protected void onCreate(Bundle savedInstanceState) {
  12.                 super.onCreate(savedInstanceState);
  13.                 setContentView(R.layout.activity_ud6_04__multimedia_foto_video);
  14.                
  15.                 controlVideo();
  16.                 xestionarEventos();
  17.         }



Gardando o Vídeo / Foto. Caso especial API >= 23 e API >= 24

  • Como comentamos antes, se queremos gardar unha imaxe/vídeo nun cartafol da SDCard e temos unha API >= 23 temos que solicitar dito permiso por programación.
Este punto xa está explicado neste punto da Wiki.
Neste caso necesitaríamos pedir permiso para escribir na tarxeta SDCard (ao facelo xa temos o permiso de lectura tamén). Mirar como facelo no enlace anterior.


  • Pero a maiores temos un problema, xa que se executamos o código anterior nun S.O. Android cunha API >=24 daranos unha excepción android.os.FileUriExposedException.
Isto é debido a que a partires desta versión xa non podemos empregar unha Uri como forma de envío á aplicación da cámara, xa que esta Uri está sendo compartida pola nosa aplicación e a aplicación da cámara e a partires desa versión non está permitido.
Para solucionalo temos que crear un provider (un recurso de Android que permite xestionar o acceso a información dende diferentes aplicacións, permitindo o acceso doutras aplicación para recuperar o gardar información na aplicación que ofrece o provider).
  • Paso 1: Definimos no AndroidManifiest.xml o provider da forma:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3.     package="es.cursoandroid.cifprodolfoucha.aprendiendo">
  4.  
  5.     <uses-permission android:name="android.permission.CALL_PHONE" />
  6.     <uses-permission android:name="android.permission.INTERNET" />
  7.     <uses-permission android:name="android.permission.WAKE_LOCK" />
  8.     <uses-permission android:name="android.permission.READ_CONTACTS" />
  9.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  10.  
  11.  
  12.  
  13.     <application
  14.         android:allowBackup="true"
  15.         android:icon="@mipmap/ic_launcher"
  16.         android:label="@string/app_name"
  17.         android:roundIcon="@mipmap/ic_launcher_round"
  18.         android:supportsRtl="true"
  19.         android:theme="@style/AppTheme">
  20.  
  21.         <provider
  22.             android:name="android.support.v4.content.FileProvider"
  23.             android:authorities="${applicationId}.provider"
  24.             android:exported="false"
  25.             android:grantUriPermissions="true">
  26.         </provider>


  • Na liña 23, ${applicationId} vaise substituír pola propiedade applicationId do arquivo build.gradle que coincide có nome do paquete.


  • Paso 2: Debemos de definir un arquivo en /res/xml/ que terá as rutas nas que deixaremos escribir.
Podemos consultar as diferentes rutas neste enlace.
No noso caso imos deixar escribir nos cartafoles '/sdcard/Movies' y '/sdcard/Pictures':
Arquivo /res/xml/provides_path.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <paths xmlns:android="http://schemas.android.com/apk/res/android">
  3.     <external-path name="external_files_pictures" path="Pictures/" />
  4.     <external-path name="external_files_movies" path="Movies/" />
  5. </paths>
Fixarse que neste caso estamos a empregar a etiqueta <external-path...> que vai devolver a seguinte ruta: Environment.getExternalStorageDirectory(). Sobre dita ruta estamos engadindo os cartafoles 'Pictures/' e 'Movies/' para crear dous 'external-path' que serán os path´s que se poderán compartir en forma de Uri entre aplicacións.
  • Paso 3: Modificamos o posto no arquivo AndroidManifiest.xml para que teña en conta as rutas postas no arquivo anterior:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3.     package="es.cursoandroid.cifprodolfoucha.aprendiendo">
  4.  
  5.     <uses-permission android:name="android.permission.CALL_PHONE" />
  6.     <uses-permission android:name="android.permission.INTERNET" />
  7.     <uses-permission android:name="android.permission.WAKE_LOCK" />
  8.     <uses-permission android:name="android.permission.READ_CONTACTS" />
  9.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  10.  
  11.  
  12.  
  13.     <application
  14.         android:allowBackup="true"
  15.         android:icon="@mipmap/ic_launcher"
  16.         android:label="@string/app_name"
  17.         android:roundIcon="@mipmap/ic_launcher_round"
  18.         android:supportsRtl="true"
  19.         android:theme="@style/AppTheme">
  20.  
  21.         <provider
  22.             android:name="android.support.v4.content.FileProvider"
  23.             android:authorities="${applicationId}.provider"
  24.             android:exported="false"
  25.             android:grantUriPermissions="true">
  26.             <meta-data
  27.                 android:name="android.support.FILE_PROVIDER_PATHS"
  28.                 android:resource="@xml/provides_path" />
  29.  
  30.         </provider>



  • Paso 4: Modificamos a aplicación para que no caso de que esteamos sobre un S.O. Api >=24 faga uso do método getUriForFile o cal vai facer uso do provider definido antes. Desta forma a cámara vai poder acceder tamén a este mesmo Uri para gardar a foto/vídeo:
Activity UD6_05_MultimediaFotoVideo.java modificada.
  1. package es.cursoandroid.cifprodolfoucha.aprendiendo.Multimedia;
  2.  
  3. import android.Manifest;
  4. import android.app.Activity;
  5. import android.content.Intent;
  6. import android.content.pm.PackageManager;
  7. import android.graphics.Bitmap;
  8. import android.graphics.BitmapFactory;
  9. import android.net.Uri;
  10. import android.os.Build;
  11. import android.os.Bundle;
  12. import android.os.Environment;
  13. import android.provider.MediaStore;
  14. import android.view.View;
  15. import android.widget.Button;
  16. import android.widget.ImageView;
  17. import android.widget.RadioButton;
  18. import android.widget.RadioGroup;
  19. import android.widget.Toast;
  20. import android.widget.VideoView;
  21.  
  22. import java.io.File;
  23.  
  24. import es.cursoandroid.cifprodolfoucha.aprendiendo.R;
  25.  
  26. import static android.support.v4.content.FileProvider.getUriForFile;
  27.  
  28. public class UD6_05_MultimediaFotoVideo extends Activity {
  29.  
  30.     private final int REQUEST_CODE_GRAVACION_OK = 1;    //Código para verificar que o resultado ven do intent de gravación
  31.     final private String nomeVideo="video.mp4";
  32.     final private String nomeFoto="foto.jpg";
  33.     private final int CODIGO_IDENTIFICADOR=1; // Usado por si necesitamos diferentes permisos, para identificar cual de ellos es
  34.  
  35.     /**
  36.      * Obtemos a imaxe ou video que ven da aplicacion Android
  37.      */
  38.     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  39.         if (requestCode == REQUEST_CODE_GRAVACION_OK) {
  40.             if (resultCode == RESULT_OK) {
  41.  
  42.                 RadioButton rb = (RadioButton) findViewById(R.id.UD6_04_rbtnFoto);
  43.                 if (rb.isChecked()) { // Saca foto
  44.                     File ruta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
  45.                     File arquivo = new File(ruta,nomeFoto);
  46.                     if (!arquivo.exists()) return;          // Non hai foto
  47.  
  48.                     ImageView imgview = (ImageView) findViewById(R.id.UD6_04_imgvwFoto);
  49.                     Bitmap bitmap = BitmapFactory.decodeFile(arquivo.getAbsolutePath());
  50.                     imgview.setImageBitmap(bitmap);
  51.                 } else { // Saca vídeo
  52.                     File ruta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
  53.                     File arquivo = new File(ruta,nomeVideo);
  54.                     if (!arquivo.exists()) return;          // Non hai foto
  55.  
  56.                     VideoView vidview = (VideoView) findViewById(R.id.UD6_04_vidvwVideo);
  57.                     vidview.setVideoURI(Uri.fromFile(arquivo));
  58.                     vidview.start();
  59.                 }
  60.  
  61.             } else if (resultCode == RESULT_CANCELED) {
  62.                 // Video ou Foto cancelada
  63.             } else {
  64.                 // Fallo na captura do Video ou foto.
  65.             }
  66.         }
  67.     }
  68.  
  69.     public void pedirPermiso(){
  70.  
  71.         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  72.             requestPermissions( new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},CODIGO_IDENTIFICADOR);
  73.         }
  74.  
  75.     }
  76.  
  77.     @Override
  78.     public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
  79.  
  80.         switch (requestCode) {
  81.             case CODIGO_IDENTIFICADOR: {
  82.                 // Se o usuario premeou o boton de cancelar o array volve cun null
  83.                 Button btn = findViewById(R.id.UD6_04_btnGravarVideoFoto);
  84.                 if (grantResults.length > 0
  85.                         && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  86.                     btn.setEnabled(true);
  87.                     // PERMISO CONCEDIDO
  88.                 } else {
  89.                     // PERMISO DENEGADO
  90.                     btn.setEnabled(false);      //Desabilitamos o botón se non temos o permiso de escritura
  91.                     Toast.makeText(this,"É NECESARIO O PERMISO DE ESCRITURA NA SDCARD",Toast.LENGTH_LONG).show();
  92.                 }
  93.                 return;
  94.             }
  95.  
  96.             // Comprobamos os outros permisos
  97.  
  98.         }
  99.     }
  100.  
  101.     /**
  102.      * Programa o código dos click´s os botóns
  103.      */
  104.     private void xestionarEventos(){
  105.         Button gravar = (Button)findViewById(R.id.UD6_04_btnGravarVideoFoto);
  106.         gravar.setOnClickListener(new View.OnClickListener(){
  107.  
  108.             @Override
  109.             public void onClick(View arg0) {
  110.                 // TODO Auto-generated method stub
  111.                 RadioButton rb = (RadioButton)findViewById(R.id.UD6_04_rbtnFoto);
  112.  
  113.  
  114.                 if (rb.isChecked()){    // Saca foto
  115.                     File ruta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
  116.                     File arquivo = new File(ruta,nomeFoto);
  117.  
  118.                     Uri contentUri=null;
  119.                     if (Build.VERSION.SDK_INT >= 24) {
  120.                         contentUri = getUriForFile(getApplicationContext(), getApplicationContext()
  121.                                 .getPackageName() + ".provider", arquivo);
  122.                     }
  123.                     else {
  124.                         contentUri = Uri.fromFile(arquivo);
  125.                     }
  126.  
  127.                     Intent intento = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  128.                     intento.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
  129.  
  130.                     startActivityForResult(intento, REQUEST_CODE_GRAVACION_OK);
  131.                 }
  132.                 else {  // Grava vídeo
  133.                     File ruta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
  134.                     File arquivo = new File(ruta,nomeVideo);
  135.  
  136.                     Uri contentUri=null;
  137.                     if (Build.VERSION.SDK_INT >= 24) {
  138.                         contentUri = getUriForFile(getApplicationContext(), getApplicationContext()
  139.                                 .getPackageName() + ".provider", arquivo);
  140.                     }
  141.                     else {
  142.                         contentUri = Uri.fromFile(arquivo);
  143.                     }
  144.  
  145.                     Intent intento = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
  146.                     intento.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
  147.  
  148.                     startActivityForResult(intento, REQUEST_CODE_GRAVACION_OK);
  149.                 }
  150.  
  151.             }
  152.  
  153.         });
  154.  
  155.         RadioGroup rgroup = (RadioGroup)findViewById(R.id.UD6_04_rgrpOpcions);
  156.         rgroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
  157.  
  158.             @Override
  159.             public void onCheckedChanged(RadioGroup group, int checkedId) {
  160.                 // TODO Auto-generated method stub
  161.                 ImageView imgview;
  162.                 VideoView videoview;
  163.  
  164.                 switch(checkedId){
  165.                     case R.id.UD6_04_rbtnFoto:      // OCULTAMOS O VIDEO
  166.                         imgview = (ImageView)findViewById(R.id.UD6_04_imgvwFoto);
  167.                         imgview.setVisibility(View.VISIBLE);
  168.                         videoview = (VideoView)findViewById(R.id.UD6_04_vidvwVideo);
  169.                         videoview.setVisibility(View.GONE);
  170.                         break;
  171.                     case R.id.UD6_04_rbtnVideo:     // OCULTAMOS AS FOTOS
  172.                         imgview = (ImageView)findViewById(R.id.UD6_04_imgvwFoto);
  173.                         imgview.setVisibility(View.GONE);
  174.                         videoview = (VideoView)findViewById(R.id.UD6_04_vidvwVideo);
  175.                         videoview.setVisibility(View.VISIBLE);
  176.                         break;
  177.                 }
  178.             }
  179.         });
  180.     }
  181.  
  182.     @Override
  183.     protected void onCreate(Bundle savedInstanceState) {
  184.         super.onCreate(savedInstanceState);
  185.         setContentView(R.layout.activity_ud05_01__foto__reproducir);
  186.  
  187.         pedirPermiso();
  188.         xestionarEventos();
  189.     }
  190. }
  • Liñas 69-75: Se a API >=23 hai que pedir permiso de escritura por código.
  • Liñas 86/90: En caso de que o usuario non dea permiso, desabilitamos o botón.
  • Liñas 118-125: En caso de que a API>=24 necesitamos ao 'método getUriForFile' para obter a URI que lle imos pasar como dato extra a cámara de fotos. En caso contrario o facemos como ata o de agora.
Fixarse como o segundo parámetro pon: getApplicationContext().getPackageName() + ".provider" , que se corresponde coa entrada android:authorities="${applicationId}.provider" do AndroidManifiest.xml.
  • Liñas 136-143: O mesmo para o caso do vídeo.


  • A forma anterior é unha das posibilidades que temos de dar permiso a certa Uri para que sexa compartida. Neste caso o facemos enviamos con setData a Uri.
Existen outra formas como podemos consultar neste enlace.


  • Máis información:

Métodos útiles no manexo de Imaxes

  • Bitmap.createScaledBitmap(bitmaporixinal, witdh, height, boolean filter): devolve un obxecto da clase Bitmap e vainos servir para escalar un bitmap a outro tamaño indicado por width e height.

O filter debería ser posto a true se facemos a imaxe máis grande e a false se a facemos máis pequena. Para determinar o tamaño adecuado do Bitmap en función dos puntos por polgada do dispositivo onde nos atopamos podemos facer uso da propiedade densityDpi:

  1.         switch (getResources().getDisplayMetrics().densityDpi) {
  2.                                         case DisplayMetrics.DENSITY_LOW:
  3.                                             break;
  4.                                         case DisplayMetrics.DENSITY_MEDIUM:
  5.                                             break;
  6.                                         case DisplayMetrics.DENSITY_HIGH:
  7.                                             break;
  8.                                         case DisplayMetrics.DENSITY_XHIGH:
  9.                                             break;
  10.         }

En función do valor de densidade escalaremos a imaxe a un tamaño adecuado tendo en conta a proporción:

  • xhdpi: 2.0
  • hdpi: 1.5
  • mdpi: 1.0 (baseline)
  • ldpi: 0.75


Nota: Normalmente cando facemos fotos e queremos visualizalas todas xuntas (por exemplo utilizando un horizontalScrollView) faise uso deste método para ter unha imaxe en pequeno da foto e despois cargar a imaxe orixinal cando a visualicemos a pantalla completa.


  • Obxectobitmap.compress(CompressFormat.JPEG, 100,os): comprime un bitmap e o escribe a disco utilizando un FileOutputStream. O primeiro parámetro indica o tipo de compresión (se temos transparencias na imaxe orixinal deberemos usar BMP), o segundo indica o nivel de compresión (se é 50 sería o 50%, no exemplo o deixaría tal cal) e o terceiro parámetro é un obxecto da clase FileOutputStream para pasalo a disco.

Este método pode servirnos para pasar un bitmap a disco utilizando un obxecto da clase File (o veremos na unidade de Datos Persistentes) e obtendo o FileOutputStream a partires del. É importante asinarlle unha extensión ó arquivo que vai ser a imaxe gardada.

Se a foto a temos asinada a un ImageView e queremos recuperala coma un obxecto da clase Bitmap teremos que facer:

  1.         imgview.setDrawingCacheEnabled(true);
  2.         Bitmap imaxe = imgview.getDrawingCache();

Sendo imgview o obxecto que fai referencia ó ImageView.


O proceso contrario, é dicir, cargar unha foto nun ImageView será o seguinte (o veremos outra vez na unidade de datos persistentes):

  1.         Bitmap bitmap = BitmapFactory.decodeFile(Obxecto_file_apuntando_á_imaxe_gardada);
  2.         img.setImageBitmap(bitmap);

Sendo img un obxecto da clase ImageView.

Métodos útil no manexo de Vídeos

Pode resultarnos necesario a partires dun vídeo obter unha foto del.

Para facelo debemos de utilizar a clase ThumbnailUtils

Vexamos un exemplo:

  1. BitMap preview_bitmap = ThumbnailUtils.createVideoThumbnail(uri_al_vídeo.toString(), Thumbnails.MICRO_KIND);


  • Queda como 'exercicio' que busquedes en Internet como cargar un vídeo gardado localmente no proxecto, no cartafol /res/raw/

Visualización de múltiples imaxes

Pode darse o caso de que necesitemos visualizar múltiples imaxes na nosa activity.

Nota: Como está comentado en liñas anteriores, o lóxico será ter unha versión 'en pequeno' da foto para non encher a memoria utilizando o método compress da clase BitMap ou ben utilizando o método Bitmap.createScaledBitmap, como está feito no exemplo que ven a continuación.


Temos varias posibilidades para facer isto:

  • Actualización 2018
A partires da API 22 aparece o Widget RecyclerView que permite facer o mesmo que o HorizontalScrollView pero de forma moito máis eficiente.
Lembrar que dito compoñente está dentro das opción de investigación para desenvolver a práctica.
Para cargar dito compoñente nunha API inferior á 22 (vos tedes que facer a aplicación cun API>=19) teredes que facer uso dunha biblioteca de compatibilidade, como xa vimos na Wiki.


Neste apartado imos ver como utilizar un HorizontalScrollView.

Caso Práctico

O obxectivo desta práctica é ver como podemos utilizar o HorizontalScrollView para visualizar imaxes en pequeno.

PDM Avanzada Multimedia Gravacion 6.jpg

Como o seu propio nome indica, o HorizontalScrollView é un control que permite facer un scroll horizontal de View´s.

A idea é ter dentro deste control un LinearLayout coas imaxes.

Cada imaxe vai ter un layout cun tamaño (o tamaño da miniatura) e xestionaremos o evento de Click sobre a imaxe en miniatura para ver dita imaxe nun ImageView en grande.

Preparación

Será necesario copiar ó cartafol da SD onde o S.O. Android garda as imaxes por defecto, dúas imaxes calquera de nome foto1.jpg e foto2.jpg.

Utilizamos a clase EnvironMent (Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)) para indicar a ruta onde se atopan as fotos.

Normalmente esta ruta se atopa en /sdcard/Pictures.

  • Se utilizades o emulador podedes copiar as fotos utilizando a perspectiva DDMS.
  • Se estades a utilizar un dispositivo real teredes que copiar as fotos conectando o dispositivo ó computador.


O alumno é libre de utilizar outra ruta calquera modificando o código convenientemente.

Creamos a Activity

  • Nome do proxecto: UD6_06_MultimediaHorizontalScrollView
  • Nome da activity: UD6_06_MultimediaHorizontalScrollView.java


Código do layout xml

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.    xmlns:tools="http://schemas.android.com/tools"
  3.    android:layout_width="match_parent"
  4.    android:layout_height="match_parent"
  5.    tools:context="${relativePackage}.${activityClass}" >
  6.  
  7.     <HorizontalScrollView
  8.        android:id="@+id/UD6_06_hsviewFotosPai"
  9.        android:layout_width="match_parent"
  10.        android:layout_height="wrap_content"
  11.        android:layout_alignParentTop="true"
  12.        android:layout_centerHorizontal="true"
  13.        android:layout_marginTop="26dp" >
  14.        
  15.        <LinearLayout
  16.                    android:id="@+id/UD6_06_linearLayoutFotosFillo"
  17.                    android:layout_width="wrap_content"
  18.                    android:layout_height="wrap_content"
  19.                    android:orientation="horizontal" />
  20.  
  21.     </HorizontalScrollView>
  22.  
  23.     <ImageView
  24.        android:id="@+id/UD6_06_imgvwFotoAmpliada"
  25.        android:layout_width="500dp"
  26.        android:layout_height="500dp"
  27.        android:layout_alignParentBottom="true"
  28.        android:layout_centerHorizontal="true"
  29.        android:layout_marginBottom="26dp"
  30.        android:src="@drawable/ic_launcher" />
  31.  
  32. </RelativeLayout>

Como vemos temos un HorizontalScrollView e un LinearLayout dentro do mesmo.

Código da clase UD6_06_MultimediaHorizontalScrollView
Obxectivo: Carga nun HorizontalScrollView dúas fotos gardadas na tarxeta SD do dispositivo.
Nota: Vos dará un erro xa que fai uso dunha clase explicada a continuación.

  1. import java.io.File;
  2.  
  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.os.Environment;
  6. import android.widget.LinearLayout;
  7.  
  8. public class UD6_06_MultimediaHorizontalScrollView extends Activity {
  9.  
  10.         @Override
  11.         protected void onCreate(Bundle savedInstanceState) {
  12.                 super.onCreate(savedInstanceState);
  13.                 setContentView(R.layout.activity_ud6_06__multimedia_horizontal_scroll_view);
  14.        
  15.                 LinearLayout linear = (LinearLayout)findViewById(R.id.UD6_06_linearLayoutFotosFillo);
  16.                
  17.                 String ruta = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath();
  18.                
  19.                 UD6_06_ImaxeHorizontalScrollView imaxe = new UD6_06_ImaxeHorizontalScrollView(this, ruta+File.separator+"foto1.jpg");
  20.                 linear.addView(imaxe.getLayout());
  21.                 imaxe = new UD6_06_ImaxeHorizontalScrollView(this, ruta+File.separator+"foto2.jpg");
  22.                 linear.addView(imaxe.getLayout());
  23.  
  24.         }
  25. }
  • Liña 15: Obtemos a referencia ó LinearLayout que se atopa dentro do HorizontalScrollView.
  • Liña 17: Ruta onde se atopan as imaxes.
  • Liña 19,21: Creamos dous obxectos da clase UD6_06_ImaxeHorizontalScrollView (explicada posteriormente).
  • Liñas 20,22: Engadimos ditas imaxes ó LinearLayout.

Creamos o ImageView personalizado

Agora imos explicar a clase UD6_06_ImaxeHorizontalScrollView.

A idea é moi sinxela.

Vou engadir ó LinearLayout obxectos da clase ImageView.

A diferenza é que vou personalizar ditos obxectos para que estean (a imaxe) dentro dun Layout creado por min y cun tamaño concreto (o veremos no código).

Ademais xestionaremos o evento Click sobre a imaxe para facer que apareza en grande no ImageView da Activity principal.

O que hai que ter moi claro é que esta clase representa cada unha das imaxes en miniatura que vemos dentro do control HorizontalScrollView.

Código da clase UD6_06_ImaxeHorizontalScrollView
Obxectivo: Facemos un ImageView personalizado cun tamaño específico e xestionamos o evento Click sobre a imaxe.

  1. import java.io.File;
  2.  
  3. import android.graphics.Bitmap;
  4. import android.graphics.BitmapFactory;
  5. import android.view.Gravity;
  6. import android.view.View;
  7. import android.view.View.OnClickListener;
  8. import android.view.ViewGroup.LayoutParams;
  9. import android.widget.ImageView;
  10. import android.widget.LinearLayout;
  11.  
  12. public class UD6_06_ImaxeHorizontalScrollView extends ImageView implements OnClickListener {
  13.         protected UD6_06_MultimediaHorizontalScrollView context;
  14.         private File file;
  15.         private String path;
  16.         private LinearLayout layout;
  17.          
  18.         /**
  19.          * Crea unha imaxe e a engade nun layout que vai ser o que visualice o HorizontalView
  20.          * @param context
  21.          * @param path: ruta a imaxe
  22.          */
  23.         public UD6_06_ImaxeHorizontalScrollView(UD6_06_MultimediaHorizontalScrollView context,String path)  {
  24.                 super(context);
  25.                 this.context=context;
  26.                 this.path=path;
  27.                 file = new File(path);
  28.                  
  29.                 setOnClickListener(this);
  30.                 crearLayout();
  31.         }
  32.          
  33.         private void crearLayout() {
  34.                 LinearLayout layout = new LinearLayout(context);
  35.                 layout.setLayoutParams(new LayoutParams(135, 135));
  36.                 layout.setGravity(Gravity.CENTER);
  37.  
  38.                 this.setLayoutParams(new LayoutParams(120, 120));       // TAMAÑO DA IMAXE
  39.                 this.setScaleType(ImageView.ScaleType.CENTER_CROP);
  40.                 Bitmap bit = BitmapFactory.decodeFile(file.getAbsolutePath());
  41.                 if (bit==null) { // Non a pode cargar
  42.                    this.layout=layout;
  43.                    return;
  44.                 }
  45.                 Bitmap bitmap;
  46.                 bitmap = Bitmap.createScaledBitmap(bit, 220, 220,false);
  47.                 this.setImageBitmap(bitmap);
  48.  
  49.                 layout.addView(this);
  50.                 this.layout = layout;
  51.         }
  52.  
  53.         public LinearLayout getLayout(){
  54.                 return layout;
  55.         }
  56.  
  57.         public File getFile(){
  58.                 return file;
  59.         }
  60.         public String getPath(){
  61.                 return path;
  62.         }
  63.         @Override
  64.         public void onClick(View v) {
  65.                 // TODO Auto-generated method stub
  66.                  
  67.                 Bitmap bp = BitmapFactory.decodeFile(getPath());
  68.                 ImageView imgview = (ImageView)context.findViewById(R.id.UD6_06_imgvwFotoAmpliada);
  69.                 imgview.setImageBitmap(bp);
  70.         }
  71.                  
  72.  
  73. }
  • Liña 12: Fixarse como facemos unha clase que deriva de ImageView e implementa a interface onClickListener para xestionar o evento click sobre a imaxe
  • Liña 23: No constructor recibimos unha instancia da clase que utiliza o ImageView. Isto é necesario xa que cando prememos sobre a imaxe en miniatura temos que atopar o ImageView da activiry para cargar a imaxe en grande. Como segundo parámetro enviamos a ruta ó arquivo de imaxe.
  • Liñas 25-27: Gardamos os datos enviados.
  • Liña 29: Facemos que o evento de click se xestione dentro da clase.
  • Liña 30: Chamamos ó método que vai crea o Layout onde vai ir a imaxe.
  • Liñas 33-51: Creamos o layout (LinearLayout) que vai albergar a foto.
  • Liñas 34-36: Layout que alberga a imaxe.
  • Liñas 38-39: Tamaño e tipo de escala da imaxe dentro do layout.
  • Liña 40-47: Cargamos a imaxe dende a SD Externa e a asignamos ó ImageView.
  • Liñas 48-51: Engadimos o layout creado o ImageView cargado de disco.
  • Liñas 64-71: Xestionamos o evento do Click sobre a imaxe. Buscamos o control ImageView da activity principal (UD6_06_imgvwFotoAmpliada) e cargamos a partires do path a imaxe no ImageView.







-- Ángel D. Fernández González e Carlos Carrión Álvarez -- (2014).