自定义View—利用Camera实现3D翻转动画
2017-07-12 16:51
387 查看
实现效果图
做这个效果时,开始觉得很懵逼,无从下手,但冷静下来想一想,就是两张图片同时在执行旋转动画,那么我就从一张图片的旋转动画开始摸索。
好,现在就从画一张图开始
自定义Roll3DView,初始化Paint,Camera,Matrix。在onMeasure里对View进行测量,然后对图片进行了适当的伸缩处理。然后就是onDraw方法画出这张图。效果图先不看了,就是一张图。
下面呢,我想让这张做旋转动画,围绕x轴旋转90度,因此我写了startAnimation方法
当我点击图片的时候开始执行startAnimation,变量degree从0到90度变化,动画执行时间为2s,那么onDraw方法要修改
调用Camera的rotateX()方法对图片旋转,看下效果图
这时我们的旋转轴的坐标就是图片的上边沿,图片是围绕着上边沿旋转的。而仔细去看3D效果的Vertical&toNext效果,第一张图的旋转时围绕着图的下边沿旋转的。那么我们就要先将轴线平移到图片的下边沿,然后再旋转的过程中再慢慢回移。修改onDraw
再看看效果,
就是这个效果,可以这么理解。图片是围绕着下边沿进行旋转的,图片的初始角度是0,先移动轴线到图片的下边沿,让图片围绕着下边沿旋转,然后在旋转的过程中将轴线从y=viewHeight位置慢慢移动到坐标y=0。
那么同理,接着看3D翻转Vertical&toNext效果,第二张图翻上来的动画,第二张图片是围绕上图片的上边沿进行旋转的,图片的初始角度是-90度,轴线不用改变,在旋转的过程中将轴线从y=viewHeight位置移动到y=0。
使用同一个animator, degree还是从0到90度变化,代码如下
看效果
两个单独的效果实现了,所以下面就将两个效果合起来,画两张图。
代码到这里当然还没结束,只是分析了其中的一种情况,而其他的情况都跟这中情况是类似的,无非就是是垂直翻转或水平翻转,下一张,前一张的区别,思想都是一样的,代码我也不贴了,如果是想实现这效果的话,最好是自己写个demo,一点点去实现,慢慢琢磨研究,才会记忆深刻。如果你认真写了,你就会发现其实很有很多细节没有处理呢,例如下面:
isRolling是判断当前动画是否执行完成,对图片下标index的初始化,对初始旋转角度的初始化。实现效果后再对代码进行简化,整理,封装等等。
欢迎大家提出不同的理解和看法,共同学习,进步。
做这个效果时,开始觉得很懵逼,无从下手,但冷静下来想一想,就是两张图片同时在执行旋转动画,那么我就从一张图片的旋转动画开始摸索。
好,现在就从画一张图开始
public class Roll3DView extends View { private Bitmap bitmap; private Paint paint; private Camera camera; private Matrix matrix; private int viewWidth; private int viewHeight; private ValueAnimator animator; private float degree; public Roll3DView(Context context) { this(context,null); } public Roll3DView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); bitmap = ((BitmapDrawable)(getResources().getDrawable(R.drawable.img1))).getBitmap(); camera = new Camera(); matrix = new Matrix(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); viewWidth = getMeasuredWidth(); viewHeight = getMeasuredHeight(); bitmap = scaleBitmap(bitmap); } /** * 根据给定的宽和高进行拉伸 * * @param origin 原图 * @return new Bitmap */ private Bitmap scaleBitmap(Bitmap origin) { if (origin == null) { return null; } int height = origin.getHeight(); int width = origin.getWidth(); float scaleWidth = ((float) viewWidth) / width; float scaleHeight = ((float) viewHeight) / height; Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight);// 使用后乘 Bitmap newBM = Bitmap.createBitmap(origin, 0< 4000 /span>, 0, width, height, matrix, false); return newBM; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); camera.getMatrix(matrix); canvas.drawBitmap(bitmap,matrix,paint); canvas.restore(); }
自定义Roll3DView,初始化Paint,Camera,Matrix。在onMeasure里对View进行测量,然后对图片进行了适当的伸缩处理。然后就是onDraw方法画出这张图。效果图先不看了,就是一张图。
下面呢,我想让这张做旋转动画,围绕x轴旋转90度,因此我写了startAnimation方法
public void startAnimation(){ animator = ValueAnimator.ofFloat(0,90); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { degree = (float) valueAnimator.getAnimatedValue(); invalidate(); } }); animator.setDuration(2000); animator.start(); }
当我点击图片的时候开始执行startAnimation,变量degree从0到90度变化,动画执行时间为2s,那么onDraw方法要修改
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); camera.save(); camera.rotateX(degree); camera.getMatrix(matrix); camera.restore(); canvas.drawBitmap(bitmap,matrix,paint); canvas.restore(); }
调用Camera的rotateX()方法对图片旋转,看下效果图
这时我们的旋转轴的坐标就是图片的上边沿,图片是围绕着上边沿旋转的。而仔细去看3D效果的Vertical&toNext效果,第一张图的旋转时围绕着图的下边沿旋转的。那么我们就要先将轴线平移到图片的下边沿,然后再旋转的过程中再慢慢回移。修改onDraw
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); camera.save(); camera.rotateX(degree); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-viewWidth/2,-viewHeight); matrix.postTranslate(viewWidth/2,(1-rate)*viewHeight); canvas.drawBitmap(bitmap,matrix,paint); canvas.restore(); }
再看看效果,
就是这个效果,可以这么理解。图片是围绕着下边沿进行旋转的,图片的初始角度是0,先移动轴线到图片的下边沿,让图片围绕着下边沿旋转,然后在旋转的过程中将轴线从y=viewHeight位置慢慢移动到坐标y=0。
那么同理,接着看3D翻转Vertical&toNext效果,第二张图翻上来的动画,第二张图片是围绕上图片的上边沿进行旋转的,图片的初始角度是-90度,轴线不用改变,在旋转的过程中将轴线从y=viewHeight位置移动到y=0。
使用同一个animator, degree还是从0到90度变化,代码如下
canvas.save(); camera.save(); camera.rotateX(degree-90); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-viewWidth/2,0); matrix.postTranslate(viewWidth/2,(1-rate)*viewHeight); canvas.drawBitmap(bitmap,matrix,paint); canvas.restore();
看效果
两个单独的效果实现了,所以下面就将两个效果合起来,画两张图。
Bitmap curBitmap = bitmapList.get(curIndex); Bitmap nextBitmap = bitmapList.get(nextIndex); canvas.save(); camera.save(); camera.rotateX(rotatedDegree); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-viewWidth / 2, -viewHeight); matrix.postTranslate(viewWidth / 2, (1 - rate) * viewHeight); canvas.drawBitmap(curBitmap, matrix, paint); camera.save(); camera.rotateX(rotatedDegree - 90); camera.getMatrix(matrix); camera.restore(); matrix.preTranslate(-viewWidth / 2, 0); matrix.postTranslate(viewWidth / 2, (1 - rate) * viewHeight); canvas.drawBitmap(nextBitmap, matrix, paint); canvas.restore();
代码到这里当然还没结束,只是分析了其中的一种情况,而其他的情况都跟这中情况是类似的,无非就是是垂直翻转或水平翻转,下一张,前一张的区别,思想都是一样的,代码我也不贴了,如果是想实现这效果的话,最好是自己写个demo,一点点去实现,慢慢琢磨研究,才会记忆深刻。如果你认真写了,你就会发现其实很有很多细节没有处理呢,例如下面:
public void toNext() { if (isRolling) return; animator = ValueAnimator.ofFloat(0, 90); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { rotatedDegree = (float) animation.getAnimatedValue(); setRotateDegree(rotatedDegree); invalidate(); } }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); isRolling = false; setRotateDegree(0); invalidate(); curIndex++; if (curIndex > bitmapList.size() - 1) { curIndex = 0; } initIndex(); } }); animator.setDuration(1000); isNext = true; isRolling = true; animator.start(); }
public void setRotateDegree(float rotateDegree) { this.rotatedDegree = rotateDegree; rate = rotateDegree / 90; }
private void initIndex() { nextIndex = curIndex + 1; preIndex = curIndex - 1; if (nextIndex > bitmapList.size() - 1) { nextIndex = 0; } if (preIndex < 0) { preIndex = bitmapList.size() - 1; } }
isRolling是判断当前动画是否执行完成,对图片下标index的初始化,对初始旋转角度的初始化。实现效果后再对代码进行简化,整理,封装等等。
欢迎大家提出不同的理解和看法,共同学习,进步。
相关文章推荐
- Android利用Camera实现中轴3D卡牌翻转效果
- Android自定义view利用Xfermode实现动态文字加载动画
- Android 利用Camera实现中轴3D卡牌翻转效果
- 【iOS开发-24】导航控制器下不同视图控制器之间切换:利用CATrasition和view的layer层来实现自定义的动画效果
- 60.自定义View练习(五)高仿小米时钟 - 使用Camera和Matrix实现3D效果
- Android自定义动画之实现3D翻转的动画
- iOS开发导航控制器下不同视图控制器之间切换:利用CATrasition和view的layer层来实现自定义的动画效果
- 自定义 View 3d翻转动画 android
- Android利用ViewFlipper实现屏幕切换动画效果
- Android利用ViewFlipper实现屏幕切换动画效果
- 利用View自身的setAnimation来实现动画效果(Hdpfans)
- 利用ViewFlipper实现View间的动画效果(平移/渐变...)
- QGraphic view实例:利用QGraphicsItem与定时器实现动画效果:蝴蝶飞舞
- iPhone开发教程之利用 UIImageView 实现全屏动画的代码例子
- Android利用ViewFlipper实现屏幕切换动画效果(下)
- ios中自定义alert view,并实现动画组合
- android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu
- Android利用ViewFlipper实现屏幕切换动画效果
- Android动画之3D翻转效果实现函数分析
- Android利用ViewFlipper实现屏幕切换动画效果