Android Gallery 3D效果(2)

扩展系统的gallery,我们需要重写两个方法,getChildStaticTransformation()和getChildDrawingOrder(),同时,要使这两个方法能被调用,必须执行如下两行代码,文档上面是有说明的。

// Enable set transformation.
        this.setStaticTransformationsEnabled(true);
        // Enable set the children drawing order.
        this.setChildrenDrawingOrderEnabled(true);

getChildDrawingOrder的实现

@Override
    protected int getChildDrawingOrder(int childCount, int i)
    {
        // Current selected index.
        int selectedIndex = getSelectedItemPosition() - getFirstVisiblePosition();
        if (selectedIndex < 0)
        {
            return i;
        }
       
        if (i < selectedIndex)
        {
            return i;
        }
        else if (i >= selectedIndex)
        {
            return childCount - 1 - i + selectedIndex;
        }
        else
        {
            return i;
        }
    }

这里为什么要计算drawing order,因为从上图中看到,我们的效果是:中间左边的顺序是 0, 1, 2,右边的child覆盖左边的child,而在中间右边的顺序正好相反,左边的覆盖右边的,所以我们要重写这个方法,而gallery自身的实现,不是这种效果。

getChildStaticTransformation的实现

@Override
    protected boolean getChildStaticTransformation(View child, Transformation t)
    {
        super.getChildStaticTransformation(child, t);
       
        final int childCenter = getCenterOfView(child);
        final int childWidth  = child.getWidth();
       
        int rotationAngle = 0;
        t.clear();
        t.setTransformationType(Transformation.TYPE_MATRIX);
       
        // If the child is in the center, we do not rotate it.
        if (childCenter == mCoveflowCenter)
        {
            transformImageBitmap(child, t, 0);
        }
        else
        {
            // Calculate the rotation angle.
            rotationAngle = (int)(((float)(mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);
           
            // Make the angle is not bigger than maximum.
            if (Math.abs(rotationAngle) > mMaxRotationAngle)
            {
                rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;
            }
           
            transformImageBitmap(child, t, rotationAngle);
        }
       
        return true;
    }

这个方法就是根据child来计算它的transformation(变换),我们需要去修改它里面的matrix,从而达到旋转的效果。根据位置和角度来计算的matrix的方法写在另外一个方法transformImageBitmap中实现。

transformImageBitmap()的实现

private void transformImageBitmap(View child, Transformation t, int rotationAngle)
    {
        mCamera.save();
       
        final Matrix imageMatrix = t.getMatrix();
        final int imageHeight = child.getHeight();
        final int imageWidth  = child.getWidth();
        final int rotation    = Math.abs(rotationAngle);
       
        // Zoom on Z axis.
        mCamera.translate(0, 0, mMaxZoom);
       
        if (rotation < mMaxRotationAngle)
        {
            float zoomAmount = (float)(mMaxZoom + rotation * 1.5f);
            mCamera.translate(0, 0, zoomAmount);
        }
       
        // Rotate the camera on Y axis.
        mCamera.rotateY(rotationAngle);
        // Get the matrix from the camera, in fact, the matrix is S (scale) transformation.
        mCamera.getMatrix(imageMatrix);
       
        // The matrix final is T2 * S * T1, first translate the center point to (0, 0),
        // then scale, and then translate the center point to its original point.
        // T * S * T
       
        // S * T1
        imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));
        // (T2 * S) * T1
        imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));
       
        mCamera.restore();
    }

这里,简单说明一个,

第一,先在Z轴上平称,其实就是得到一个缩放矩阵变换,我这里简写为 S。

第二,是利用camera这个类来生成matrix,其实mCamera.rotateY就是围绕Y轴旋转。这里生成了一个旋转矩阵,记为 R 。经过这两步,此时调用mCamera.getMatrix(imageMatrix); 从Camera中得到matrix,此时这个矩阵中包含了S * R。

第三,最关键是下面两句

// S * T1
imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));
// (T2 * S) * T1
imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));

由于这里涉及到旋转与缩放,缩放操作其实应该是针对Child中点进行了,这里就是作一个平衡操作,我们必须是先平移,再缩放,再平移回原来位置,所以,我们最终的矩阵变换应该是这样的:

M = T * (S * R) * T1 (这里在T1表示与T相反)。

linux

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/2475baf7585ea79e6f088ce969a8bd09.html