I did a similar POC overriding the getChildStaticTransformation() method of the Gallery. Like Taf's widget, you need to provide a standard adapter and should probably pre-create the mirror images (if you need them). The below runs pretty smooth on a G1 & Droid, feel free to use and improve :)
package com.nnm.sexyui.widget; import android.content.Context; import android.graphics.Camera; import android.graphics.Color; import android.graphics.Matrix; import android.util.AttributeSet; //import android.util.Log; import android.view.View; import android.view.animation.Transformation; import android.widget.Gallery; /** * */ public class Gallery3D extends Gallery { //private static final String TAG = "Gallery3D"; private static final int DEFAULT_FADING_EDGE_LENGTH = 90; private static final Camera mCamera = new Camera(); private float[] mOffsetRotateCache, mOffsetScaleCache; private float mMaxUnselectedRotateAngle = 45.0f, mMaxSelectedScale = 1.0f, mMinUnselectedScale = 0.85f; private int mStageOffsetMin = 0, mStageOffsetMax = 0; private int mItemWidth = 280; /********************************** CONSTRUCTORS **********************************/ /** * Create a new Gallery3D instance. * @param context */ public Gallery3D(Context context) { this(context, null); } /** * Create a new Gallery3D instance. * @param context * @param attrs */ public Gallery3D(Context context, AttributeSet attrs) { this(context, attrs, 0); } /** * Create a new Gallery3D instance. * @param context * @param attrs * @param defStyle */ public Gallery3D(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setClipChildren(false); setClipToPadding(false); setDrawingCacheBackgroundColor(Color.BLACK); setHorizontalFadingEdgeEnabled(true); setFadingEdgeLength(DEFAULT_FADING_EDGE_LENGTH); setStaticTransformationsEnabled(true); } /********************************** GETTERS/SETTERS **********************************/ /** * The width of gallery items (must be uniform) * @param width */ public final void setItemWidth(int width) { mItemWidth = width; buildOffsetCache(); } /** * The amount that non-focused items will be rotated. * @param rotate Valid rotation value between 0.0f and 90.0f. */ public final void setUnselectedRotate(float rotate) { mMaxUnselectedRotateAngle = rotate; buildOffsetCache(); } /** * The amount that non-selected items will be scaled. * @param scale Scale value, may be greater than 1.0f. */ public final void setUnselectedScale(float scale) { mMinUnselectedScale = scale; buildOffsetCache(); } /** * Optional, over-scale the selected item (ie, 1.1f) * @param scale */ public final void setSelectedScale(float scale) { mMaxSelectedScale = scale; buildOffsetCache(); } /********************************** PRIVATE METHODS **********************************/ /** * Pre-calculate the range rotation angles and scaling factors * for the non-static horizontal range of the Gallery. */ private final void buildOffsetCache() { final int galleryWidth = getWidth(); if(galleryWidth<1 || mItemWidth<1) return; final float unRotate = mMaxUnselectedRotateAngle, unScale = mMinUnselectedScale, maxScale = mMaxSelectedScale, unScaleRange = (mMaxSelectedScale-mMinUnselectedScale); final float centerline = galleryWidth/2; final float itemHalfWidth = mItemWidth/2; final int rangeMin = mStageOffsetMin = (int)(centerline- itemHalfWidth); final int rangeMax = mStageOffsetMax = (int)(centerline +itemHalfWidth); mOffsetRotateCache = new float[galleryWidth]; mOffsetScaleCache = new float[galleryWidth]; // child is to the left of the centerline, so translating only for(int i=0;i<rangeMin;i++) { mOffsetRotateCache[i]=mMaxUnselectedRotateAngle; mOffsetScaleCache[i]=unScale; } // child is in range, so translating, rotating, and scaling float rangePct = 0.0f; for(int i=rangeMin;i<rangeMax;i++) { rangePct = ((centerline-i)/itemHalfWidth); mOffsetRotateCache[i]=(rangePct*unRotate); mOffsetScaleCache[i]= (rangePct>0)? (maxScale-(rangePct*unScaleRange)): (maxScale+(rangePct*unScaleRange)); } // child is to the right of the range, so translating only for(int i=rangeMax;i<galleryWidth;i++) { mOffsetRotateCache[i]=-unRotate; mOffsetScaleCache[i]=unScale; } // this is ugly but it works :) // smooth the rotation/scaling around the centerline by 3 pixels in either direction final int smoothMin = (int)(centerline-3), smoothMax = (int) (centerline+3); for(int i=smoothMin;i<smoothMax;i++) { mOffsetRotateCache[i]=0.0f; mOffsetScaleCache[i]=maxScale; } // TODO: this was a quick proof-of-concept. we don't really need to store // the entire width, only the range between rangeMin and rangeMax. The // getStaticTransformation method would then need to take this into account // when it grabs the rotation/scale values (ie, subtract the range lower-bound // from the child centerline, or something like that). } /********************************** OVERRIDE METHODS **********************************/ /** * Per SDK: * <b><i> * Override this if your view is known to always be drawn on top of a solid color * background, and needs to draw fading edges. Returning a non-zero color enables t * he view system to optimize the drawing of the fading edges. If you do return * a non-zero color, the alpha should be set to 0xFF. * </i><b> * @return */ @Override public int getSolidColor() { return Color.BLACK; } /** * Be sure the static rotation/scale cache is updated * when the overall size changes **/ @Override public void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); buildOffsetCache(); } /** * Apply the necessary rotate and scale transformations to the provided child. * @param child * @param t * @return */ @Override protected boolean getChildStaticTransformation(View child, Transformation t) { // reset the transformation t.clear(); t.setTransformationType(Transformation.TYPE_BOTH); // the offset of the child's centerline from the center // of the gallery final int centerX = child.getWidth()/2, centerY = child.getHeight()/ 2; final int centerChild = (child.getLeft()+centerX); final Camera camera = mCamera; final Matrix matrix = t.getMatrix(); // left of rotating, scaling range if(centerChild<mStageOffsetMin) { camera.save(); camera.rotateY(mMaxUnselectedRotateAngle); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); matrix.preScale(mMinUnselectedScale, mMinUnselectedScale, centerX, centerY); // right of rotating, scaling range } else if(centerChild>mStageOffsetMax) { camera.save(); camera.rotateY(-mMaxUnselectedRotateAngle); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); matrix.preScale(mMinUnselectedScale, mMinUnselectedScale, centerX, centerY); // within the rotating, scaling range } else { camera.save(); camera.rotateY(mOffsetRotateCache[centerChild]); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-centerX, -centerY); matrix.postTranslate(centerX, centerY); matrix.preScale(mOffsetScaleCache[centerChild], mOffsetScaleCache [centerChild], centerX, centerY); } return true; } } On Jan 8, 2:41 pm, Flying Coder <av8r.st...@gmail.com> wrote: > Wow - looks great! I'll definitely play around with it and will let > you know if I have any feedback. > > Cheers, > Steve > > On Jan 8, 3:45 am, Taf <neild...@gmail.com> wrote: > > > > > Hi, > > > I've had a go at creating a coverflow like widget. My results can be > > found here: > > >http://www.inter-fuser.com/2010/01/android-coverflow-widget.html > > > If you fancy giving it a try I'd been interested in your feedback. > > I've only tried it on a HTC G1 running Android 1.1 > > > Thanks, > > > Neil.
-- You received this message because you are subscribed to the Google Groups "Android Developers" group. To post to this group, send email to android-developers@googlegroups.com To unsubscribe from this group, send email to android-developers+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/android-developers?hl=en