仿格瓦拉转场动画

下载地址: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  312
        cy=imgTop+imgHeight/2; // 624  420
        LogUtil.e(this, "imgWidth = "+ imgWidth + " imgHeight="+imgHeight 
                + " imgLeft"+imgLeft + " imgTop="+imgTop
                + " cx"+cx + " cy="+cy
                );
    }


    @Override
    protected 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();
        }
    }

    @Override
    protected 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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值