本文主要是介绍仿格瓦拉转场动画,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
下载地址:Demo
2016-04-21 问题记录
init 方法中初始化画布的宽度和高度: 适配所有手机
canvaswWidth = context.getResources().getDisplayMetrics().widthPixels;
canvasHeight = context.getResources().getDisplayMetrics().heightPixels;
转场动画效果图:
xfermode遮罩层效果图:
显示逻辑:
1,图片的平移动画 时间:2s
2,1s的时候,执行add Frament
3,平移动画执行结束,执行放大圆的绘制
隐藏逻辑:
1,缩小圆的绘制
2,图片还原动画
系统要求和主要类:
android系统:2.2
第三方图片框架:glide-3.7.0.jar
view完整效果:
FlyCircleActivity+FlyCircleAnimView+FlyCircleDetailsFragment
FlyCircleAnimView:
package com.heaven.circleanimview.views.flowview;/*** 画布的宽度高度需要初始化<br>* 圆点坐标和图片的宽高也是需要初始化的,这个跟详情界面的图片位置有关<br>* maxRadius根据圆心点算出<br>*/
public class FlyCircleAnimView extends RelativeLayout{protected Handler handler;protected FlyBean fly;public ImageView iv_fly;private Canvas myCanvas; // 画布private Bitmap originalBitmap; // 画布bitmap/*** 画笔*/protected Paint paint = null ;/*** 画布重叠部分的显示模式*/private Xfermode xfermode ;/*** 圆的半径*/private int radius = 2100;/*** 最大半径,根据圆心点坐标算出*/private int maxRadius = 2000;/*** 默认半径*/private int defaultRadius = 200;/*** 放大 step 值越大执行的时间越短*/private int step = 150;/*** 图片的宽度*/private int imgWidth = 312;/*** 图盘的高度*/private int imgHeight = 420;/*** 图片距离左边的距离*/private int imgLeft = 36; // 和FlowViewHelper中的left值一样/*** 图片距离上边的距离*/private int imgTop = 624;/*** 圆的中心点 x坐标*/private int cx=imgLeft+imgWidth/2; // 32 312/*** 圆的中心点 y坐标*/private int cy=imgTop+imgHeight/2; // 624 420/*** 画布的宽度*/private int canvaswWidth = 1080;/*** 画布的高度*/private int canvasHeight = 1920;/*** 遮罩层颜色*/private int maskColor = Color.RED;/*** 放大还是收缩 true 放大,false 收缩*/boolean isBigZoom = true;/*** 图片的点击位置*/protected Rect localRect = null;/*** false 不绘制圆。 true 绘制*/protected boolean isCircleAnim = false;public FlyCircleAnimView(Context context, AttributeSet attrs) {super(context, attrs);LayoutInflater.from(context).inflate(R.layout.flow_layout,this);iv_fly = (ImageView)findViewById(R.id.iv_fly);init(context);}public FlyCircleAnimView(Context context) {super(context);init(context);}public FlyCircleAnimView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context);}/*** 可以不用初始化,在外部初始化数据* @param context*/private void init(Context context){this.setWillNotDraw(false);setClipChildren(false);paint = new Paint();paint.setAntiAlias(true);paint.setStyle(Style.FILL);xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);maskColor = Color.parseColor("#c8c8c8");originalBitmap = Bitmap.createBitmap(canvaswWidth, canvasHeight, Bitmap.Config.ARGB_4444);myCanvas = new Canvas(originalBitmap);
// myCanvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));myCanvas.drawColor(maskColor); // 默认背景/*** 根据圆心点坐标算出 maxRadius 向上取整,保证圆的边界要在屏幕外。* 有些底部导航栏可以隐藏的,获取的高度是不准确的,要有对应的高度调整逻辑。*/maxRadius = (int) Math.ceil(Math.sqrt((canvaswWidth - cx)*(canvaswWidth - cx) +(canvasHeight - cy)*(canvasHeight - cy)));System.out.println("maxRadius = "+ maxRadius);radius = maxRadius+10; // 只是为了开始的时候不绘制// 初始化图片的宽度和高度,图片的左上点坐标imgWidth = (int) context.getResources().getDimension(R.dimen.flycircle_img_width);imgHeight = (int) context.getResources().getDimension(R.dimen.flycircle_img_height);imgLeft = (int) context.getResources().getDimension(R.dimen.flycircle_img_left);;imgTop = (int) context.getResources().getDimension(R.dimen.flycircle_img_top);;cx=imgLeft+imgWidth/2; // 32 312cy=imgTop+imgHeight/2; // 624 420LogUtil.e(this, "imgWidth = "+ imgWidth + " imgHeight="+imgHeight + " imgLeft"+imgLeft + " imgTop="+imgTop+ " cx"+cx + " cy="+cy);}@Overrideprotected void onDraw(Canvas canvas) {/*if (isCircleAnim){canvas.drawColor(Color.parseColor("#c8c8c8"));LogUtil.e(this, "onDraw = ========== isCircleAnim = " +isCircleAnim + " w = "+ PhoneInfoUtil.widthPixels + " h = "+PhoneInfoUtil.heightPixels);paint.setXfermode(null);paint.setColor(getContext().getResources().getColor(R.color.c5));if(radius < PhoneInfoUtil.widthPixels/2){canvas.drawCircle(PhoneInfoUtil.widthPixels/2,PhoneInfoUtil.heightPixels/2,radius,paint);radius +=10;invalidate();}else{paint.setColor(Color.parseColor("#ffff0000"));canvas.drawCircle(PhoneInfoUtil.widthPixels/2,PhoneInfoUtil.heightPixels/2,radius,paint);sendMessage(fly,100);}}else { zoomDraw(canvas);}*/if(isCircleAnim){zoomDraw(canvas);}else{}}/*** 110 放大圆绘制完毕 111 缩小圆绘制完毕*/private void sendMessage(FlyBean fly,int what) {if(handler!=null){Message msg = handler.obtainMessage();msg.obj = fly;msg.what = what;handler.sendMessage(msg);}}/*** @param canvas*/private void zoomDraw(Canvas canvas) {try {// 记得还原透明背景,否则绘制圆的操作不显示(背景一直是灰色的)setBackgroundColor(Color.parseColor("#00000000"));
// canvas.drawColor(maskColor);LogUtil.e(this, "zoomDraw isBigZoom = "+isBigZoom + " radius ="+radius);if(isBigZoom){if(radius<=maxRadius){ // 放大paint.setXfermode(null);paint.setColor(maskColor);myCanvas.drawRect(0, 0, canvaswWidth, canvasHeight, paint);// 和之前的画布做交互处理。 在该步骤之前可以重绘画布paint.setXfermode(xfermode);
// paint.setColor(Color.BLUE);//可以不用设置颜色myCanvas.drawCircle(cx, cy, radius, paint);radius+=step;invalidate();}else{sendMessage(fly,110);}}else{// 缩小if(radius<=maxRadius && radius >=0){paint.setXfermode(null); // 如果不设置为null,每次都会和之前的画布做重叠运算操作。 paint.setColor(maskColor); myCanvas.drawRect(0, 0, canvaswWidth, canvasHeight, paint);// SRC_IN 取两层绘制交集,显示上层(后来画的) DST_IN 取两层绘制交集。显示下层。// DST_OUT 取下层绘制非交集部分。 SRC_OUT 取上层绘制非交集部分(上层的非交集部分)
// paint.setColor(Color.BLUE); // out 下层颜色设置无效paint.setXfermode(xfermode);myCanvas.drawCircle(cx, cy, radius, paint);radius-=step;
// Thread.sleep(1000);invalidate();}else{paint.setXfermode(null);paint.setColor(maskColor);myCanvas.drawRect(0, 0, canvaswWidth, canvasHeight, paint);paint.setXfermode(xfermode);myCanvas.drawCircle(cx, cy, maxRadius, paint);
// myCanvas.drawColor(maskColor);sendMessage(fly,111);}}
// Thread.sleep(1000);canvas.drawBitmap(originalBitmap, 0, 0, null);} catch (Exception e) {e.printStackTrace();}}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {LogUtil.e(this, "onLayout = " + l + " = " + l + " t = " + t + " r=" + r + " b = " + b + " ");super.onLayout(changed, l, t, r, b);if (localRect != null) {ViewGroup vg = (ViewGroup) getChildAt(0);// 固定图片的位置vg.getChildAt(0).layout(localRect.left, localRect.top, localRect.right, localRect.bottom);LogUtil.e(this, "onLayout = " + l + " = " + l + " t = " + t + " r=" + r + " b = " + b + " iv = " + vg.getChildAt(0));LogUtil.e(this, "onLayout width = " + vg.getChildAt(0).getWidth() + " height = "+ vg.getChildAt(0).getHeight());}}/*** 执行动画。 通过handler发送消息: what==2 添加fragment what ==100 动画执行结束* @param fly* @param handler*/public void setVisibility(FlyBean fly,Handler handler ) {this.handler = handler;this.localRect = fly.rect;this.fly = fly;isCircleAnim = false;radius = defaultRadius;LogUtil.e(this, "setVisibility rect = " + localRect.toString());setBackgroundColor(maskColor); setVisibility(View.VISIBLE);FlowViewHelper.startAnim(getContext(),fly,this,handler);GlideUtil.displayImage(getContext(), fly.movie.movie_img_url,iv_fly);requestLayout();invalidate();}public void revertAnim(FlyBean fly,Handler handler){isCircleAnim = false;FlowViewHelper.revertAnim(getContext(),fly,this,handler);}public void startCircleAnim(Handler handler){this.handler = handler;isCircleAnim = false;invalidate();}/*** * @param tag 1 放大 0 缩小*/public void startAnim(int tag){isCircleAnim = true;if(tag == 1){isBigZoom = true;System.out.println("startAnim==============放大");radius = defaultRadius;invalidate();}else{setVisibility(View.VISIBLE);isBigZoom = false;System.out.println("startAnim==============收缩");radius = maxRadius;invalidate();}}/*** @return the imgLeft*/public int getImgLeft() {return imgLeft;}/*** @param imgLeft the imgLeft to set*/public void setImgLeft(int imgLeft) {this.imgLeft = imgLeft;}/*** @return the imgTop*/public int getImgTop() {return imgTop;}/*** @param imgTop the imgTop to set*/public void setImgTop(int imgTop) {this.imgTop = imgTop;}
}
下载地址:Demo
这篇关于仿格瓦拉转场动画的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!