Saturday, 27 February 2010

Android Coverflow Widget V2


It's been a while now and I've been pretty busy with life, work, and other things, but at last here's a new version of the coverflow widget that I released a while back. There's not really much new functionality here, but I have cut down the amount of code needed by a lot. Gone are the CoverAbsSpinner and the CoverAdapterView classes and now we are left with just the CoverFlow class weighing in at less than 200 lines of code. Of course, you still have to instantiate it and populate it using an ImageAdapter so I'll also include the activity class for doing those tasks as well.


Background
The basic idea is that the Coverflow widget works very much like the standard Android Gallery widget, but with the addition of the rotation of the images. For more background information on the Coverflow widget see my original post here

How to use
In your Android project create a package called com.example.coverflow, and in this place the CoverFlow class. Now all you need is an activity to instantiate the Coverflow widget in this example the activity class is called CoverflowExampleCoverFlowExample simply extends Activity and instantiates a Coverflow class in it's onCreate method. It also has an internal Class, ImageAdapter which we use as the adapter for the Coverflow widget, much as we would for a Gallery widget. It is also possible to use the Coverflow widget when it is specified in an XML layout file.


The CoverFlow and CoverflowExample classes are here:


/*
 * Copyright (C) 2010 Neil Davies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * This code is base on the Android Gallery widget and was Created 
 * by Neil Davies neild001 'at' gmail dot com to be a Coverflow widget
 * 
 * @author Neil Davies
 */
package com.example.coverflow;


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();
 }
}
/*
 * Copyright (C) 2010 Neil Davies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * This code is base on the Android Gallery widget and was Created 
 * by Neil Davies neild001 'at' gmail dot com to be a Coverflow widget
 * 
 * @author Neil Davies
 */
package com.example.coverflow;

import java.io.FileInputStream;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;

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);
     
     //coverImageAdapter.createReflectedImages();
     
     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.kasabian_kasabian,
             R.drawable.starssailor_silence_is_easy,
             R.drawable.killers_day_and_age,
             R.drawable.garbage_bleed_like_me,
             R.drawable.death_cub_for_cutie_the_photo_album,
             R.drawable.kasabian_kasabian,
             R.drawable.massive_attack_collected,
             R.drawable.muse_the_resistance,
             R.drawable.starssailor_silence_is_easy
     };

     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);
          imageView.setLayoutParams(new CoverFlow.LayoutParams(120, 180));
          imageView.setScaleType(ScaleType.MATRIX);
          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(130, 130));
         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))); 
      } 

 }
}

Code explanation
The CoverflowExample Code contains some extra code for creating reflections of the images, but apart from this is a standard activity class of the kind used with the Gallery widget.

The CoverFlow class extends the Gallery widget , but now we override a few methods to allow us to transform the images before they are displayed. The most important method that we override is the getChildStaticTransformation method. Here I have to say thank you to a user called Nerdrow on the Android developers group who first showed me an example of overriding this method.  By setting setStaticTransformationsEnabled in the constructors, we are telling the parent ViewGroup of the Coverflow class to invoke getChildStaticTransformation every time one of our images in drawn. In getChildStaticTransformation we simply calculate and apply a rotation and scale to the ImageView depending on it's position relative to the centre of the Coverflow widget. We also override the onSizeChanged method. This method is called every time the widget changes size e.g. when we change the orientation of the phone from portrait to landscape. In the onSizeChanged method we just get the centre position of the coverflow widget. There are also a few parameters that we can set, mZoomMax controls the maximum zoom of the central image and mMaxRotationAngle sets the maximum rotation angle of each image.


Thanks
Lastly, I just wanted to say thanks to everyone who has commented and given me feedback on the coverflow widget. It's be really positive and great to hear that people have got it working successfully on a range of devices such as the HTC magic , Motorolla droid and Nexus 1. There's still more to do for the coverflow widget and I'll release new version as and when I make updates. If anyone has anymore suggests for cool widgets or enhancements to this Coverflow widget then please do get in touch.

84 comments:

  1. Hi,
    Nice Widget Thanks for publishing! but where do i add coding to trigger a action when i click on the center image.

    ReplyDelete
  2. Hello!
    I really like that widget! I would like to use it in my project but I dont know how... I would like Your widget to be in the middle of the screen. At the top and at the bottom of the screen I would like to have some text... But I have no idea how to do it :S (look at this pic: http://e.imagehost.org/0309/Untitled_20.png)
    Would anyone be so nice and help me out? Thanks =)

    Also: Please response to sjanamica's post :)

    ReplyDelete
  3. You can use this widget as you would the Gallery Widget. If you want it in the middle of the screen I would suggest using a vertical LinearLayout. For an example of specifying the widget in an XML layout file see my first post on Coverflow. For sjanamica's question, again you would do this as you would for the standard Gallery widget. If you don't know how have a search on the web or ask a question on one of the developer groups or stackoverflow.

    ReplyDelete
  4. Thanks for quick response and kindness =)

    ReplyDelete
  5. Hello,

    Very interesting, really,

    Do you think it should be possible to make it vertical?

    BM

    ReplyDelete
  6. thanks a lot...very cool....i will use it in my code....

    ReplyDelete
  7. How use this coverflow with an XML Layout ?

    In my XML file (main.xml) I have :



    In my JAVA file I have :

    public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    CoverFlow c = (CoverFlow)findViewById(R.id.coverflow);
    coverFlow.setAdapter(new ImageAdapter(this));
    }

    But the layout on the emulator display but without the coverflow... What's the problem ?

    Thanks a lot

    ReplyDelete
  8. Example given in this post of how to use with an XML layout: http://www.inter-fuser.com/2010/01/android-coverflow-widget.html

    ReplyDelete
  9. Indeed, it works very well with XML :)

    Now how do you think about movements in the focused (most zoomed) JPG ?

    Do you have some tips or anything else to help me in this idea of movement ?

    Thanks a lot !

    ReplyDelete
  10. Hi
    Very good article.
    I'll have a question, is it possible to use a ImageButtonAdapter to retrieve the selection of the current image?

    ReplyDelete
  11. Ermmm, not sure off the top of my head. But essentially this is a Gallery widget, with transformations on the images. So look for examples of how to do this with the Gallery widget.

    ReplyDelete
  12. Hey Taf .... nice work ... Helped me alot ... I am having a problem with reflectioins ... Only the original image is shown ... reflection is not there ... Why is it so?

    ReplyDelete
  13. I haven't included the reflections in this example. Have a look at my previous example. And also the separate post That I did on creating reflections.

    ReplyDelete
  14. Hi taf,
    Amazing job...thanks for sharing.

    I am getting an out of memory exception when entering and leaving the activity (CoverflowExample) twice or three times. Is this something you are aware of or is it just me? (haven't made any changes to CoverflowExample except putting my own drawables in the mImageIds array...)

    I read a bit about memory leaks: http://developer.android.com/intl/de/resources/articles/avoiding-memory-leaks.html
    Is it possible that the line:
    ImageView i = new ImageView(mContext); inside getView is causing it?

    ReplyDelete
  15. I can't say I've noticed this. I have seen problems in the previous example I did. When I was including the reflections in the images. That was just a quick hack to show the coverflow with reflections. I think the first thing I would try is taking out the drawable you've added and see if you still get the problem.

    ReplyDelete
  16. taf, thanks for your quick reply.

    I replaced all the drawables with the default android icon and still got the same result.
    Apparently one or more of the views keeps a hold of a reference to context-activity which the garbage collector can't release... problem is I can't tell which...

    ReplyDelete
  17. This is a bit of a quick guess, but I think I remember seeing a few posts on various groups that there may be a bug in the Gallery widget itself. Might be worth looking into. The way we set up the images here is the same as the way it is done for the original Gallery widget, have a look at a Gallery widget example. I can't think that what i've done would be causing memory leaks, I'm just doing transformations on each image, underneath it's still just the gallery widget

    ReplyDelete
  18. This comment has been removed by the author.

    ReplyDelete
  19. Not sure what you trying to do here, but as I've said before, this widget is essentially a standard gallery widget, so anything you can do with the gallery widget you should be able to do with this widget.

    ReplyDelete
  20. Hi taf,
    i think u can't understand what i am trying ,simply i am trying click event work just like which is using in gallery : -

    public void onItemClick(AdapterView arg0, View arg1, int position, long rowId)
    {

    System.out.println("-------- Simple Adapter ClickItem Working--------");

    Toast.makeText(CoverFlowExample.this, "Selected Pic position"+position, Toast.LENGTH_LONG).show();
    }

    but this is not working not show any toast and print message in debug...

    can u help me please what i am missing ...

    ReplyDelete
  21. Sorry I haven't got much time to look into this at the moment. As an aside you should use the Android logging rather than system.out.println for debug

    ReplyDelete
  22. Hello.
    Many Thanks for posting this article.

    I have two question that

    1. How can I set the specific image to the center of cover flow?

    2. How can I set selected images to the right and selected images to the left of the currently displayed image.?

    Can anyone help me.? Thanks in Advance. :)

    ReplyDelete
  23. This widget is essentially a Gallery widget. look for how to do this with the Gallery widget, it should be the same for this widget.

    ReplyDelete
  24. Can you give an example of how to modify the size of the images in the widget? I've looked at Gallery and there's nothing to specify what the min/max size of images should be - nor do I see that easily in your code either. Any pointers would be great!

    ReplyDelete
  25. Currently the images are scaled to fit into the coverflow widget : i.setScaleType(ImageView.ScaleType.CENTER_INSIDE);

    ReplyDelete
  26. If you want this Widget to work with Views (instead of just Drawables), you can do this:
    In the generatereflection method of the image adapter line 101 replace"
    Bitmap originalImage = BitmapFactory.decodeResource(getResources(),
    imageId);"

    By "
    View cardView = get this item's view;
    cardView.measure(150, 183);
    cardView.layout(0, 0, 150, 183);
    cardView.setDrawingCacheEnabled(true);
    Bitmap originalImage= cardView.getDrawingCache();
    cardView.setDrawingCacheEnabled(false);
    "

    And in the CoverFlow class replace lines 169 and 170 replace "
    final int imageHeight = child.getLayoutParams().height;
    final int imageWidth = child.getLayoutParams().width;
    "

    By "
    final int imageHeight = child.getHeight();
    final int imageWidth = child.getWidth();
    "
    (for some reason, those two lines caused some bugs)

    ReplyDelete
  27. Thank you very much for this great widget :)
    I'm gonna try to understand how it works

    ReplyDelete
  28. I did some modifications but the scroll is still real choppy on a HTC Legend. How's performance on your phone?

    ReplyDelete
  29. Performance was good on a G1. See the Video on my earlier post. I found that if I did to much in the getView method things would get choppy, but that was the same for the standard Gallery Widget.

    ReplyDelete
  30. hari hara kumar27 July 2010 19:29

    hey taf, Excellent job..this is helping me a lot in my project...I have an idea which I tried in many ways but I am unable to succeed, my idea is: when I click at a point on the image, I want the images to be coming out from that point where I clicked" that is , scroll should start from the point I clicked, for this I want the point from where the scroll starts. Please help me. Can I get the starting point of the scroll.

    ReplyDelete
  31. I am not sure what you are trying to do. But i would suggest looking at n,earlier post i,did on coverflow. In that post i am,using the source code of the gallery widget. If you look at the,source for the gallery widget you may be able to,find,what you need.

    ReplyDelete
  32. Hello,
    Great job !
    But I wanted to know how I can put an action after an item have been selected ?

    Thank you.

    ReplyDelete
  33. Nice blog post, the widget looks really nice.

    One question though: does the reflection not work on this version anymore, or why did you comment out the line "coverImageAdapter.createReflectedImages();"?

    But even when I comment in the line for the reflection, the reflection won't show. I'm looking into it right now, but maybe other readers are wondering about it as well.

    ReplyDelete
  34. Here's the answer to my previous question: in CoverFlowExample.java, line 161, it must be:
    i.setImageDrawable( mImages[position].getDrawable() );
    then the reflection is visible.

    ReplyDelete
  35. I don't think you can call this an "widget" since its an activity. If it was a real widget, then your class would of extended from "AppWidgetProvider". But great job!!

    ReplyDelete
  36. The activity is just to create a running example. If you look at the coverflow class you will see that it extends android.widget.gallery .

    ReplyDelete
  37. Hi Idol..

    I have two suggestion from your source code...

    1. CoverFlowExample.java
    from: imageView.setScaleType(ScaleType.MATRIX);
    To: imageView.setScaleType(ScaleType.CENTER_INSIDE);

    so that when they use your createReflectedImages() having different size of images it wont look bad or dis aligne.. I assumed that you used same size images for your sample.. try using different sizes it will look bad.

    2. CoverFlow.java
    From: private void transformImageBitmap(ImageView child, Transformation t, int rotationAngle)
    To: private void transformImageBitmap(View child, Transformation t, int rotationAngle)

    So that when they used your CoverFlow widget they can use customize view to display inside the gallery.. for example inflating xml layout as display for your widget.. instead of using ImageView why not using View?

    If I missed something please let me know so that I can understand very well.

    Thanks.

    ReplyDelete
  38. Hi Taf,
    Thanks for excellent widget and tutorial as well as following up the comments.

    I have similar question as previous guy. I want to use GridView as an item of CoverFlow and these GridViews dynamically populated with different App icons. Do you foresee any issue implementing it.

    Thanks
    &
    Regards

    ReplyDelete
  39. Is there an option for widged or app download?

    ReplyDelete
  40. Hi TAF, great post! I like your solution based on Gallery.

    I'm beating my head trying to find the solution to make the elements of the Gallery to have dynamic size.
    you set it in the
    i.setLayoutParams(new CoverFlow.LayoutParams(130, 130));

    but as the result transformed elements have the size equal to it. but I would like to have smaller or even no gap between elements, so I can show more elements in that control.
    Do you see any ways to achieve that ? to put them closer to each other ? (actually that should mean that they will have dynamic size, depending on their actual transformed width)

    Thanks

    ReplyDelete
  41. Great improvement, thanks!

    I'm just looking for a equivalent of the onFinishedMovement() method that was present in V1.

    Any ideas how to implement this?

    Thank you

    ReplyDelete
  42. hiya,
    great widget!
    one improvement suggestion: you should never automatically create a new View in the getView method of your Adapter but first check if you can reuse the convertView parameter.
    See the official documentation: http://developer.android.com/reference/android/widget/Adapter.html#getView%28int,%20android.view.View,%20android.view.ViewGroup%29

    So, in this case something like this:

    ...
    //Use this code if you want to load from resources
    ImageView i = null;
    if (convertView==null || !(convertView instanceof ImageView)) {
    i = new ImageView(mContext);
    } else {
    i = (ImageView) convertView;
    } i.setImageResource(mImageIds[position]);
    ...

    ReplyDelete
  43. Hi Niel...
    I have trouble figuring out how to shrink images behind the main image. I have set spacing very high so now my images are behind my main photo. I want to have sense of space so i need to shrink them. Where should this be set up?

    ReplyDelete
  44. Hi Niel,

    I want to reduce the spacing between the child images so that the screen can show child images. Can you tell me how to achieve this ?

    ReplyDelete
  45. I love it!
    One caveat: It doesn't seem to draw the images in the right order- the 'z index', I believe it's called, seems to be a little borked, but only when I have large images and small spacing. I'm digging into your code trying to patch it but do you have any hints?

    ReplyDelete
  46. Hi
    i am using this code for image sliding.
    i am fetching 10 or more image from web and loading it.
    it is working fine. but problem is here. it is taking lot of time to load images. i want to know how to cache image on folder and fetch from folder. so please help me.

    ReplyDelete
  47. That works really well. I am amazed you can do it in so few lines of code - I was going to try something similar but it would have been significantly larger.

    If there are a lot of images to scroll through, you might have to manage the reflection bitmaps a bit better - possibly cache them to SD or something. if there a 100s ...

    ReplyDelete
  48. Thanks for that great post!
    I try to use it, but I would like to have an endless list where the end show the begin and the begin show the end.
    Do you think it's possible with your work and how I can do that?
    Thanks.

    ReplyDelete
  49. Hi Neil,

    Great blog thumbs up.

    My question is, if I change the Max Rotation Angle to say 85degrees, you can imagine my images are pretty much side on. So how do I bunch them up so I can get more on the screen either side of my middle flat image?

    I can't resize the image as this will skew it correct?

    Pointers in the right direction would be great.

    ReplyDelete
  50. I am new to android and i wanna use this in my samsung galaxy ace, what should i do? Can i use it by just copying the code in a new apk in eclipse. pls respond...

    ReplyDelete
  51. hey neil, great widget, tx so much for sharing! i'll be using it in a new app, multi-clock. will be out in a few weeks, so be on the look out.

    ReplyDelete
  52. Hii,
    This widget is cool...Im trying to use it. I noticed one issue here at the begining when the view is loaded the icons will not be in scaled state..How do I make it happen???

    ReplyDelete
  53. It's really nice tutorial...!!!

    ReplyDelete
  54. any one guide me how can i set on click listener of selected image ?

    my requirement is if image is selected and if user clicks on it, it should open new activity to show image full size

    any help would be appreciated.

    ReplyDelete
  55. i have used following code but i want to put check if image is in centre right now if i click on other images which are displaying left or right side of selected images it is called

    coverFlow.setAnimationDuration(1000);
    coverFlow.setOnItemClickListener(new OnItemClickListener() {

    @Override
    public void onItemClick(AdapterView arg0, View v, int position,
    long rowID) {
    Toast.makeText(v.getContext(), "clicked " + position , 1000).show();
    }
    });


    setContentView(coverFlow);

    ReplyDelete
  56. Can I do this animation for images taken using the device camera. If yes, please show me how to do it. Thanks in advance

    ReplyDelete
  57. Hey there,

    definitely a great job! I like the refactoring making it extends the Gallery. I would like to highlight a couple things though.
    *If you face outOfMemory errors, don't hesitate to add originalImage.recycle(); (line. 149). It appeared that I could also free reflection image memory by using reflectionImage.recycle(); (l. 150). As long as after drawing it in the canvas we don't need those Bitmaps anymore.
    *I had a weird result when I put back the reflexion, the sizes where incorrect (with to short resulting in a crop & reflexion incomplete), since I changed imageView.setScaleType(ScaleType.MATRIX); by something else like imageView.setScaleType(ScaleType.FIT_CENTER); it works fine (l. 147).

    Thanks for this job, coming back to you after I release the result ;)
    -O-

    ReplyDelete
  58. Thanks for this great example and extensive comments!

    Without any changes, I did run into a problem with the v2 design. After replacing v1 CoverFlow.java and CoverFlowExample.java files with the code above, all occurrences of "setStaticTransformationsEnabled" generate the errors "The method setStaticTransformationsEnabled(boolean) is undefined for the type CoverFlow".

    Is there something missing in the new code or other changes necessary?

    ReplyDelete
  59. Update: Looks like commenting out the three lines with "setStaticTransformationsEnabled" eliminates the compile problem. Everything appears to work fine! Perhaps it's not needed with the current SDK and updates as of today.

    ReplyDelete
  60. For Fullscreen,
    replace: i.setLayoutParams(new CoverFlow.LayoutParams(130, 130));


    for:

    Display display = getWindowManager().getDefaultDisplay();
    i.setLayoutParams(new CoverFlow.LayoutParams(display.getWidth(), display.getHeight()));

    ReplyDelete
  61. Great job.
    But if I use coverFlow.setSpacing(-45);
    , it will cause the image of right side overlaps left side. How to fix this problem?

    ReplyDelete
  62. hi sir
    i folw your code every thing fine but the images displayed in mobile was too small , how can i increase image size in coveflow disply

    ReplyDelete
  63. hello,
    congratulations! His coverflow is wonderful.
    I have a question, it is possible to add different links in the image?

    thank you

    ReplyDelete
  64. Hi, excellent tutorial, which parameter I have to modify to resize images? What class? Thanks

    ReplyDelete
  65. @taf Thanks for all the good work! I posted your two classes as gists at https://gist.github.com/2246183 and https://gist.github.com/2246185 FYI.

    ReplyDelete
  66. How can I put a static image in the background that does not move and it under the coverflow images?

    ReplyDelete
  67. EXCELLENT EXCELLENT work! Love this. Thanks for taking the time to do this.

    ReplyDelete
  68. can we make it carousel view ?

    ReplyDelete
  69. Thanx for this awesome script! I added an OnClickListener to open links by tapping on images, but this prevents the app from scrolling, any ideas?

    ReplyDelete
  70. Hi,

    I'm having issues with coverflow. It does not center back as it should>

    http://stackoverflow.com/questions/13014715/android-coverflow-issue-on-4-0-3-samsung-galaxy-s2

    ReplyDelete
  71. Hiya! I just wanted to highlight that you sure have created a splendid blog. Will you be so nice and provide an answer to my question. Do you take into considerations writing professionally or blogging is just a kind of hobby of yours?

    ReplyDelete
  72. Blogging is mostly just a hobby. Although sometimes people get in touch and work opportunities may come about.

    ReplyDelete
  73. Neil,

    Thanks, this works well thus far. My guess is that Google's getting ready to come out with something similar, which is why they deprecated the Gallery in JB.

    I modified it to take Uri's and snapped my existing adapter in to it that creates the images from Uris, fairly trivial. I'll send that to you in an email along with some other info I have for you.

    Cheers and Happy New Year!

    ReplyDelete
  74. Hi HereGear, can I take a look at your implementation with URIs? I found several bugs in Neil code so I would like to start with something newer and focus on fixing not already fixed things and take advantage of better implementations. write me to rainymanyu (a-t) yahoo .com

    thanks

    ReplyDelete
  75. Hi Freak & aamir,
    Add this code OnCreate() of CoverFlowExample it will not prevent scrolling.

    coverFlow.setOnItemClickListener(new OnItemClickListener() {

    @Override
    public void onItemClick(AdapterView arg0, View arg1, int position,
    long arg3) {
    Toast.makeText(CoverFlowExample.this, "" + position,
    Toast.LENGTH_LONG).show();
    }
    });

    don't forget to import
    import android.widget.AdapterView.OnItemClickListener;

    Thanks

    ReplyDelete
  76. Thanks this is the great example.

    I want to know how can we show 3 images on right and 3 images on left of the selected image?

    Thanks

    ReplyDelete
  77. it doesn't work well on android 4.2, please update it.
    Pictures never go into plat position.

    ReplyDelete
  78. Now that Gallery is deprecated, it's not working well in new Android releases. I think that it'd me better to implement it using ViewPager, don't you agree? Do you have any plans to reimplement it? Thank you.

    ReplyDelete
  79. Hi,
    I want add this whole cover flow wrapper to one android view is it possible?

    Thanks and Regards,
    Venkatesh

    ReplyDelete
  80. Neil, thank you for this widget!

    For Android 4.x issue I found this solution:
    http://stackoverflow.com/questions/13014715/android-coverflow-issue-on-4-0-3-samsung-galaxy-s2

    The widget can be also used with other Views instead of ImageView. Simply remove all ImageView casts and replace ImageView parameters with View.

    Thanks and regards,
    Dietmar

    ReplyDelete
  81. Hello if i want to place the widget at the top of the screen, and put other fields like text, buttons. How do I? I already have these fields in the xml but they do not appear on the screen, because I think that the widget is to overlap

    ReplyDelete
  82. hi man
    thanks for good tutorial
    how can I make listener for thumbnail buttons plz ?

    ReplyDelete
  83. Hi

    When I press on a picture, or simply scroll so a picture is in the middle, it does not always become straight so to speak. One side of it can be larger than another side so that it looks angled still.

    ReplyDelete
  84. Hi,

    Great job! Widget looks really good. Can I include this widget to my project with fragments?

    ReplyDelete