Wednesday, March 9, 2011

Images with Coverflow like animation in ANDROID



AIM:  To show an array of images in CoverFlow like animation in ANDROID Gallery.
Solution:
We need to create one custom gallery extends Gallery.


File 1: 
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Transformation;
import android.widget.Gallery;
import android.widget.ImageView;

public class CoverFlow extends Gallery {

    /**
     * Graphics Camera used for transforming the matrix of ImageViews
     */
    private Camera mCamera = new Camera();

    /**
     * The maximum angle the Child ImageView will be rotated by
     */  
    private int mMaxRotationAngle = 60;
  
    /**
     * The maximum zoom on the centre Child
     */
    private int mMaxZoom = -120;
  
    /**
     * The Centre of the Coverflow
     */  
    private int mCoveflowCenter;
  
 public CoverFlow(Context context) {
  super(context);
  this.setStaticTransformationsEnabled(true);
 }

 public CoverFlow(Context context, AttributeSet attrs) {
  super(context, attrs);
        this.setStaticTransformationsEnabled(true);
 }

  public CoverFlow(Context context, AttributeSet attrs, int defStyle) {
   super(context, attrs, defStyle);
   this.setStaticTransformationsEnabled(true);  
  }
 
    /**
     * Get the max rotational angle of the image
  * @return the mMaxRotationAngle
  */
 public int getMaxRotationAngle() {
  return mMaxRotationAngle;
 }

 /**
  * Set the max rotational angle of each image
  * @param maxRotationAngle the mMaxRotationAngle to set
  */
 public void setMaxRotationAngle(int maxRotationAngle) {
  mMaxRotationAngle = maxRotationAngle;
 }

 /**
  * Get the Max zoom of the centre image
  * @return the mMaxZoom
  */
 public int getMaxZoom() {
  return mMaxZoom;
 }

 /**
  * Set the max zoom of the centre image
  * @param maxZoom the mMaxZoom to set
  */
 public void setMaxZoom(int maxZoom) {
  mMaxZoom = maxZoom;
 }

 /**
     * Get the Centre of the Coverflow
     * @return The centre of this Coverflow.
     */
    private int getCenterOfCoverflow() {
        return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft();
    }
  
    /**
     * Get the Centre of the View
     * @return The centre of the given view.
     */
    private static int getCenterOfView(View view) {
        return view.getLeft() + view.getWidth() / 2;
    }
    /**
  * {@inheritDoc}
  *
  * @see #setStaticTransformationsEnabled(boolean)
  */
    protected boolean getChildStaticTransformation(View child, Transformation t) {
 
  final int childCenter = getCenterOfView(child);
  final int childWidth = child.getWidth() ;
  int rotationAngle = 0;
 
  t.clear();
  t.setTransformationType(Transformation.TYPE_MATRIX);
 
        if (childCenter == mCoveflowCenter) {
            transformImageBitmap((ImageView) child, t, 0);
        } else {    
            rotationAngle = (int) (((float) (mCoveflowCenter - childCenter)/ childWidth) *  mMaxRotationAngle);
            if (Math.abs(rotationAngle) > mMaxRotationAngle) {
             rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;  
            }
            transformImageBitmap((ImageView) child, t, rotationAngle);        
        }  
            
  return true;
 }

 /**
  * This is called during layout when the size of this view has changed. If
  * you were just added to the view hierarchy, you're called with the old
  * values of 0.
  *
  * @param w Current width of this view.
  * @param h Current height of this view.
  * @param oldw Old width of this view.
  * @param oldh Old height of this view.
     */
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
      mCoveflowCenter = getCenterOfCoverflow();
      super.onSizeChanged(w, h, oldw, oldh);
     }
 
     /**
      * Transform the Image Bitmap by the Angle passed
      *
      * @param imageView ImageView the ImageView whose bitmap we want to rotate
      * @param t transformation
      * @param rotationAngle the Angle by which to rotate the Bitmap
      */
     private void transformImageBitmap(ImageView child, Transformation t, int rotationAngle) {          
      mCamera.save();
      final Matrix imageMatrix = t.getMatrix();;
      final int imageHeight = child.getLayoutParams().height;;
      final int imageWidth = child.getLayoutParams().width;
      final int rotation = Math.abs(rotationAngle);
                    
      mCamera.translate(0.0f, 0.0f, 100.0f);
        
      //As the angle of the view gets less, zoom in    
      if ( rotation < mMaxRotationAngle ) {
       float zoomAmount = (float) (mMaxZoom +  (rotation * 1.5));
       mCamera.translate(0.0f, 0.0f, zoomAmount);        
      }
    
      mCamera.rotateY(rotationAngle);
      mCamera.getMatrix(imageMatrix);              
      imageMatrix.preTranslate(-(imageWidth/2), -(imageHeight/2));
      imageMatrix.postTranslate((imageWidth/2), (imageHeight/2));
      mCamera.restore();
 }
}
File 2:
Activity Class ,where you need to show the Coverflow of Images

public class CoverFlowExample extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     
     CoverFlow coverFlow;
     coverFlow = new CoverFlow(this);
     
     coverFlow.setAdapter(new ImageAdapter(this));

     ImageAdapter coverImageAdapter =  new ImageAdapter(this);
     
      coverFlow.setAdapter(coverImageAdapter);
     
     coverFlow.setSpacing(-25);
     coverFlow.setSelection(4, true);
     coverFlow.setAnimationDuration(1000);
         
     setContentView(coverFlow);
    }

 public class ImageAdapter extends BaseAdapter {
     int mGalleryItemBackground;
     private Context mContext;

     private FileInputStream fis;
        
     private Integer[] mImageIds = {
     R.drawable.yadi,
             R.drawable.yadi_1,
             R.drawable.yadi_2,
             R.drawable.yadi_3,
             R.drawable.yadi_4,
             R.drawable.yadi_5,
             R.drawable.yadi_6,
             R.drawable.yadi_7,
             R.drawable.yadi_8
             
     };

     private ImageView[] mImages;
     
     public ImageAdapter(Context c) {
      mContext = c;
      mImages = new ImageView[mImageIds.length];
     }
  public boolean createReflectedImages() {
          //The gap we want between the reflection and the original image
          final int reflectionGap = 4;
          
          
          int index = 0;
          for (int imageId : mImageIds) {
        Bitmap originalImage = BitmapFactory.decodeResource(getResources(), 
          imageId);
           int width = originalImage.getWidth();
           int height = originalImage.getHeight();
           
     
           //This will not scale but will flip on the Y axis
           Matrix matrix = new Matrix();
           matrix.preScale(1, -1);
           
           //Create a Bitmap with the flip matrix applied to it.
           //We only want the bottom half of the image
           Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0, height/2, width, height/2, matrix, false);
           
               
           //Create a new bitmap with same width but taller to fit reflection
           Bitmap bitmapWithReflection = Bitmap.createBitmap(width 
             , (height + height/2), Config.ARGB_8888);
         
          //Create a new Canvas with the bitmap that's big enough for
          //the image plus gap plus reflection
          Canvas canvas = new Canvas(bitmapWithReflection);
          //Draw in the original image
          canvas.drawBitmap(originalImage, 0, 0, null);
          //Draw in the gap
          Paint deafaultPaint = new Paint();
          canvas.drawRect(0, height, width, height + reflectionGap, deafaultPaint);
          //Draw in the reflection
          canvas.drawBitmap(reflectionImage,0, height + reflectionGap, null);
          
          //Create a shader that is a linear gradient that covers the reflection
          Paint paint = new Paint(); 
          LinearGradient shader = new LinearGradient(0, originalImage.getHeight(), 0, 
            bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, 0x00ffffff, 
            TileMode.CLAMP); 
          //Set the paint to use this shader (linear gradient)
          paint.setShader(shader); 
          //Set the Transfer mode to be porter duff and destination in
          paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); 
          //Draw a rectangle using the paint with our linear gradient
          canvas.drawRect(0, height, width, 
            bitmapWithReflection.getHeight() + reflectionGap, paint); 
          
          ImageView imageView = new ImageView(mContext);
          imageView.setImageBitmap(bitmapWithReflection);
          android.widget.Gallery.LayoutParams imgLayout = new CoverFlow.LayoutParams(320, 480);
          imageView.setLayoutParams(imgLayout);
          imageView.setPadding(30, 100, 20, 20);
          mImages[index++] = imageView;
          
          }
       return true;
  }

     public int getCount() {
         return mImageIds.length;
     }

     public Object getItem(int position) {
         return position;
     }

     public long getItemId(int position) {
         return position;
     }

     public View getView(int position, View convertView, ViewGroup parent) {

      //Use this code if you want to load from resources
         ImageView i = new ImageView(mContext);
         i.setImageResource(mImageIds[position]);
         i.setLayoutParams(new CoverFlow.LayoutParams(380, 450));
         i.setScaleType(ImageView.ScaleType.CENTER_INSIDE); 
         
         //Make sure we set anti-aliasing otherwise we get jaggies
         BitmapDrawable drawable = (BitmapDrawable) i.getDrawable();
         drawable.setAntiAlias(true);
         return i;
      
      //return mImages[position];
     }
   /** Returns the size (0.0f to 1.0f) of the views 
      * depending on the 'offset' to the center. */ 
      public float getScale(boolean focused, int offset) { 
        /* Formula: 1 / (2 ^ offset) */ 
          return Math.max(0, 1.0f / (float)Math.pow(2, Math.abs(offset))); 
      } 

 }
}
The output will be as follows ( in GAlaXY TABlet) 


Please let me know if any.


25 comments:

  1. Thanks for this nice flow.
    Im trying to put this in a layout xml
    and then add o other views into.
    But not really successfully.
    Can you make tip, how this could work?

    ReplyDelete
  2. Thanks for this gallery... it's really awesome!!!

    But I've a question :)

    Is it possible that the gallery switches automatically the next image (without a gesture) and I still have the animation?

    There's no animation, when I set the position with "gallery.setSelection(position)"

    Thanks a lot!

    FloDo

    ReplyDelete
  3. There is a arrayindexoutofbounce exception, when im using three pictures.

    ReplyDelete
  4. paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); im getting error at Mode.DST_IN.... Could you please suggest me

    ReplyDelete
  5. paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    Try this. it ll work.

    --
    Arun, Infowave.

    ReplyDelete
  6. Hi,

    Thanks for providing this code for gallery customization.

    I want to have rotating options in 3D. When clicking on any image/icon/button should open an another activity. Can you help me how can we do this.

    ReplyDelete
  7. Hi is it a 2.2 or 2.3.1 application??? because i am getting the
    paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); Mode.dst_in cnnot be resolved error?? please help

    ReplyDelete
  8. Datta, I also get Same error, any body have a solution then plz give me

    ReplyDelete
  9. Hi,
    This post is really useful. I tried it and its working fine.
    I tried to modify your code as I don't want spacing between images. I set Spacing but
    that is working only for the selected image and images next to that . I tried to set padding also but that too not reflecting any changes in the view. Could you please what i can do to change that. And I have one more doubt , can we draw border to that image. I mean something like drawing rect to that bitmap image

    ReplyDelete
  10. @Datta:
    Remove this library if you have imported.

    import android.graphics.AvoidXfermode.Mode;


    By importing this library

    import android.graphics.PorterDuff.Mode;

    ReplyDelete
  11. Using this import works like a charm :D amazing
    import android.graphics.PorterDuff.Mode;

    ReplyDelete
  12. coverFlow.setSelection(4, true); getting here nullpointerexception

    ReplyDelete
  13. can you please send me the zip file , as i am trying to get the code run but its not working :)

    ReplyDelete
  14. I also get same err

    ReplyDelete
  15. I get errors on all the
    private Integer[] mImageIds = {
    R.drawable.yadi,
    R.drawable.yadi_1,
    R.drawable.yadi_2,
    R.drawable.yadi_3,
    R.drawable.yadi_4,
    R.drawable.yadi_5,
    R.drawable.yadi_6,
    R.drawable.yadi_7,
    R.drawable.yadi_8

    };

    ReplyDelete
    Replies
    1. All those files are the images need to show in coverflow.
      Replace with your required image file ids.

      Delete
  16. This comment has been removed by the author.

    ReplyDelete
  17. does not work it's force closing?? any help

    ReplyDelete
  18. Can i chagne to String[] from url ?

    private Integer[] mImageIds = {
    R.drawable.yadi,
    R.drawable.yadi_1,
    R.drawable.yadi_2,
    R.drawable.yadi_3,
    R.drawable.yadi_4,
    R.drawable.yadi_5,
    R.drawable.yadi_6,
    R.drawable.yadi_7,
    R.drawable.yadi_8

    };

    ReplyDelete
  19. Thank you for this code. I found it helpful in creating my android image carousel. I compiled a list of top resources for carousel implementation and design. Hope its useful to other developers.
    http://www.verious.com/board/Giancarlo-Leonio/creating-an-android-image-carousel/

    ReplyDelete
  20. How to show Selected Image in another image view in same layout.Please help me.

    ReplyDelete
  21. hello thanks for the tutorial I wanted to add a title underneath the images and did, but I have a problem if I make the move to the side, the title image does not change, it only changes if I click on the picture. anyone can solve? thank you

    ReplyDelete
  22. where is the xml file what we have to put their.

    ReplyDelete

Android Developers Blog

Ram's shared items