程序员

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

2016-04-02  本文已影响738人  黑丫山上小旋风

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

前言

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

需求

效果图

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

布局

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

动画

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

<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);
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

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);

最后祝大家节日快乐

上一篇 下一篇

猜你喜欢

热点阅读