martes, 27 de agosto de 2013

Galería de Imágenes usando swipe



Como crear una Galería de Imágenes usando "GridView" y "Swipe"
(How create image gallery using gridview and swipe)

Intentaremos crear una galería de imagen bastante sencilla, con la funcionalidad de:
  • Mostrar la miniaturas en un "GridView".
  • Seleccionar una imagen para verla en tamaño original.
  • una vez seleccionada una imagen podremos hacer "swipe" a la derecha o a la izquierda para continuar viendo las imágenes de la galería en tamaño original.
  • Al volver a la galería de miniaturas, siempre tendremos seleccionada la ultima imagen que vimos en tamaño original.  

Para ello crearemos solamente tres activities.
- MainActivity (Se crea por defecto cuando creamos el proyecto)
- ShowGalleryActivity
- SwipeImageActivity

Y ademas crearemos cuatro layouts.
- activity_main (Se crea por defecto cuando creamos el proyecto)
- images_gallery (Contiene el GridView)
- show_image (Es el contenedor de la imagen original, con algunos textos de ayuda)
- swipe_image_layout (Contiene el componente ViewPager, donde cargaremos el layout show_image, con las imágenes originales para hacer el efecto de "swipe").

Las imágenes que utilizaremos para esta galería las colocaremos, en una de nuestras carpetas de recursos, en nuestro caso drawable-xhdpi

Para este tutorial hemos usado Android Studio (I/O Preview) 0.2.5

1.- Después de haber creado un nuevo projecto, copiaremos nuestras imágenes a la carpeta de recursos drawable-xhdpi.
2.- A continuación creamos un layout llamado images_gallery




3.- Creamos una Activity llamada ShowGalleryActivity y la enlazamos con el 
images_gallery layout (setContentView(R.layout.images_gallery);)

A continuación el código con los comentarios suficientes para que se pueda entender.
public class ShowGalleryActivity extends Activity {

    public static int mSelected = 0;
    private GridView gridview;
    // Hacemos referencia a nuestras imagenes en miniatura de la carpeta de recursos
    public static Integer[] mImagesIds = {
            R.drawable.i1_thumb, R.drawable.i2_thumb,
            R.drawable.i3_thumb, R.drawable.i4_thumb,
            R.drawable.i5_thumb, R.drawable.i6_thumb,
            R.drawable.i7_thumb, R.drawable.i8_thumb,
            R.drawable.i9_thumb, R.drawable.i10_thumb,
            R.drawable.i11_thumb, R.drawable.i12_thumb,
            R.drawable.i13_thumb, R.drawable.i14_thumb,
            R.drawable.i15_thumb, R.drawable.i16_thumb,
            R.drawable.i17_thumb, R.drawable.i18_thumb,
            R.drawable.i10_thumb, R.drawable.i20_thumb,
            R.drawable.i21_thumb, R.drawable.i22_thumb,
            R.drawable.i23_thumb, R.drawable.i24_thumb,
            R.drawable.i25_thumb, R.drawable.i26_thumb,
            R.drawable.i27_thumb, R.drawable.i28_thumb,
            R.drawable.i29_thumb, R.drawable.i30_thumb,
            R.drawable.i31_thumb
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.images_gallery);

        //Hacemos referncia nuestro GridView
        gridview = (GridView) findViewById(R.id.gridview);
        //Asignamos el ImageAdapter que hemos creado en esta misma clase al GridView
        gridview.setAdapter(new ImageAdapter(this));
        //Nos movemos al elemento seleccionado del GridView
        gridview.setSelection(mSelected);
    }
    @Override
    protected void onStart() {
        super.onStart();
        gridview = (GridView) findViewById(R.id.gridview);
        gridview.setAdapter(new ImageAdapter(this));
        gridview.setSelection(mSelected);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.show_gallery_activity, menu);
        return true;
    }

    //ImageAdapter para almacenar las imagemes en el GridView
    public class ImageAdapter extends BaseAdapter {
        private Context mContext;
        public ImageAdapter(Context c) {
            mContext = c;
        }
        public int getCount() {
            return mImagesIds.length;
        }
        public Object getItem(int position) {
            return null;
        }
        public long getItemId(int position) {
            return 0;
        }

        // Creamos un ImageView por cada imagen miniatura referenciada en nuestro ImageAdapter
        public View getView(final int position, View convertView, ViewGroup parent) {
            ImageView imageView;
            if (convertView == null) {  // if it's not recycled, initialize some attributes
                imageView = new ImageView(mContext);
                imageView.setLayoutParams(new GridView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 130));
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                    imageView.setCropToPadding(true);
                } else {
                    imageView.setScaleType(ImageView.ScaleType.FIT_XY);
                }
                imageView.setPadding(2, 2, 2, 2);
            } else {
                imageView = (ImageView) convertView;
            }
            //Asignamos a cada ImageView una imagen de nuestro "Array" de recursos
            //utilizamos "setImageResource" ya que nuestras imagenes estan almacenadas en una
            //carpeta de recursos en nuestro proyecto.
            // "mImagesIds" es un Array de enteros, ya que almacena el Id del recurso, no la imagen en si.
            imageView.setImageResource(mImagesIds[position]);

            //En el evento click del ImageView obtenemos el indice de la imagen seleccionada
            imageView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mSelected = (Integer) view.getTag();
                    notifyDataSetChanged();

                    String index = String.valueOf(position);
                    Bundle extras = new Bundle();

                    //Pasamos el indice de la imagen seleccionada a la activity que se encarga de mostrar la image Original
                    //y hacer el "swipe"
                    extras.putString("position", index);
                    startActivity(new Intent(ShowGalleryActivity.this, SwipeImageActivity.class).putExtras(extras).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
                }
            });
            try {
                imageView.setTag(position);
                //Ponemos un borde de color naranja a la imagen en miniatura seleccionada en el GrisView
                if (position == mSelected) {
                    imageView.setBackgroundColor(Color.parseColor("#ff6203"));
                } else {
                    imageView.setBackgroundColor(Color.TRANSPARENT);
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return imageView;
        }
    }
}


5.- A continuación creamos un layout llamado swipe_images_layout que servirá de contenedor de la colección de imágenes


    

6.- Creamos otro layout con la estructura de cada elemento de la colección de imágenes.


    

    

        
    

    

        
    


Nota: Aquí usamos el componente <android.support.v4.view.ViewPager> por esta razón, debemos copiar en la carpeta lib de nuestro proyecto la librearía: android-support-v4.jar  

6.- Creamos una activity llamada SwipeImageActivity. A continuación les dejo el código con los comentarios suficientes para que se pueda entender.

public class SwipeImageActivity extends Activity {

    //Hacemos referencia a nuestras imagenes originales de la carpeta de recursos
    public static Integer[] mImagesIds = {
            R.drawable.i1, R.drawable.i2,
            R.drawable.i3, R.drawable.i4,
            R.drawable.i5, R.drawable.i6,
            R.drawable.i7, R.drawable.i8,
            R.drawable.i9, R.drawable.i10,
            R.drawable.i11, R.drawable.i12,
            R.drawable.i13, R.drawable.i14,
            R.drawable.i15, R.drawable.i16,
            R.drawable.i17, R.drawable.i18,
            R.drawable.i10, R.drawable.i20,
            R.drawable.i21, R.drawable.i22,
            R.drawable.i23, R.drawable.i24,
            R.drawable.i25, R.drawable.i26,
            R.drawable.i27, R.drawable.i28,
            R.drawable.i29, R.drawable.i30,
            R.drawable.i31
    };

    private boolean hideSwipeText;
    private String[] imagesDescriptions;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.swipe_images_layout);

        //Optenenos del GridView de la activity anterior el indice de la imagen que hemos
        //seleccionado
        String i = getIntent().getStringExtra("position");
        //Lo convertimos a entero
        int index = Integer.parseInt(i);

        //Obtenemos la decripcion de la imagen seleccionada de una lista en la carpeta values\arrays.xml
        imagesDescriptions = getResources().getStringArray(R.array.images_descriptions);

        SwipeImagePagerAdapter swipeNewsAdapter = new SwipeImagePagerAdapter();
        ViewPager newsPager = (ViewPager) findViewById(R.id.swipe_pager);
        newsPager.setAdapter(swipeNewsAdapter);
        newsPager.setCurrentItem(index);

        newsPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int i, float v, int i2) {
                ShowGalleryActivity.mSelected = i;
            }

            @Override
            public void onPageSelected(int i) {

            }

            @Override
            public void onPageScrollStateChanged(int i) {

            }
        });
    }

    //Creamos el SwipeImagePagerAdapter. Donde utilizaremos el layout "show_images"
    //para cargar la imagen original y los textos de descripcion de la imagen
    private class SwipeImagePagerAdapter extends PagerAdapter {
        @Override
        public int getCount() {
            return ShowGalleryActivity.mImagesIds.length;
        }
        /**
         * Create the page for the given position.  The adapter is responsible
         * for adding the view to the container given here, although it only
         * must ensure this is done by the time it returns from
         * {@link #finishUpdate(android.view.ViewGroup)}.
         *
         * @param collection The containing View in which the page will be shown.
         * @param position   The page position to be instantiated.
         * @return Returns an Object representing the new page.  This does not
         * need to be a View, but can be some other container of the page.
         */
        @Override
        public Object instantiateItem(ViewGroup collection, int position) {

            LayoutInflater inflater = (LayoutInflater) collection.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            //Refereciamos el show_images layout
            View view = inflater.inflate(R.layout.show_images, null);
            LinearLayout swipeDescription = (LinearLayout) view.findViewById(R.id.swipe_description);

            if (hideSwipeText) {
                swipeDescription.setVisibility(View.GONE);
            }

            hideSwipeText = true;

            //Refereciamos el objeto ImageView del "show_images" layout
            ImageView imageView = (ImageView) view.findViewById(R.id.gallery_image);

            //Asignamos a cada ImageView una imagen de nuestro "Array" de recursos
            //utilizamos "setImageResource" ya que nuestras imagenes estan almacenadas en una
            //carpeta de recursos en nuestro proyecto.
            // "mImagesIds" es un Array de enteros, ya que almacena el Id del recurso, no la imagen en si.
            imageView.setImageResource(mImagesIds[position]);

            //Refereciamos el objeto TextView del "show_images" layout, para colocar la descripcion de la imagen
            TextView imageDescription = (TextView) view.findViewById(R.id.image_description);

            //Asignamos el test descriptivo de la imagen al objecto TextView.
            imageDescription.setText(imagesDescriptions[position].toString());

            //Adicionamos el "view" que hemos creado con los objectos ImageView y TextView a la coleccion ViewGroup
            collection.addView(view, 0);

            return view;
        }

        /**
         * Remove a page for the given position.  The adapter is responsible
         * for removing the view from its container, although it only must ensure
         * this is done by the time it returns from {@link #finishUpdate(android.view.ViewGroup)}.
         *
         * @param collection The containing View from which the page will be removed.
         * @param position   The page position to be removed.
         * @param view       The same object that was returned by
         *                   {@link #instantiateItem(android.view.View, int)}.
         */
        @Override
        public void destroyItem(ViewGroup collection, int position, Object view) {
            collection.removeView((View) view);
        }
        /**
         * Determines whether a page View is associated with a specific key object
         * as returned by instantiateItem(ViewGroup, int). This method is required
         * for a PagerAdapter to function properly.
         *
         * @param view   Page View to check for association with object
         * @param object Object to check for association with view
         * @return
         */
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return (view == object);
        }
        /**
         * Called when the a change in the shown pages has been completed.  At this
         * point you must ensure that all of the pages have actually been added or
         * removed from the container as appropriate.
         *
         * @param arg0 The containing View which is displaying this adapter's
         *             page views.
         */
        @Override
        public void finishUpdate(ViewGroup arg0) {
        }

        @Override
        public void restoreState(Parcelable arg0, ClassLoader arg1) {
        }
        @Override
        public Parcelable saveState() {
            return null;
        }
        @Override
        public void startUpdate(ViewGroup arg0) {
        }
    }
}

Nota: Las descripciones de las imagenes se encuentran en la carpeta res\values\arrays.xml

7. -Por ultimo modificaremos nuestro Main Activity para hacer el llamado nuestra galería de imágenes:

El layout associado a la Main Activity (activity_main) queda de la siguiente manera:


    

En la clase MainActivity, capturamos el evento del click del botón, para así mostrar la galería:


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button showGallery = (Button) findViewById(R.id.button);

        showGallery.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(MainActivity.this, ShowGalleryActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
            }
        });
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        return true;
    } 
}
Así debería quedar nuestro proyecto:

Y el resultado seria el siguiente:

Y después de seleccionar una imagen:

Puede descargar el código fuente en: ImageGallerySource

No hay comentarios: