com.taobao.weex.ui.action.GraphicActionAnimation.java Source code

Java tutorial

Introduction

Here is the source code for com.taobao.weex.ui.action.GraphicActionAnimation.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package com.taobao.weex.ui.action;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.animation.PathInterpolatorCompat;
import android.text.TextUtils;
import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;

import com.alibaba.fastjson.JSONObject;
import com.taobao.weex.WXSDKInstance;
import com.taobao.weex.WXSDKManager;
import com.taobao.weex.ui.animation.BackgroundColorProperty;
import com.taobao.weex.ui.animation.HeightProperty;
import com.taobao.weex.ui.animation.WXAnimationBean;
import com.taobao.weex.ui.animation.WXAnimationModule;
import com.taobao.weex.ui.animation.WidthProperty;
import com.taobao.weex.ui.component.WXComponent;
import com.taobao.weex.ui.component.list.template.TemplateDom;
import com.taobao.weex.ui.view.border.BorderDrawable;
import com.taobao.weex.utils.SingleFunctionParser;
import com.taobao.weex.utils.WXLogUtils;
import com.taobao.weex.utils.WXResourceUtils;
import com.taobao.weex.utils.WXUtils;
import com.taobao.weex.utils.WXViewUtils;

import java.util.HashMap;
import java.util.List;

public class GraphicActionAnimation extends BasicGraphicAction {

    private final static String TAG = "GraphicActionAnimation";

    private final boolean styleNeedInit;

    @Nullable
    private final String callback;

    @Nullable
    private WXAnimationBean mAnimationBean;

    public GraphicActionAnimation(@NonNull WXSDKInstance instance, @NonNull String ref,
            @NonNull WXAnimationBean animationBean) {
        super(instance, ref);
        this.styleNeedInit = false;
        this.callback = null;
        this.mAnimationBean = animationBean;
    }

    public GraphicActionAnimation(@NonNull WXSDKInstance instance, @NonNull String ref, @Nullable String animation,
            @Nullable final String callBack) {
        super(instance, ref);
        this.styleNeedInit = true;
        this.callback = callBack;
        if (!TextUtils.isEmpty(animation)) {
            this.mAnimationBean = JSONObject.parseObject(animation, WXAnimationBean.class);
        }
    }

    public GraphicActionAnimation(@NonNull WXSDKInstance instance, @NonNull String ref,
            @NonNull WXAnimationBean animationBean, @Nullable final String callBack) {
        super(instance, ref);
        this.styleNeedInit = false;
        this.mAnimationBean = animationBean;
        this.callback = callBack;
    }

    @Override
    public void executeAction() {
        if (null == mAnimationBean) {
            return;
        }

        WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(),
                getRef());
        if (component == null) {
            if (!TemplateDom.isVirtualDomRef(getRef())) {
                return;
            }
            component = TemplateDom.findVirtualComponentByVRef(getPageId(), getRef());
            if (component == null) {
                return;
            }
        }

        WXSDKInstance instance = WXSDKManager.getInstance().getWXRenderManager().getWXSDKInstance(getPageId());
        if (instance == null) {
            return;
        }

        if (null != mAnimationBean.styles) {
            if (styleNeedInit) {
                mAnimationBean.styles.init(mAnimationBean.styles.transformOrigin, mAnimationBean.styles.transform,
                        (int) component.getLayoutWidth(), (int) component.getLayoutHeight(),
                        instance.getInstanceViewPortWidth(), instance);
            }
            startAnimation(instance, component);
        }
    }

    private void startAnimation(@NonNull WXSDKInstance instance, @Nullable WXComponent component) {
        if (component != null) {
            if (mAnimationBean != null) {
                component.setNeedLayoutOnAnimation(mAnimationBean.needLayout);
            }
            if (component.getHostView() == null) {
                WXAnimationModule.AnimationHolder holder = new WXAnimationModule.AnimationHolder(mAnimationBean,
                        callback);
                component.postAnimation(holder);
            } else {
                try {
                    Animator animator = createAnimator(component.getHostView(),
                            instance.getInstanceViewPortWidth());
                    if (animator != null) {
                        Animator.AnimatorListener animatorCallback = createAnimatorListener(instance, callback);
                        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2
                                && component.isLayerTypeEnabled()) {
                            component.getHostView().setLayerType(View.LAYER_TYPE_HARDWARE, null);
                        }
                        Interpolator interpolator = createTimeInterpolator();
                        if (animatorCallback != null) {
                            animator.addListener(animatorCallback);
                        }
                        if (interpolator != null) {
                            animator.setInterpolator(interpolator);
                        }
                        component.getHostView().setCameraDistance(mAnimationBean.styles.getCameraDistance());
                        animator.setDuration(mAnimationBean.duration);
                        animator.start();
                    }
                } catch (RuntimeException e) {
                    WXLogUtils.e(TAG, WXLogUtils.getStackTrace(e));
                }
            }
        }
    }

    private @Nullable ObjectAnimator createAnimator(final View target, final int viewPortWidth) {
        if (target == null) {
            return null;
        }
        WXAnimationBean.Style style = mAnimationBean.styles;
        if (style != null) {
            ObjectAnimator animator;
            List<PropertyValuesHolder> holders = style.getHolders();
            if (!TextUtils.isEmpty(style.backgroundColor)) {
                BorderDrawable borderDrawable;
                if ((borderDrawable = WXViewUtils.getBorderDrawable(target)) != null) {
                    holders.add(PropertyValuesHolder.ofObject(new BackgroundColorProperty(), new ArgbEvaluator(),
                            borderDrawable.getColor(), WXResourceUtils.getColor(style.backgroundColor)));
                } else if (target.getBackground() instanceof ColorDrawable) {
                    holders.add(PropertyValuesHolder.ofObject(new BackgroundColorProperty(), new ArgbEvaluator(),
                            ((ColorDrawable) target.getBackground()).getColor(),
                            WXResourceUtils.getColor(style.backgroundColor)));
                }
            }

            if (target.getLayoutParams() != null
                    && (!TextUtils.isEmpty(style.width) || !TextUtils.isEmpty(style.height))) {
                ViewGroup.LayoutParams layoutParams = target.getLayoutParams();
                if (!TextUtils.isEmpty(style.width)) {
                    holders.add(PropertyValuesHolder.ofInt(new WidthProperty(), layoutParams.width,
                            (int) WXViewUtils.getRealPxByWidth(WXUtils.getFloat(style.width), viewPortWidth)));
                }
                if (!TextUtils.isEmpty(style.height)) {
                    holders.add(PropertyValuesHolder.ofInt(new HeightProperty(), layoutParams.height,
                            (int) WXViewUtils.getRealPxByWidth(WXUtils.getFloat(style.height), viewPortWidth)));
                }
            }

            if (style.getPivot() != null) {
                Pair<Float, Float> pair = style.getPivot();
                target.setPivotX(pair.first);
                target.setPivotY(pair.second);
            }
            animator = ObjectAnimator.ofPropertyValuesHolder(target,
                    holders.toArray(new PropertyValuesHolder[holders.size()]));
            animator.setStartDelay(mAnimationBean.delay);
            return animator;
        } else {
            return null;
        }
    }

    private @Nullable Animator.AnimatorListener createAnimatorListener(final WXSDKInstance instance,
            @Nullable final String callBack) {
        if (!TextUtils.isEmpty(callBack)) {
            return new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    if (instance == null || instance.isDestroy()) {
                        WXLogUtils.e(
                                "RenderContextImpl-onAnimationEnd WXSDKInstance == null NPE or instance is destroyed");
                    } else {
                        WXSDKManager.getInstance().callback(instance.getInstanceId(), callBack,
                                new HashMap<String, Object>());
                    }
                }
            };
        } else {
            return null;
        }
    }

    private @Nullable Interpolator createTimeInterpolator() {
        String interpolator = mAnimationBean.timingFunction;
        if (!TextUtils.isEmpty(interpolator)) {
            switch (interpolator) {
            case WXAnimationBean.EASE_IN:
                return new AccelerateInterpolator();
            case WXAnimationBean.EASE_OUT:
                return new DecelerateInterpolator();
            case WXAnimationBean.EASE_IN_OUT:
                return new AccelerateDecelerateInterpolator();
            case WXAnimationBean.LINEAR:
                return new LinearInterpolator();
            default:
                //Parse cubic-bezier
                try {
                    SingleFunctionParser<Float> parser = new SingleFunctionParser<>(mAnimationBean.timingFunction,
                            new SingleFunctionParser.FlatMapper<Float>() {
                                @Override
                                public Float map(String raw) {
                                    return Float.parseFloat(raw);
                                }
                            });
                    List<Float> params = parser.parse(WXAnimationBean.CUBIC_BEZIER);
                    if (params != null && params.size() == WXAnimationBean.NUM_CUBIC_PARAM) {
                        return PathInterpolatorCompat.create(params.get(0), params.get(1), params.get(2),
                                params.get(3));
                    } else {
                        return null;
                    }
                } catch (RuntimeException e) {
                    return null;
                }
            }
        }
        return null;
    }
}