I would like to make vertical 3d list view like here, but for ImageButtons and for free. Is there any library or sample code for that? I am new in Android development, so I don't know how to animate such thing
Asked
Active
Viewed 1.0k times
1 Answers
10
its actually pretty simple. You need to extend ListView and override onDrawChild(). In there you can apply 3d transformation matrices to get the effect you want. I have a working example on my github Or you can have a look at this question which is quite similar.
For your convenience this is my implementation of a 3d ListView:
public class ListView3d extends ListView {
/** Ambient light intensity */
private static final int AMBIENT_LIGHT = 55;
/** Diffuse light intensity */
private static final int DIFFUSE_LIGHT = 200;
/** Specular light intensity */
private static final float SPECULAR_LIGHT = 70;
/** Shininess constant */
private static final float SHININESS = 200;
/** The max intensity of the light */
private static final int MAX_INTENSITY = 0xFF;
private final Camera mCamera = new Camera();
private final Matrix mMatrix = new Matrix();
/** Paint object to draw with */
private Paint mPaint;
public ListView3d(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
// get top left coordinates
final int top = child.getTop();
final int left = child.getLeft();
Bitmap bitmap = child.getDrawingCache();
if (bitmap == null) {
child.setDrawingCacheEnabled(true);
child.buildDrawingCache();
bitmap = child.getDrawingCache();
}
final int centerY = child.getHeight() / 2;
final int centerX = child.getWidth() / 2;
final int radius = getHeight() / 2;
final int absParentCenterY = getTop() + getHeight() / 2;
final int absChildCenterY = child.getTop() + centerX;
final int distanceY = absParentCenterY - absChildCenterY;
final int absDistance = Math.min(radius, Math.abs(distanceY));
final float translateZ = (float) Math.sqrt((radius * radius) - (absDistance * absDistance));
double radians = Math.acos((float) absDistance / radius);
double degree = 90 - (180 / Math.PI) * radians;
mCamera.save();
mCamera.translate(0, 0, radius - translateZ);
mCamera.rotateX((float) degree); // remove this line..
if (distanceY < 0) {
degree = 360 - degree;
}
mCamera.rotateY((float) degree); // and change this to rotateX() to get a
// wheel like effect
mCamera.getMatrix(mMatrix);
mCamera.restore();
// create and initialize the paint object
if (mPaint == null) {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setFilterBitmap(true);
}
//highlight elements in the middle
mPaint.setColorFilter(calculateLight((float) degree));
mMatrix.preTranslate(-centerX, -centerY);
mMatrix.postTranslate(centerX, centerY);
mMatrix.postTranslate(left, top);
canvas.drawBitmap(bitmap, mMatrix, mPaint);
return false;
}
private LightingColorFilter calculateLight(final float rotation) {
final double cosRotation = Math.cos(Math.PI * rotation / 180);
int intensity = AMBIENT_LIGHT + (int) (DIFFUSE_LIGHT * cosRotation);
int highlightIntensity = (int) (SPECULAR_LIGHT * Math.pow(cosRotation, SHININESS));
if (intensity > MAX_INTENSITY) {
intensity = MAX_INTENSITY;
}
if (highlightIntensity > MAX_INTENSITY) {
highlightIntensity = MAX_INTENSITY;
}
final int light = Color.rgb(intensity, intensity, intensity);
final int highlight = Color.rgb(highlightIntensity, highlightIntensity, highlightIntensity);
return new LightingColorFilter(light, highlight);
}
}
Cheers
-
When I try to download your project through Git, Eclipse can't find any projects in there. I tried downloading as Zip and directly from git. The same issue. Also tried to configure your project, but there goes lots of errors – Paulius Vindzigelskis Apr 05 '12 at 10:59
-
I dont like to have project files in my repositories. But this should be no problem as you can simply do the following: 1. download as zip. 2. Extract to a folder of your choice. 3. In eclipse do new->Android Project->Create Project from existing source. 4. Set Build target to android 4 or remove hardwareacceleration from the manifest. Maybe you also need to clean the project.. – Renard Apr 05 '12 at 11:15
-
With some corrections, I got your code to work, but there is another problem: how to change position to selected row? also, how to make rows to overlay each other. Like here: [link](http://img6.imageshack.us/img6/1375/snor1.jpg) – Paulius Vindzigelskis Apr 10 '12 at 08:44
-
ListView.setSelection(int) will scroll to a position of your choice. For the overlap you can use mMatrix to position the child views. – Renard Apr 10 '12 at 09:05
-
You can change the drawing order the children with setChildrenDrawingOrderEnabled() and overriding getChildDrawingOrder(). This way you should manage to get the correct overlap( draw order is basically dependent on the z-value). As for the space between rows you can try to increase the padding or margin in the layout-xml for the child-views. – Renard Apr 20 '12 at 08:14
-
How change overlap to below center rows? I changed translate z axis, so it looks like overlapping, but all rows overlaps each other going down. So last row is always on top and first row is always on bottom (Seeing as layers) – Paulius Vindzigelskis Apr 20 '12 at 08:21
-
Overlap is dependent on drawing order so you need to override getChildDrawingOrder() and specify that the items wich have the largest z-translation are drawn first – Renard Apr 20 '12 at 08:27
-
Is there any way to preserve the transparency of the view when using this 3d list view? beacuse my view background is not semi transprent. – null pointer Feb 05 '13 at 09:47
-
A small correction, this ==> "final int absChildCenterY = child.getTop() + centerX;" should be " + centerY" – subiet Sep 24 '14 at 11:51
-
How to start reverse the animation from top to bottom? – Moorthy Feb 13 '18 at 06:58