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 <[email protected]> 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 <[email protected]> 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 [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en