美文网首页程序员
子控件实现全屏动画的某些坑

子控件实现全屏动画的某些坑

作者: 黑丫山上小旋风 | 来源:发表于2016-04-02 22:21 被阅读738次

转载请附原文地址:http://www.jianshu.com/p/f9c0b00efd14

前言

因为公司UI需要撸一个动效,然后我又一个人没有人约,别人在嗨嗨嗨,嘿嘿嘿,呵呵呵的时候,我只能在家里默默撸代码。一个很简单的位移动画,因为嵌套布局,出现了一些蛋疼的坑。记录一下,以后碰就可以绕过了。
在这里感谢洋葱司机提供思路,帮我解决了这个问题

需求

效果图

需求是,这四个分享控件按照比例,分布在屏幕靠近中央的矩形范围内,每个图标左右,上下的间距都是按权重来分配,避免在大屏幕太靠中间,小屏幕又太靠边。弹窗弹出时,四个图标依次从屏幕底部飞入。

布局

根布局为LinearLayout,orientation="vertical"
每一排图标为一个水平的LinearLayout

动画

布局写完了,开始撸动画。
这里很容易想到,用TranslateAnimation,so easy

  • 第一个坑来了。(子控件被限制视图)
    因为四个控件的父布局是水平的LinearLayout(简称二级布局),当控件移动到二级布局的边缘时就没有视图了,看不见了~坑爹啊。
    于是我去求助,见多识广的洋葱老司机给了我一个思路,在window上加一个布局用来做动画,这个布局只用来做动画,动画完成后消失,布局背景设置为透明。
    先写一个动画布局,把需要做动效的控件copy一份到这个布局中
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:background="#00ffffff"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
      <!-- 这里放你的控件-->        
</RelativeLayout>
  • 又踩了个坑(布局特性)
    一开始根布局用的是线性布局,结果有两个控件被挤出去了。。。
    这是个小问题

  • 在代码中添加动画图层

View animWindow=LayoutInflater.from(mActivity).inflate(R.layout.popupwindow_anim, null);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
        WindowManager.LayoutParams.MATCH_PARENT,
        WindowManager.LayoutParams.MATCH_PARENT,
        0, 0, 
       WindowManager.LayoutParams.TYPE_TOAST, 
       WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,                  
       PixelFormat.RGBA_8888);
windowManager.addView(animWindow, params);

拿到四个子控件

LinearLayout weixinCircle = (LinearLayout) animWindow.findViewById(R.id.ll_share_wx_circle);
LinearLayout weixin = (LinearLayout) animWindow.findViewById(R.id.ll_share_wx);
LinearLayout sina = (LinearLayout) animWindow.findViewById(R.id.ll_share_sina);
LinearLayout copy = (LinearLayout) animWindow.findViewById(R.id.ll_share_url);
  • 获取子控件的坐标
    为了让动画图层中的控件位置和实际位置精确重合,需要计算一下每个控件的位置,getLocationInWindow(location);可以获取在窗口内的坐标,具体用什么方法获取看具体需求,这里我的popwindow已经对statusbar做了适配处理,所以直接获取window坐标就可以了
getLocationInWindow(location);
getLocationOnScreen(location);
getGlobalVisibleRect(rect);

不一一列举了,搜一下一堆。
这里有个坑,如果绘制还没有完成的情况下去获取坐标,会得到0,并没有什么卵用
怎么判断绘制完毕,也有很多方法,也不一一列举了,我用的 ViewTreeObserver

ViewTreeObserver viewTreeObserver = mWeixinCircle.getViewTreeObserver();
viewTreeObserver
        .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                mWeixinCircle.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                startEnterAnimation();
            }
        });

别忘了remove

  • 绘制完成后获取坐标启动动画,并监听
    动画的代码就不写,几行代码。原来的popwindow初始化后,将四个控件隐藏
    常用的监听方法,在onAnimationEnd中,将四个控件显示出来,并remove动画图层
ta.setAnimationListener(new Animation.AnimationListener() {
    @Override
    public void onAnimationStart(Animation animation) {    }
    @Override
    public void onAnimationEnd(Animation animation) {
      mWeixinCircle.setVisibility(View.VISIBLE);
      mWeixin.setVisibility(View.VISIBLE);
      mSina.setVisibility(View.VISIBLE);
      mCopy.setVisibility(View.VISIBLE);
      windowManager.removeView(animWindow);
    }
    @Override
    public void onAnimationRepeat(Animation animation) {    }
});

坑爹的又来了
测试中,这个方法在进入动画时正常,退出动画时没有被调用!
查阅官方文档,当动画被设置为无限重复时,不会被调用。

This callback is not invoked for animations with repeat count set to INFINITE.

WTF?我没有设置重复啊?
上stackoverflow找到一个相关问题,这哥们儿是这么回答的
原文链接:http://stackoverflow.com/questions/5474923/onanimationend-is-not-getting-called-onanimationstart-works-fine

AnimationEnd
is not reliable. If you don't want to rewrite your code with custom views that override OnAnimationEnd, use postDelayed.
While it MAY seem ugly, I can guarantee it's very reliable. I use it for ListViews that are inserting new rows while removing with animation to other rows. Stress testing a listener with AnimationEnd proved unreliable. Sometimes AnimationEnd
was never triggered. You might want to reapply any transformation in the postDelayed
function in case the animation didn't fully finish, but that really depends on what type of animation you're using.

坑爹啊,用postDelayed吧,起码靠谱~

handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        ULog.d("isEnter=" + isEnter);
        if (isEnter) {
            mWeixinCircle.setVisibility(View.VISIBLE);
            mWeixin.setVisibility(View.VISIBLE);
            mSina.setVisibility(View.VISIBLE);
            mCopy.setVisibility(View.VISIBLE);
        } else {
            CustomShareBoard.this.dismiss();
        }
        windowManager.removeView(animWindow);
    }
}, 700);

最后祝大家节日快乐

相关文章

  • 子控件实现全屏动画的某些坑

    转载请附原文地址:http://www.jianshu.com/p/f9c0b00efd14 前言 因为公司UI需...

  • Android 动画

    Android 的动画不管是补间动画还是属性动画,都只能让子view在其父控件内实现动画,而有一些动画需求必须要让...

  • UIViewAnimationOptions的讲解

    UIViewAnimationOptionLayoutSubviews //提交动画的时候布局子控件,表示子控件将...

  • iOS-动画相关

    本篇涵盖各种直播动画,跳转,过渡动画等. 1.分享iOS中实现navigationController全屏手势滑动...

  • CATransition基础

    简介 CATransition通常用于通过CALayer控制UIView内子控件的过渡动画,比如删除子控件,添加子...

  • 通知和代理区别和使用

    (一)代理Delegate 1.使用的场合 主要用于子控件发生某些动作时,通知父控件,子控件的代理是父控件。常见就...

  • iOS动画学习之缩放控件

    实现控件的缩放很简单,就是用动画改变frame的大小。 和操作layer的动画不同,控件缩放其实是调用UIView...

  • 聊聊自定义View那些事

    为什么要自定义View 为了实现某些炫酷的动画和效果。 为了优化应用性能。 系统控件满足不了需要 如何自定义Vie...

  • 自定义View

    自定义控件的三种实现方法 对现有控件进行拓展 通过组合来实现新的控件:将系统原生控件组合起来,加上动画效果,形成一...

  • Android动画基础详析 | 属性动画基础及ValueAnim

    为什么要引入属性动画 逐帧动画主要是用来实现动画的,而补间动画才能实现控件的渐入渐出、移动、旋转和缩放效果;属性动...

网友评论

    本文标题:子控件实现全屏动画的某些坑

    本文链接:https://www.haomeiwen.com/subject/vpxulttx.html