受iOS版本的启发,在最近的一个项目中,我们决定在打开列表元素时实现类似风格的动画。起初,我们尝试使用现有的实现-android-flip,它通过OpenGL渲染动画-在最新版本的Android中,它只能在屏幕上显示相对明显的伪影(图片闪烁)。另外这个类库需要改一下,因为它是为滑动列表元素设计的,但是我们的项目需要有打开列表元素的动画效果。您可以在下面的演示视频中看到不同之处:android-flip实现的是折叠列表,而我们真正需要的是展开细节。考虑到这种情况,我们决定自己实现效果。因为应用支持的Android最低版本为4.0,所以没有使用OpenGL,而是使用标准AndroidSDK中的方法:View.setRotationX()、View.setScaleX()等。当开启硬件加速时(硬件加速是如果目标API级别>=14,则默认启用),这些方法可以非常有效地利用GPU。事实证明它很棒,所以决定分享我们是如何做到的。由于本文只介绍了基本的实现要点,您可以从GitHub下载所有实际代码:FoldableLayout。布局的实施设计的第一个元素是可以对折的布局。我们的做法相当大胆:主布局(FoldableItemLayout)只包含一个特定的布局(在baselayout中)。在动画过程中,BaseLayout将其内容写入缓存,缓存是根据原始布局的尺寸专门创建的Bitmap对象。classFoldableItemLayoutextendsFrameLayout{@OverrideprotectedvoidonSizeChanged(intw,inth,intoldw,intoldh){BitmapcacheBitmap=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);mBaseLayout.setCacheCanvas(newCanvas(cacheBitmap));}}classBaseLayoutextendsFrameLayout{privateCanvasmCacheCanvasCavas;privateCanvasmCacheCanvasCavas(privateCanvasmCacheCanvasCavas)){mCacheCanvas=cacheCanvas;}@Overridepublicvoiddraw(Canvascanvas){mCacheCanvas.drawColor(0,PorterDuff.Mode.CLEAR);super.draw(mCacheCanvas);}}此外,还需要两个额外的视图(PartView)——在图像的上半部分和下半部分。它们会在缓存中显示相应的数据,分别代表图片(Bitmap)的上半部分和下半部分。这两个视图填充了主布局的整个区域,但只显示了需要的部分。为了实现这种效果,我们计算位图的边界——在onDraw()方法中,我们让画布通过[drawBitmap(Bitmapbitmap,Rectsrc,RectFdst,Paintpaint)](http://developer.android.com/reference/android/graphics/Canvas.html#drawBitmap(android.graphics.Bitmap,android.graphics.Rect,android.graphics.RectF,android.graphics.Paint))方法绘制需要的部分。然后尝试通过setRotationX()方法设置相应的角度来旋转这些额外的视图,这样图像的上下半部分就可以独立旋转了。为实现此功能,我们向FoldableItemLayout添加了一个名为FoldRotation的新参数。FoldRotation参数范围为(-180,180]:FoldRotation=0:两部分都不旋转。这种情况下,我们可以跳过位图缓存,实时显示原始布局。0
