com.taobao.weex.ui.component.WXComponent.java Source code

Java tutorial

Introduction

Here is the source code for com.taobao.weex.ui.component.WXComponent.java

Source

/**
 * Apache License Version 2.0, January 2004 http://www.apache.org/licenses/
 * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 * 1. Definitions.
 * "License" shall mean the terms and conditions for use, reproduction, and distribution as defined
 * by Sections 1 through 9 of this document.
 * "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is
 * granting the License.
 * "Legal Entity" shall mean the union of the acting entity and all other entities that control, are
 * controlled by, or are under common control with that entity. For the purposes of this definition,
 * "control" means (i) the power, direct or indirect, to cause the direction or management of such
 * entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
 * outstanding shares, or (iii) beneficial ownership of such entity.
 * "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this
 * License.
 * "Source" form shall mean the preferred form for making modifications, including but not limited
 * to software source code, documentation source, and configuration files.
 * "Object" form shall mean any form resulting from mechanical transformation or translation of a
 * Source form, including but not limited to compiled object code, generated documentation, and
 * conversions to other media types.
 * "Work" shall mean the work of authorship, whether in Source or Object form, made available under
 * the License, as indicated by a copyright notice that is included in or attached to the work (an
 * example is provided in the Appendix below).
 * "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or
 * derived from) the Work and for which the editorial revisions, annotations, elaborations, or other
 * modifications represent, as a whole, an original work of authorship. For the purposes of this
 * License, Derivative Works shall not include works that remain separable from, or merely link (or
 * bind by name) to the interfaces of, the Work and Derivative Works thereof.
 * "Contribution" shall mean any work of authorship, including the original version of the Work and
 * any modifications or additions to that Work or Derivative Works thereof, that is intentionally
 * submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or
 * Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this
 * definition, "submitted" means any form of electronic, verbal, or written communication sent to
 * the Licensor or its representatives, including but not limited to communication on electronic
 * mailing lists, source code control systems, and issue tracking systems that are managed by, or on
 * behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding
 * communication that is conspicuously marked or otherwise designated in writing by the copyright
 * owner as "Not a Contribution."
 * "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a
 * Contribution has been received by Licensor and subsequently incorporated within the Work.
 * 2. Grant of Copyright License. Subject to the terms and conditions of this License, each
 * Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
 * irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display,
 * publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or
 * Object form.
 * 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor
 * hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 * (except as stated in this section) patent license to make, have made, use, offer to sell, sell,
 * import, and otherwise transfer the Work, where such license applies only to those patent claims
 * licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or
 * by combination of their Contribution(s) with the Work to which such Contribution(s) was
 * submitted. If You institute patent litigation against any entity (including a cross-claim or
 * counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work
 * constitutes direct or contributory patent infringement, then any patent licenses granted to You
 * under this License for that Work shall terminate as of the date such litigation is filed.
 * 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works
 * thereof in any medium, with or without modifications, and in Source or Object form, provided that
 * You meet the following conditions:
 * (a) You must give any other recipients of the Work or Derivative Works a copy of this License;
 * and
 * (b) You must cause any modified files to carry prominent notices stating that You changed the
 * files; and
 * (c) You must retain, in the Source form of any Derivative Works that You distribute, all
 * copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding
 * those notices that do not pertain to any part of the Derivative Works; and
 * (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative
 * Works that You distribute must include a readable copy of the attribution notices contained
 * within such NOTICE file, excluding those notices that do not pertain to any part of the
 * Derivative Works, in at least one of the following places: within a NOTICE text file distributed
 * as part of the Derivative Works; within the Source form or documentation, if provided along with
 * the Derivative Works; or, within a display generated by the Derivative Works, if and wherever
 * such third-party notices normally appear. The contents of the NOTICE file are for informational
 * purposes only and do not modify the License. You may add Your own attribution notices within
 * Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the
 * Work, provided that such additional attribution notices cannot be construed as modifying the
 * License.
 * You may add Your own copyright statement to Your modifications and may provide additional or
 * different license terms and conditions for use, reproduction, or distribution of Your
 * modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and
 * distribution of the Work otherwise complies with the conditions stated in this License.
 * 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution
 * intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms
 * and conditions of this License, without any additional terms or conditions. Notwithstanding the
 * above, nothing herein shall supersede or modify the terms of any separate license agreement you
 * may have executed with Licensor regarding such Contributions.
 * 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service
 * marks, or product names of the Licensor, except as required for reasonable and customary use in
 * describing the origin of the Work and reproducing the content of the NOTICE file.
 * 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor
 * provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation,
 * any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 * PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or
 * redistributing the Work and assume any risks associated with Your exercise of permissions under
 * this License.
 * 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including
 * negligence), contract, or otherwise, unless required by applicable law (such as deliberate and
 * grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for
 * damages, including any direct, indirect, special, incidental, or consequential damages of any
 * character arising as a result of this License or out of the use or inability to use the Work
 * (including but not limited to damages for loss of goodwill, work stoppage, computer failure or
 * malfunction, or any and all other commercial damages or losses), even if such Contributor has
 * been advised of the possibility of such damages.
 * 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works
 * thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty,
 * indemnity, or other liability obligations and/or rights consistent with this License. However, in
 * accepting such obligations, You may act only on Your own behalf and on Your sole responsibility,
 * not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each
 * Contributor harmless for any liability incurred by, or claims asserted against, such Contributor
 * by reason of your accepting any such warranty or additional liability.
 * END OF TERMS AND CONDITIONS
 * APPENDIX: How to apply the Apache License to your work.
 * To apply the Apache License to your work, attach the following boilerplate notice, with the
 * fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include
 * the brackets!)  The text should be enclosed in the appropriate comment syntax for the file
 * format. We also recommend that a file or class name and description of purpose be included on the
 * same "printed page" as the copyright notice for easier identification within third-party
 * archives.
 * Copyright 2016 Alibaba Group
 * Licensed 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.component;

import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Message;
import android.support.annotation.CallSuper;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewCompat;
import android.text.TextUtils;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.taobao.weex.IWXActivityStateListener;
import com.taobao.weex.WXEnvironment;
import com.taobao.weex.WXSDKInstance;
import com.taobao.weex.WXSDKManager;
import com.taobao.weex.bridge.Invoker;
import com.taobao.weex.common.Constants;
import com.taobao.weex.common.IWXObject;
import com.taobao.weex.common.WXRuntimeException;
import com.taobao.weex.dom.ImmutableDomObject;
import com.taobao.weex.dom.WXDomHandler;
import com.taobao.weex.dom.WXDomObject;
import com.taobao.weex.dom.WXDomTask;
import com.taobao.weex.dom.WXStyle;
import com.taobao.weex.dom.flex.Spacing;
import com.taobao.weex.ui.IFComponentHolder;
import com.taobao.weex.ui.animation.WXAnimationModule;
import com.taobao.weex.ui.component.pesudo.OnActivePseudoListner;
import com.taobao.weex.ui.component.pesudo.PesudoStatus;
import com.taobao.weex.ui.component.pesudo.TouchActivePseudoListener;
import com.taobao.weex.ui.view.border.BorderDrawable;
import com.taobao.weex.ui.view.gesture.WXGesture;
import com.taobao.weex.ui.view.gesture.WXGestureObservable;
import com.taobao.weex.ui.view.gesture.WXGestureType;
import com.taobao.weex.utils.WXDataStructureUtil;
import com.taobao.weex.utils.WXLogUtils;
import com.taobao.weex.utils.WXReflectionUtils;
import com.taobao.weex.utils.WXResourceUtils;
import com.taobao.weex.utils.WXUtils;
import com.taobao.weex.utils.WXViewUtils;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * abstract component
 *
 */
public abstract class WXComponent<T extends View>
        implements IWXObject, IWXActivityStateListener, OnActivePseudoListner {

    public static final String PROP_FIXED_SIZE = "fixedSize";
    public static final String PROP_FS_MATCH_PARENT = "m";
    public static final String PROP_FS_WRAP_CONTENT = "w";

    private int mFixedProp = 0;
    public static int mComponentNum = 0;
    /** package **/
    T mHost;

    private volatile WXVContainer mParent;
    private volatile ImmutableDomObject mDomObj;
    private WXSDKInstance mInstance;
    private Context mContext;

    private int mAbsoluteY = 0;
    private int mAbsoluteX = 0;
    private Set<String> mGestureType;

    private BorderDrawable mBackgroundDrawable;
    private int mPreRealWidth = 0;
    private int mPreRealHeight = 0;
    private int mPreRealLeft = 0;
    private int mPreRealTop = 0;
    private int mStickyOffset = 0;
    private WXGesture mGesture;
    private IFComponentHolder mHolder;
    private boolean isUsing = false;
    private List<OnClickListener> mHostClickListeners;
    private List<OnFocusChangeListener> mFocusChangeListeners;
    private String mCurrentRef;
    private Set<String> mAppendEvents = new HashSet<>();
    private WXAnimationModule.AnimationHolder mAnimationHolder;
    private PesudoStatus mPesudoStatus = new PesudoStatus();
    private boolean mIsDestroyed = false;
    private boolean mCanRecycled = true;

    //Holding the animation bean when component is uninitialized
    public void postAnimation(WXAnimationModule.AnimationHolder holder) {
        this.mAnimationHolder = holder;
    }

    private OnClickListener mClickEventListener = new OnClickListener() {
        @Override
        public void onHostViewClick() {
            Map<String, Object> param = WXDataStructureUtil.newHashMapWithExpectedSize(1);
            Map<String, Object> position = WXDataStructureUtil.newHashMapWithExpectedSize(4);
            int[] location = new int[2];
            mHost.getLocationOnScreen(location);
            position.put("x", WXViewUtils.getWebPxByWidth(location[0], mInstance.getViewPortWidth()));
            position.put("y", WXViewUtils.getWebPxByWidth(location[1], mInstance.getViewPortWidth()));
            position.put("width",
                    WXViewUtils.getWebPxByWidth(mDomObj.getLayoutWidth(), mInstance.getViewPortWidth()));
            position.put("height",
                    WXViewUtils.getWebPxByWidth(mDomObj.getLayoutHeight(), mInstance.getViewPortWidth()));
            param.put(Constants.Name.POSITION, position);
            fireEvent(Constants.Event.CLICK, param);
        }
    };

    public String getInstanceId() {
        return mInstance.getInstanceId();
    }

    public Rect getComponentSize() {
        Rect size = new Rect();
        if (mHost != null) {
            int[] location = new int[2];
            int[] anchor = new int[2];
            mHost.getLocationOnScreen(location);
            mInstance.getContainerView().getLocationOnScreen(anchor);

            int left = location[0] - anchor[0];
            int top = (location[1] - mStickyOffset) - anchor[1];
            int width = (int) mDomObj.getLayoutWidth();
            int height = (int) mDomObj.getLayoutHeight();
            size.set(left, top, left + width, top + height);
        }
        return size;
    }

    public final void invoke(String method, JSONArray args) {
        final Invoker invoker = mHolder.getMethodInvoker(method);
        if (invoker != null) {
            try {
                getInstance().getNativeInvokeHelper().invoke(this, invoker, args);

            } catch (Exception e) {
                WXLogUtils.e("[WXComponent] updateProperties :" + "class:" + getClass() + "method:"
                        + invoker.toString() + " function " + WXLogUtils.getStackTrace(e));
            }
        } else {
            onInvokeUnknownMethod(method, args);
        }
    }

    /**
     * Will be invoked when request method not found.
     * Subclass should override this method, If you return hard-code method list in {@link IFComponentHolder#getMethods()}
     * @param method
     * @param args
     */
    protected void onInvokeUnknownMethod(String method, JSONArray args) {

    }

    public interface OnClickListener {
        void onHostViewClick();
    }

    interface OnFocusChangeListener {
        void onFocusChange(boolean hasFocus);
    }

    @Deprecated
    public WXComponent(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, String instanceId,
            boolean isLazy) {
        this(instance, dom, parent, isLazy);
    }

    @Deprecated
    public WXComponent(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, boolean isLazy) {
        this(instance, dom, parent);
    }

    public WXComponent(WXSDKInstance instance, WXDomObject dom, WXVContainer parent) {
        mInstance = instance;
        mContext = mInstance.getContext();
        mParent = parent;
        mDomObj = dom.clone();
        mCurrentRef = mDomObj.getRef();
        mCanRecycled = dom.canRecycled();
        mGestureType = new HashSet<>();
        ++mComponentNum;
        onCreate();
    }

    protected void onCreate() {

    }

    public void bindHolder(IFComponentHolder holder) {
        mHolder = holder;
    }

    public WXSDKInstance getInstance() {
        return mInstance;
    }

    public Context getContext() {
        return mContext;
    }

    /**
     * Find component by component reference.
     * @param ref
     * @return
     */
    protected final WXComponent findComponent(String ref) {
        if (mInstance != null && ref != null) {
            return WXSDKManager.getInstance().getWXRenderManager().getWXComponent(mInstance.getInstanceId(), ref);
        }
        return null;
    }

    public final void fireEvent(String type) {
        fireEvent(type, null);
    }

    public final void fireEvent(String type, Map<String, Object> params) {
        fireEvent(type, params, null);
    }

    protected final void fireEvent(String type, Map<String, Object> params, Map<String, Object> domChanges) {
        if (mInstance != null && mDomObj != null) {
            mInstance.fireEvent(mCurrentRef, type, params, domChanges);
        }
    }

    /**
     * The view is created as needed
     * @return true for lazy
     */
    public boolean isLazy() {
        return mParent != null && mParent.isLazy();
    }

    public void applyLayoutAndEvent(WXComponent component) {
        if (!isLazy()) {
            if (component == null) {
                component = this;
            }
            setLayout(component.getDomObject());
            setPadding(component.getDomObject().getPadding(), component.getDomObject().getBorder());
            addEvents();

        }
    }

    protected final void addFocusChangeListener(OnFocusChangeListener l) {
        View view;
        if (l != null && (view = getRealView()) != null) {
            if (mFocusChangeListeners == null) {
                mFocusChangeListeners = new ArrayList<>();
                view.setFocusable(true);
                view.setOnFocusChangeListener(new View.OnFocusChangeListener() {
                    @Override
                    public void onFocusChange(View v, boolean hasFocus) {
                        for (OnFocusChangeListener listener : mFocusChangeListeners) {
                            if (listener != null) {
                                listener.onFocusChange(hasFocus);
                            }
                        }
                    }
                });
            }
            mFocusChangeListeners.add(l);
        }
    }

    protected final void addClickListener(OnClickListener l) {
        View view;
        if (l != null && (view = getRealView()) != null) {
            if (mHostClickListeners == null) {
                mHostClickListeners = new ArrayList<>();
                view.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        for (OnClickListener listener : mHostClickListeners) {
                            if (listener != null) {
                                listener.onHostViewClick();
                            }
                        }
                    }
                });
            }
            mHostClickListeners.add(l);

        }
    }

    protected final void removeClickListener(OnClickListener l) {
        mHostClickListeners.remove(l);
    }

    public void bindData(WXComponent component) {
        if (!isLazy()) {
            if (component == null) {
                component = this;
            }
            mCurrentRef = component.getDomObject().getRef();
            updateProperties(component.getDomObject().getStyles());
            updateProperties(component.getDomObject().getAttrs());
            updateExtra(component.getDomObject().getExtra());
        }
    }

    public void refreshData(WXComponent component) {

    }

    protected BorderDrawable getOrCreateBorder() {
        if (mBackgroundDrawable == null) {
            Drawable backgroundDrawable = mHost.getBackground();
            WXViewUtils.setBackGround(mHost, null);
            mBackgroundDrawable = new BorderDrawable();
            if (backgroundDrawable == null) {
                WXViewUtils.setBackGround(mHost, mBackgroundDrawable);
            } else {
                //TODO Not strictly clip according to background-clip:border-box
                WXViewUtils.setBackGround(mHost,
                        new LayerDrawable(new Drawable[] { mBackgroundDrawable, backgroundDrawable }));
            }
        }
        return mBackgroundDrawable;
    }

    /**
     * layout view
     */
    public final void setLayout(ImmutableDomObject domObject) {
        if (domObject == null || TextUtils.isEmpty(mCurrentRef)) {
            return;
        }

        boolean nullParent = mParent == null;//parent is nullable
        mDomObj = domObject;

        //offset by sibling
        int siblingOffset = nullParent ? 0 : mParent.getChildrenLayoutTopOffset();

        Spacing parentPadding = (nullParent ? new Spacing() : mParent.getDomObject().getPadding());
        Spacing parentBorder = (nullParent ? new Spacing() : mParent.getDomObject().getBorder());
        Spacing margin = mDomObj.getMargin();
        int realWidth = (int) mDomObj.getLayoutWidth();
        int realHeight = (int) mDomObj.getLayoutHeight();
        int realLeft = (int) (mDomObj.getLayoutX() - parentPadding.get(Spacing.LEFT)
                - parentBorder.get(Spacing.LEFT));
        int realTop = (int) (mDomObj.getLayoutY() - parentPadding.get(Spacing.TOP) - parentBorder.get(Spacing.TOP))
                + siblingOffset;
        int realRight = (int) margin.get(Spacing.RIGHT);
        int realBottom = (int) margin.get(Spacing.BOTTOM);

        if (mPreRealWidth == realWidth && mPreRealHeight == realHeight && mPreRealLeft == realLeft
                && mPreRealTop == realTop) {
            return;
        }

        mAbsoluteY = (int) (nullParent ? 0 : mParent.getAbsoluteY() + mDomObj.getLayoutY());
        mAbsoluteX = (int) (nullParent ? 0 : mParent.getAbsoluteX() + mDomObj.getLayoutX());

        //calculate first screen time
        if (!mInstance.mEnd && !(mHost instanceof ViewGroup)
                && mAbsoluteY + realHeight > mInstance.getWeexHeight() + 1) {
            mInstance.firstScreenRenderFinished();
        }

        if (mHost == null) {
            return;
        }

        MeasureOutput measureOutput = measure(realWidth, realHeight);
        realWidth = measureOutput.width;
        realHeight = measureOutput.height;

        //fixed style
        if (mDomObj.isFixed()) {
            setFixedHostLayoutParams(mHost, realWidth, realHeight, realLeft, realRight, realTop, realBottom);
        } else {
            setHostLayoutParams(mHost, realWidth, realHeight, realLeft, realRight, realTop, realBottom);
        }

        mPreRealWidth = realWidth;
        mPreRealHeight = realHeight;
        mPreRealLeft = realLeft;
        mPreRealTop = realTop;

        onFinishLayout();
    }

    public int getLayoutTopOffsetForSibling() {
        return 0;
    }

    protected void setHostLayoutParams(T host, int width, int height, int left, int right, int top, int bottom) {
        ViewGroup.LayoutParams lp;
        if (mParent == null) {
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height);
            params.setMargins(left, top, right, bottom);
            lp = params;
        } else {
            lp = mParent.getChildLayoutParams(this, host, width, height, left, right, top, bottom);
        }
        if (lp != null) {
            mHost.setLayoutParams(lp);
        }
    }

    private void setFixedHostLayoutParams(T host, int width, int height, int left, int right, int top, int bottom) {
        if (host.getParent() instanceof ViewGroup) {
            ViewGroup viewGroup = (ViewGroup) host.getParent();
            viewGroup.removeView(host);
        }
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);

        params.width = width;
        params.height = height;
        params.setMargins(left, top, right, bottom);
        host.setLayoutParams(params);
        mInstance.addFixedView(host);

        if (WXEnvironment.isApkDebugable()) {
            WXLogUtils.d("Weex_Fixed_Style",
                    "WXComponent:setLayout :" + left + " " + top + " " + width + " " + height);
            WXLogUtils.d("Weex_Fixed_Style", "WXComponent:setLayout Left:" + mDomObj.getStyles().getLeft() + " "
                    + (int) mDomObj.getStyles().getTop());
        }
    }

    /**
     * After component's layout result is apply to view. May be invoke multiple times since
     * DOM can be changed in js runtime.
     */
    protected void onFinishLayout() {

    }

    public void setPadding(Spacing padding, Spacing border) {
        int left = (int) (padding.get(Spacing.LEFT) + border.get(Spacing.LEFT));
        int top = (int) (padding.get(Spacing.TOP) + border.get(Spacing.TOP));
        int right = (int) (padding.get(Spacing.RIGHT) + border.get(Spacing.RIGHT));
        int bottom = (int) (padding.get(Spacing.BOTTOM) + border.get(Spacing.BOTTOM));

        if (mHost == null) {
            return;
        }
        mHost.setPadding(left, top, right, bottom);
    }

    private void addEvents() {
        int count = mDomObj.getEvents().size();
        for (int i = 0; i < count; ++i) {
            addEvent(mDomObj.getEvents().get(i));
        }
        setActiveTouchListener();
    }

    public void updateExtra(Object extra) {

    }

    public ImmutableDomObject getDomObject() {
        return mDomObj;
    }

    /**
     * measure
     */
    protected MeasureOutput measure(int width, int height) {
        MeasureOutput measureOutput = new MeasureOutput();

        if (mFixedProp != 0) {
            measureOutput.width = mFixedProp;
            measureOutput.height = mFixedProp;
        } else {
            measureOutput.width = width;
            measureOutput.height = height;
        }
        return measureOutput;
    }

    public void updateProperties(Map<String, Object> props) {
        if (props == null || mHost == null) {
            return;
        }

        for (Map.Entry<String, Object> entry : props.entrySet()) {
            String key = entry.getKey();
            Object param = entry.getValue();
            String value = WXUtils.getString(param, null);
            if (TextUtils.isEmpty(value)) {
                param = convertEmptyProperty(key, value);
            }
            if (!setProperty(key, param)) {
                if (mHolder == null) {
                    return;
                }
                Invoker invoker = mHolder.getPropertyInvoker(key);
                if (invoker != null) {
                    try {
                        Type[] paramClazzs = invoker.getParameterTypes();
                        if (paramClazzs.length != 1) {
                            WXLogUtils.e("[WXComponent] setX method only one parameter" + invoker);
                            return;
                        }
                        param = WXReflectionUtils.parseArgument(paramClazzs[0], param);
                        invoker.invoke(this, param);
                    } catch (Exception e) {
                        WXLogUtils.e("[WXComponent] updateProperties :" + "class:" + getClass() + "method:"
                                + invoker.toString() + " function " + WXLogUtils.getStackTrace(e));
                    }
                }
            }
        }
        readyToRender();
    }

    /**
     * Apply styles and attributes.
     * @param key name of argument
     * @param param value of argument
     * @return true means that the property is consumed
       */
    protected boolean setProperty(String key, Object param) {
        switch (key) {
        case Constants.Name.PREVENT_MOVE_EVENT:
            if (mGesture != null) {
                mGesture.setPreventMoveEvent(WXUtils.getBoolean(param, false));
            }
            return true;
        case Constants.Name.DISABLED:
            Boolean disabled = WXUtils.getBoolean(param, null);
            if (disabled != null) {
                setDisabled(disabled);
                setPseudoClassStatus(Constants.PSEUDO.DISABLED, disabled);
            }
            return true;
        case Constants.Name.POSITION:
            String position = WXUtils.getString(param, null);
            if (position != null)
                setSticky(position);
            return true;
        case Constants.Name.BACKGROUND_COLOR:
            String bgColor = WXUtils.getString(param, null);
            if (bgColor != null)
                setBackgroundColor(bgColor);
            return true;
        case Constants.Name.BACKGROUND_IMAGE:
            String bgImage = WXUtils.getString(param, null);
            if (bgImage != null) {
                setBackgroundImage(bgImage);
            }
            return true;
        case Constants.Name.OPACITY:
            Float opacity = WXUtils.getFloat(param, null);
            if (opacity != null)
                setOpacity(opacity);
            return true;
        case Constants.Name.BORDER_RADIUS:
        case Constants.Name.BORDER_TOP_LEFT_RADIUS:
        case Constants.Name.BORDER_TOP_RIGHT_RADIUS:
        case Constants.Name.BORDER_BOTTOM_RIGHT_RADIUS:
        case Constants.Name.BORDER_BOTTOM_LEFT_RADIUS:
            Float radius = WXUtils.getFloat(param, null);
            if (radius != null)
                setBorderRadius(key, radius);
            return true;
        case Constants.Name.BORDER_WIDTH:
        case Constants.Name.BORDER_TOP_WIDTH:
        case Constants.Name.BORDER_RIGHT_WIDTH:
        case Constants.Name.BORDER_BOTTOM_WIDTH:
        case Constants.Name.BORDER_LEFT_WIDTH:
            Float width = WXUtils.getFloat(param, null);
            if (width != null)
                setBorderWidth(key, width);
            return true;
        case Constants.Name.BORDER_STYLE:
        case Constants.Name.BORDER_RIGHT_STYLE:
        case Constants.Name.BORDER_BOTTOM_STYLE:
        case Constants.Name.BORDER_LEFT_STYLE:
        case Constants.Name.BORDER_TOP_STYLE:
            String border_style = WXUtils.getString(param, null);
            if (border_style != null)
                setBorderStyle(key, border_style);
            return true;
        case Constants.Name.BORDER_COLOR:
        case Constants.Name.BORDER_TOP_COLOR:
        case Constants.Name.BORDER_RIGHT_COLOR:
        case Constants.Name.BORDER_BOTTOM_COLOR:
        case Constants.Name.BORDER_LEFT_COLOR:
            String border_color = WXUtils.getString(param, null);
            if (border_color != null)
                setBorderColor(key, border_color);
            return true;
        case Constants.Name.VISIBILITY:
            String visibility = WXUtils.getString(param, null);
            if (visibility != null)
                setVisibility(visibility);
            return true;
        case Constants.Name.ELEVATION:
            if (param != null) {
                updateElevation();
            }
            return true;
        case PROP_FIXED_SIZE:
            String fixedSize = WXUtils.getString(param, PROP_FS_MATCH_PARENT);
            setFixedSize(fixedSize);
            return true;
        case Constants.Name.WIDTH:
        case Constants.Name.MIN_WIDTH:
        case Constants.Name.MAX_WIDTH:
        case Constants.Name.HEIGHT:
        case Constants.Name.MIN_HEIGHT:
        case Constants.Name.MAX_HEIGHT:
        case Constants.Name.ALIGN_ITEMS:
        case Constants.Name.ALIGN_SELF:
        case Constants.Name.FLEX:
        case Constants.Name.FLEX_DIRECTION:
        case Constants.Name.JUSTIFY_CONTENT:
        case Constants.Name.FLEX_WRAP:
        case Constants.Name.MARGIN:
        case Constants.Name.MARGIN_TOP:
        case Constants.Name.MARGIN_LEFT:
        case Constants.Name.MARGIN_RIGHT:
        case Constants.Name.MARGIN_BOTTOM:
        case Constants.Name.PADDING:
        case Constants.Name.PADDING_TOP:
        case Constants.Name.PADDING_LEFT:
        case Constants.Name.PADDING_RIGHT:
        case Constants.Name.PADDING_BOTTOM:
        case Constants.Name.LEFT:
        case Constants.Name.TOP:
        case Constants.Name.RIGHT:
        case Constants.Name.BOTTOM:
            return true;
        default:
            return false;
        }
    }

    /**
     * Avoid large size view fail in GPU-Animation.
     * @param fixedSize
     */
    private void setFixedSize(String fixedSize) {
        if (PROP_FS_MATCH_PARENT.equals(fixedSize)) {
            mFixedProp = ViewGroup.LayoutParams.MATCH_PARENT;
        } else if (PROP_FS_WRAP_CONTENT.equals(fixedSize)) {
            mFixedProp = ViewGroup.LayoutParams.WRAP_CONTENT;
        } else {
            mFixedProp = 0;
            return;
        }
        if (mHost != null) {
            ViewGroup.LayoutParams layoutParams = mHost.getLayoutParams();
            if (layoutParams != null) {
                layoutParams.height = mFixedProp;
                layoutParams.width = mFixedProp;
                mHost.setLayoutParams(layoutParams);
            }
        }
    }

    /**
     * Add new event to component,this will post a task to DOM thread to add event.
     * @param type
     */
    protected void appendEventToDOM(String type) {
        Message message = Message.obtain();
        WXDomTask task = new WXDomTask();
        task.instanceId = getInstanceId();
        task.args = new ArrayList<>();
        task.args.add(getRef());
        task.args.add(type);
        message.obj = task;
        message.what = WXDomHandler.MsgType.WX_DOM_ADD_EVENT;
        WXSDKManager.getInstance().getWXDomManager().sendMessage(message);
    }

    /**
     * Do not use this method to add event, this only apply event already add to DomObject.
     * @param type
     */
    public void addEvent(String type) {
        if (TextUtils.isEmpty(type)) {
            return;
        }
        mAppendEvents.add(type);

        View view = getRealView();
        if (type.equals(Constants.Event.CLICK) && view != null) {
            addClickListener(mClickEventListener);
        } else if ((type.equals(Constants.Event.FOCUS) || type.equals(Constants.Event.BLUR))) {
            addFocusChangeListener(new OnFocusChangeListener() {
                public void onFocusChange(boolean hasFocus) {
                    Map<String, Object> params = new HashMap<>();
                    params.put("timeStamp", System.currentTimeMillis());
                    fireEvent(hasFocus ? Constants.Event.FOCUS : Constants.Event.BLUR, params);
                }
            });
        } else if (view != null && needGestureDetector(type)) {
            if (view instanceof WXGestureObservable) {
                if (mGesture == null) {
                    mGesture = new WXGesture(this, mContext);
                    boolean isPreventMove = WXUtils
                            .getBoolean(getDomObject().getAttrs().get(Constants.Name.PREVENT_MOVE_EVENT), false);
                    mGesture.setPreventMoveEvent(isPreventMove);
                }
                mGestureType.add(type);
                ((WXGestureObservable) view).registerGestureListener(mGesture);
            } else {
                WXLogUtils.e(view.getClass().getSimpleName() + " don't implement "
                        + "WXGestureObservable, so no gesture is supported.");
            }
        } else {
            Scrollable scroller = getParentScroller();
            if (type.equals(Constants.Event.APPEAR) && scroller != null) {
                scroller.bindAppearEvent(this);
            }
            if (type.equals(Constants.Event.DISAPPEAR) && scroller != null) {
                scroller.bindDisappearEvent(this);
            }
        }
    }

    public View getRealView() {
        return mHost;
    }

    /**
     * Judge whether need to set an onTouchListener.<br>
     * As there is only one onTouchListener in each view, so all the gesture that use onTouchListener should put there.
     *
     * @param type eventType {@link com.taobao.weex.common.Constants.Event}
     * @return true for set an onTouchListener, otherwise false
     */
    private boolean needGestureDetector(String type) {
        if (mHost != null) {
            for (WXGestureType gesture : WXGestureType.LowLevelGesture.values()) {
                if (type.equals(gesture.toString())) {
                    return true;
                }
            }
            for (WXGestureType gesture : WXGestureType.HighLevelGesture.values()) {
                if (type.equals(gesture.toString())) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * get Scroller components
     */
    public Scrollable getParentScroller() {
        WXComponent component = this;
        WXVContainer container;
        Scrollable scroller;
        for (;;) {
            container = component.getParent();
            if (container == null) {
                return null;
            }
            if (container instanceof Scrollable) {
                scroller = (Scrollable) container;
                return scroller;
            }
            if (container.getRef().equals(WXDomObject.ROOT)) {
                return null;
            }
            component = container;
        }
    }

    public WXVContainer getParent() {
        return mParent;
    }

    public String getRef() {
        if (mDomObj == null) {
            return null;
        }
        return mCurrentRef;
    }

    /**
     * create view
     *
     */
    public final void createView() {
        if (!isLazy()) {
            createViewImpl();
        }
    }

    protected void createViewImpl() {
        if (mContext != null) {
            mHost = initComponentHostView(mContext);
            if (mHost == null) {
                //compatible
                initView();
            }
            if (mHost != null) {
                mHost.setId(WXViewUtils.generateViewId());
            }
            onHostViewInitialized(mHost);
        } else {
            WXLogUtils.e("createViewImpl", "Context is null");
        }
    }

    /**
     * Use {@link #initComponentHostView(Context context)} instead.
     */
    @Deprecated
    protected void initView() {
        if (mContext != null)
            mHost = initComponentHostView(mContext);
    }

    /**
     * Create corresponding view for this component.
     * @param context
     * @return
     */
    protected T initComponentHostView(@NonNull Context context) {
        /**
         * compatible old initView
         * TODO: change to abstract method in next V1.0 .
         */
        return null;
    }

    /**
     * Called after host view init. <br>
     * Any overriding methods should invoke this method at the right time, to ensure the cached animation can be triggered correctly.
     * (the animation will be cached when {@link #isLazy()} is true)
     * @param host the host view
     */
    @CallSuper
    protected void onHostViewInitialized(T host) {
        if (mAnimationHolder != null) {
            //Performs cached animation
            mAnimationHolder.execute(mInstance, this);
        }
        setActiveTouchListener();
    }

    public T getHostView() {
        return mHost;
    }

    /**
     * use {@link #getHostView()} instead
     * @return
     */
    @Deprecated
    public View getView() {
        return mHost;
    }

    public int getAbsoluteY() {
        return mAbsoluteY;
    }

    public int getAbsoluteX() {
        return mAbsoluteX;
    }

    public void updateDom(WXDomObject dom) {
        if (dom == null) {
            return;
        }
        mDomObj = dom.clone();
    }

    public final void removeEvent(String type) {
        if (TextUtils.isEmpty(type)) {
            return;
        }
        mAppendEvents.remove(type);//only clean append events, not dom's events.
        mGestureType.remove(type);
        removeEventFromView(type);
    }

    protected void removeEventFromView(String type) {
        if (type.equals(Constants.Event.CLICK) && getRealView() != null && mHostClickListeners != null) {
            mHostClickListeners.remove(mClickEventListener);
            //click event only remove from listener array
        }
        Scrollable scroller = getParentScroller();
        if (type.equals(Constants.Event.APPEAR) && scroller != null) {
            scroller.unbindAppearEvent(this);
        }
        if (type.equals(Constants.Event.DISAPPEAR) && scroller != null) {
            scroller.unbindDisappearEvent(this);
        }
    }

    public final void removeAllEvent() {
        if (mDomObj == null || mDomObj.getEvents().size() < 1) {
            return;
        }
        for (String event : mDomObj.getEvents()) {
            removeEventFromView(event);
        }
        mAppendEvents.clear();//only clean append events, not dom's events.
        mGestureType.clear();
        mGesture = null;
        if (getRealView() != null && getRealView() instanceof WXGestureObservable) {
            ((WXGestureObservable) getRealView()).registerGestureListener(null);
        }
        if (mHost != null) {
            mHost.setOnFocusChangeListener(null);
            mHost.setOnClickListener(null);
        }
    }

    public final void removeStickyStyle() {
        if (mDomObj == null) {
            return;
        }

        if (isSticky()) {
            Scrollable scroller = getParentScroller();
            if (scroller != null) {
                scroller.unbindStickStyle(this);
            }
        }
    }

    public boolean isSticky() {
        return mDomObj.getStyles().isSticky();
    }

    public void setDisabled(boolean disabled) {
        if (mHost == null) {
            return;
        }
        mHost.setEnabled(!disabled);
    }

    public void setSticky(String sticky) {
        if (!TextUtils.isEmpty(sticky) && sticky.equals(Constants.Value.STICKY)) {
            Scrollable waScroller = getParentScroller();
            if (waScroller != null) {
                waScroller.bindStickStyle(this);
            }
        }
    }

    public void setBackgroundColor(String color) {
        if (!TextUtils.isEmpty(color) && mHost != null) {
            int colorInt = WXResourceUtils.getColor(color);
            if (!(colorInt == Color.TRANSPARENT && mBackgroundDrawable == null)) {
                getOrCreateBorder().setColor(colorInt);
            }
        }
    }

    public void setBackgroundImage(String bgImage) {
        if (!TextUtils.isEmpty(bgImage) && mHost != null) {
            Shader shader = WXResourceUtils.getShader(bgImage, mDomObj.getLayoutWidth(), mDomObj.getLayoutHeight());
            getOrCreateBorder().setImage(shader);
        }
    }

    public void setOpacity(float opacity) {
        if (opacity >= 0 && opacity <= 1 && mHost.getAlpha() != opacity) {
            mHost.setLayerType(View.LAYER_TYPE_HARDWARE, null);
            mHost.setAlpha(opacity);
        }
    }

    public void setBorderRadius(String key, float borderRadius) {
        if (borderRadius >= 0) {
            switch (key) {
            case Constants.Name.BORDER_RADIUS:
                getOrCreateBorder().setBorderRadius(BorderDrawable.BORDER_RADIUS_ALL,
                        WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getViewPortWidth()));
                break;
            case Constants.Name.BORDER_TOP_LEFT_RADIUS:
                getOrCreateBorder().setBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS,
                        WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getViewPortWidth()));
                break;
            case Constants.Name.BORDER_TOP_RIGHT_RADIUS:
                getOrCreateBorder().setBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS,
                        WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getViewPortWidth()));
                break;
            case Constants.Name.BORDER_BOTTOM_RIGHT_RADIUS:
                getOrCreateBorder().setBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS,
                        WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getViewPortWidth()));
                break;
            case Constants.Name.BORDER_BOTTOM_LEFT_RADIUS:
                getOrCreateBorder().setBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS,
                        WXViewUtils.getRealSubPxByWidth(borderRadius, mInstance.getViewPortWidth()));
                break;
            }
        }
    }

    public void setBorderWidth(String key, float borderWidth) {
        if (borderWidth >= 0) {
            switch (key) {
            case Constants.Name.BORDER_WIDTH:
                getOrCreateBorder().setBorderWidth(Spacing.ALL,
                        WXViewUtils.getRealSubPxByWidth(borderWidth, getInstance().getViewPortWidth()));
                break;
            case Constants.Name.BORDER_TOP_WIDTH:
                getOrCreateBorder().setBorderWidth(Spacing.TOP,
                        WXViewUtils.getRealSubPxByWidth(borderWidth, getInstance().getViewPortWidth()));
                break;
            case Constants.Name.BORDER_RIGHT_WIDTH:
                getOrCreateBorder().setBorderWidth(Spacing.RIGHT,
                        WXViewUtils.getRealSubPxByWidth(borderWidth, getInstance().getViewPortWidth()));
                break;
            case Constants.Name.BORDER_BOTTOM_WIDTH:
                getOrCreateBorder().setBorderWidth(Spacing.BOTTOM,
                        WXViewUtils.getRealSubPxByWidth(borderWidth, getInstance().getViewPortWidth()));
                break;
            case Constants.Name.BORDER_LEFT_WIDTH:
                getOrCreateBorder().setBorderWidth(Spacing.LEFT,
                        WXViewUtils.getRealSubPxByWidth(borderWidth, getInstance().getViewPortWidth()));
                break;
            }
        }
    }

    public void setBorderStyle(String key, String borderStyle) {
        if (!TextUtils.isEmpty(borderStyle)) {
            switch (key) {
            case Constants.Name.BORDER_STYLE:
                getOrCreateBorder().setBorderStyle(Spacing.ALL, borderStyle);
                break;
            case Constants.Name.BORDER_RIGHT_STYLE:
                getOrCreateBorder().setBorderStyle(Spacing.RIGHT, borderStyle);
                break;
            case Constants.Name.BORDER_BOTTOM_STYLE:
                getOrCreateBorder().setBorderStyle(Spacing.BOTTOM, borderStyle);
                break;
            case Constants.Name.BORDER_LEFT_STYLE:
                getOrCreateBorder().setBorderStyle(Spacing.LEFT, borderStyle);
                break;
            case Constants.Name.BORDER_TOP_STYLE:
                getOrCreateBorder().setBorderStyle(Spacing.TOP, borderStyle);
                break;
            }
        }
    }

    public void setBorderColor(String key, String borderColor) {
        if (!TextUtils.isEmpty(borderColor)) {
            int colorInt = WXResourceUtils.getColor(borderColor);
            if (colorInt != Integer.MIN_VALUE) {
                switch (key) {
                case Constants.Name.BORDER_COLOR:
                    getOrCreateBorder().setBorderColor(Spacing.ALL, colorInt);
                    break;
                case Constants.Name.BORDER_TOP_COLOR:
                    getOrCreateBorder().setBorderColor(Spacing.TOP, colorInt);
                    break;
                case Constants.Name.BORDER_RIGHT_COLOR:
                    getOrCreateBorder().setBorderColor(Spacing.RIGHT, colorInt);
                    break;
                case Constants.Name.BORDER_BOTTOM_COLOR:
                    getOrCreateBorder().setBorderColor(Spacing.BOTTOM, colorInt);
                    break;
                case Constants.Name.BORDER_LEFT_COLOR:
                    getOrCreateBorder().setBorderColor(Spacing.LEFT, colorInt);
                    break;
                }
            }
        }
    }

    public @Nullable String getVisibility() {
        try {
            return (String) getDomObject().getStyles().get(Constants.Name.VISIBILITY);
        } catch (Exception e) {
            return Constants.Value.VISIBLE;
        }
    }

    public void setVisibility(String visibility) {
        View view;
        if ((view = getRealView()) != null) {
            if (TextUtils.equals(visibility, Constants.Value.VISIBLE)) {
                view.setVisibility(View.VISIBLE);
            } else if (TextUtils.equals(visibility, Constants.Value.HIDDEN)) {
                view.setVisibility(View.GONE);
            }
        }
    }

    /**
     * This is an experimental feature for elevation of material design.
     */
    private void updateElevation() {
        float elevation = getDomObject().getAttrs().getElevation(getInstance().getViewPortWidth());
        if (!Float.isNaN(elevation)) {
            ViewCompat.setElevation(getHostView(), elevation);
        }
    }

    @Deprecated
    public void registerActivityStateListener() {

    }

    /********************************
     *  begin hook Activity life cycle callback
     ********************************************************/
    public void onActivityCreate() {

    }

    public void onActivityStart() {

    }

    public void onActivityPause() {

    }

    public void onActivityResume() {

    }

    public void onActivityStop() {

    }

    public void onActivityDestroy() {

    }

    public boolean onActivityBack() {
        return false;
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {

    }

    public boolean onCreateOptionsMenu(Menu menu) {
        return false;
    }

    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

    }

    /********************************
     *  end hook Activity life cycle callback
     ********************************************************/

    public void destroy() {
        if (WXEnvironment.isApkDebugable() && !WXUtils.isUiThread()) {
            throw new WXRuntimeException("[WXComponent] destroy can only be called in main thread");
        }
        if (mHost != null && mHost.getLayerType() == View.LAYER_TYPE_HARDWARE) {
            mHost.setLayerType(View.LAYER_TYPE_NONE, null);
        }
        removeAllEvent();
        removeStickyStyle();
        if (mDomObj != null) {
            mDomObj = null;
        }

        mIsDestroyed = true;
    }

    public boolean isDestoryed() {
        return mIsDestroyed;
    }

    /**
     * Detach view from its component. Components,
     * which have difference between getHostView and getRealView or have temp calculation results,
     * must<strong> override</strong>  this method with their own implementation.
     *
     * @return the original View
     */
    public View detachViewAndClearPreInfo() {
        View original = mHost;
        mPreRealLeft = 0;
        mPreRealWidth = 0;
        mPreRealHeight = 0;
        mPreRealTop = 0;
        //    mHost = null;
        return original;
    }

    /**
     * This method computes user visible left-top point in view's coordinate.
     * The default implementation uses the scrollX and scrollY of the view as the result,
     * and put the value in the parameter pointer.
     * Components with different computation algorithm
     * <strong> should override </strong> this method.
     *
     * @param pointF the user visible left-top point in view's coordinate.
     */
    public void computeVisiblePointInViewCoordinate(PointF pointF) {
        View view = getRealView();
        pointF.set(view.getScrollX(), view.getScrollY());
    }

    public boolean containsGesture(WXGestureType WXGestureType) {
        return mGestureType != null && mGestureType.contains(WXGestureType.toString());
    }

    protected boolean containsEvent(String event) {
        return mDomObj.getEvents().contains(event) || mAppendEvents.contains(event);
    }

    public void notifyAppearStateChange(String wxEventType, String direction) {
        if (containsEvent(Constants.Event.APPEAR) || containsEvent(Constants.Event.DISAPPEAR)) {
            Map<String, Object> params = new HashMap<>();
            params.put("direction", direction);
            fireEvent(wxEventType, params);
        }
    }

    public boolean isUsing() {
        return isUsing;
    }

    public void setUsing(boolean using) {
        isUsing = using;
    }

    public void readyToRender() {
        if (mParent != null && getInstance().isTrackComponent()) {
            mParent.readyToRender();
        }
    }

    public static class MeasureOutput {

        public int width;
        public int height;
    }

    /**
     * Determine whether the current component needs to be placed in the real View tree
     * @return false component add subview
     */
    public boolean isVirtualComponent() {
        return false;
    }

    public void removeVirtualComponent() {
    }

    public boolean hasScrollParent(WXComponent component) {
        if (component.getParent() == null) {
            return true;
        } else if (component.getParent() instanceof WXScroller) {
            return false;
        } else {
            return hasScrollParent(component.getParent());
        }
    }

    /**
     * Called when property has empty value
     * @param propName
       */
    @CheckResult
    protected Object convertEmptyProperty(String propName, Object originalValue) {
        if (Constants.Name.BACKGROUND_COLOR.equals(propName)) {
            return "transparent";
        }
        return originalValue;
    }

    private void setActiveTouchListener() {
        boolean hasActivePesudo = mDomObj.getStyles().getPesudoStyles().containsKey(Constants.PSEUDO.ACTIVE);
        View view;
        if (hasActivePesudo && (view = getRealView()) != null) {
            boolean hasTouchConsumer = (mHostClickListeners != null && mHostClickListeners.size() > 0)
                    || mGesture != null;
            view.setOnTouchListener(new TouchActivePseudoListener(this, !hasTouchConsumer));
        }
    }

    @Override
    public void updateActivePseudo(boolean isSet) {
        setPseudoClassStatus(Constants.PSEUDO.ACTIVE, isSet);
    }

    /**
     *
     * @param clzName like ':active' or ':active:enabled'
     * @param status
     */
    protected void setPseudoClassStatus(String clzName, boolean status) {
        WXStyle styles = getDomObject().getStyles();
        Map<String, Map<String, Object>> pesudoStyles = styles.getPesudoStyles();

        if (pesudoStyles == null || pesudoStyles.size() == 0) {
            return;
        }
        Map<String, Object> resultStyles = mPesudoStatus.updateStatusAndGetUpdateStyles(clzName, status,
                pesudoStyles, styles.getPesudoResetStyles());
        updateStyleByPesudo(resultStyles);
    }

    private void updateStyleByPesudo(Map<String, Object> styles) {
        Message message = Message.obtain();
        WXDomTask task = new WXDomTask();
        task.instanceId = getInstanceId();
        task.args = new ArrayList<>();

        JSONObject styleJson = new JSONObject(styles);
        task.args.add(getRef());
        task.args.add(styleJson);
        task.args.add(true);//flag pesudo
        message.obj = task;
        message.what = WXDomHandler.MsgType.WX_DOM_UPDATE_STYLE;
        WXSDKManager.getInstance().getWXDomManager().sendMessage(message);
    }

    public int getStickyOffset() {
        return mStickyOffset;
    }

    public boolean canRecycled() {
        return mCanRecycled;
    }

    /**
     * Sets the offset for the sticky
     * @param stickyOffset child[y]-parent[y]
     */
    public void setStickyOffset(int stickyOffset) {
        mStickyOffset = stickyOffset;
    }
}