/**
* 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.graphics.Color;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import com.taobao.weex.IWXActivityStateListener;
import com.taobao.weex.WXEnvironment;
import com.taobao.weex.WXSDKInstance;
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.WXDomObject;
import com.taobao.weex.dom.flex.CSSLayout;
import com.taobao.weex.dom.flex.Spacing;
import com.taobao.weex.ui.IFComponentHolder;
import com.taobao.weex.ui.component.list.WXCell;
import com.taobao.weex.ui.component.list.WXListComponent;
import com.taobao.weex.ui.view.WXCircleIndicator;
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.ui.view.refresh.wrapper.BaseBounceView;
import com.taobao.weex.ui.view.refresh.wrapper.BounceRecyclerView;
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 {
public static int mComponentNum = 0;
public T mHost;
/** Use {@link #getParent()} instead. Do not access this field outside of this class which will be removed soon.**/
@Deprecated
public volatile WXVContainer mParent;
/** Use {@link #getDomObject()} instead. Do not access this field outside of this class which will be removed soon.**/
@Deprecated
public volatile WXDomObject mDomObj;
/** Use {@link #getInstanceId()} ()} instead. Do not access this field outside of this class which will be removed soon.**/
@Deprecated
public final String mInstanceId;
/** Use {@link #getInstance()} instead. Do not access this field outside of this class which will be removed soon.**/
@Deprecated
protected WXSDKInstance mInstance;
/** Use {@link #getContext()} instead. Do not access this field outside of this class which will be removed soon.**/
@Deprecated
protected Context mContext;
protected int mAbsoluteY = 0;
protected int mAbsoluteX = 0;
protected Set<String> mGestureType;
private BorderDrawable mBackgroundDrawable;
private boolean mLazy;
private int mPreRealWidth = 0;
private int mPreRealHeight = 0;
private int mPreRealLeft = 0;
private int mPreRealTop = 0;
private WXGesture wxGesture;
private IFComponentHolder mHolder;
private boolean isUsing = false;
private List<OnClickListener> mHostClickListeners;
private List<OnFocusChangeListener> mFocusChangeListeners;
private String mCurrentRef;
private OnClickListener mClickEventListener = new OnClickListener() {
@Override
public void onHostViewClick() {
Map<String, Object> params = new HashMap<>();
int[] location = new int[2];
mHost.getLocationOnScreen(location);
params.put("x", location[0]);
params.put("y", location[1]);
params.put("width", mDomObj.getCSSLayoutWidth());
params.put("height", mDomObj.getCSSLayoutHeight());
getInstance().fireEvent(mCurrentRef,
Constants.Event.CLICK,
params);
}
};
public String getInstanceId() {
return mInstanceId;
}
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);
}
public WXComponent(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, boolean isLazy) {
mInstance = instance;
mContext = mInstance.getContext();
mParent = parent;
mDomObj = dom.clone();
mInstanceId = instance.getInstanceId();
mLazy = isLazy;
mCurrentRef = mDomObj.getRef();
mGestureType = new HashSet<>();
++mComponentNum;
}
public void bindHolder(IFComponentHolder holder){
mHolder = holder;
}
public WXSDKInstance getInstance(){
return mInstance;
}
public Context getContext(){
return mContext;
}
/**
* The view is created as needed
* @return true for lazy
*/
public boolean isLazy() {
return mLazy;
}
public void lazy(boolean lazy) {
mLazy = lazy;
}
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(WXDomObject domObject) {
if (mParent == null || domObject == null || TextUtils.isEmpty(mCurrentRef)) {
return;
}
mDomObj = domObject;
if (this instanceof WXRefresh && mParent instanceof WXScroller &&
hasScrollParent(mParent)) {
mInstance.setRefreshMargin(mDomObj.getCSSLayoutHeight());
}
if ((this instanceof WXBaseRefresh && mParent instanceof WXScroller)) {
return;
}
if (mParent instanceof WXScroller && hasScrollParent(mParent)) {
if (!(this instanceof WXBaseRefresh)) {
CSSLayout newLayout = new CSSLayout();
newLayout.copy(mDomObj.csslayout);
newLayout.position[CSSLayout.POSITION_TOP] = mDomObj.getCSSLayoutTop() - mInstance.getRefreshMargin();
mDomObj.csslayout.copy(newLayout);
}
}
Spacing parentPadding = mParent.getDomObject().getPadding();
Spacing parentBorder = 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));
int realRight = (int) margin.get(Spacing.RIGHT);
int realBottom = (int) margin.get(Spacing.BOTTOM);
if (mPreRealWidth == realWidth && mPreRealHeight == realHeight && mPreRealLeft == realLeft && mPreRealTop == realTop) {
return;
}
if (mParent != null) {
mAbsoluteY = (int) (mParent.mAbsoluteY + mDomObj.getLayoutY());
mAbsoluteX = (int) (mParent.mAbsoluteX + 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;
if (mHost instanceof WXCircleIndicator) {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(realWidth, realHeight);
params.setMargins(realLeft, realTop, realRight, realBottom);
mHost.setLayoutParams(params);
return;
}
//fixed style
if (mDomObj.isFixed() && mInstance.getRootView() != null) {
if (mHost.getParent() instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) mHost.getParent();
viewGroup.removeView(mHost);
}
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.width = realWidth;
params.height = realHeight;
params.setMargins(realLeft, realTop, realRight, realBottom);
mHost.setLayoutParams(params);
mInstance.getRootView().addView(mHost);
if (WXEnvironment.isApkDebugable()) {
WXLogUtils.d("Weex_Fixed_Style", "WXComponent:setLayout :" + realLeft + " " + realTop + " " + realWidth + " " + realHeight);
WXLogUtils.d("Weex_Fixed_Style", "WXComponent:setLayout Left:" + mDomObj.getStyles().getLeft() + " " + (int) mDomObj.getStyles().getTop());
}
return;
}
if (mParent.getRealView() instanceof ViewPager ) {
// ViewPager.LayoutParams params = new ViewPager.LayoutParams();
// params.width = realWidth;
// params.height = realHeight;
// mHost.setLayoutParams(params);
} else if (mParent.getRealView() instanceof BounceRecyclerView && this instanceof WXCell) {
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) mHost.getLayoutParams();
if (params == null)
params = new RecyclerView.LayoutParams(realWidth,realHeight);
params.width = realWidth;
params.height = realHeight;
params.setMargins(realLeft, 0, realRight, 0);
mHost.setLayoutParams(params);
} else if(mParent.getRealView() instanceof BaseBounceView && this instanceof WXBaseRefresh) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(realWidth,realHeight);
realTop = (int) (parentPadding.get(Spacing.TOP) - parentBorder.get(Spacing.TOP));
params.setMargins(realLeft, realTop, realRight, realBottom);
mHost.setLayoutParams(params);
} else if (mParent.getRealView() instanceof FrameLayout) {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(realWidth, realHeight);
params.setMargins(realLeft, realTop, realRight, realBottom);
mHost.setLayoutParams(params);
} else if (mParent.getRealView() instanceof LinearLayout) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(realWidth, realHeight);
params.setMargins(realLeft, realTop, realRight, realBottom);
mHost.setLayoutParams(params);
} else if (mParent.getRealView() instanceof ScrollView) {
ScrollView.LayoutParams params = new ScrollView.LayoutParams(realWidth, realHeight);
params.setMargins(realLeft, realTop, realRight, realBottom);
mHost.setLayoutParams(params);
}
mPreRealWidth = realWidth;
mPreRealHeight = realHeight;
mPreRealLeft = realLeft;
mPreRealTop = realTop;
}
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 updateProperties() {
// if (mDomObj.attr != null && mDomObj.attr.size() > 0) {
// updateProperties(mDomObj.attr);
// }
// if (mDomObj.style != null && mDomObj.style.size() > 0) {
// updateProperties(mDomObj.style);
// }
// }
private void addEvents() {
int count = mDomObj.getEvents().size();
for (int i = 0; i < count; ++i) {
addEvent(mDomObj.getEvents().get(i));
}
}
public void updateExtra(Object extra) {
}
public WXDomObject getDomObject() {
return mDomObj;
}
/**
* measure
*/
protected MeasureOutput measure(int width, int height) {
MeasureOutput measureOutput = new MeasureOutput();
measureOutput.width = width;
measureOutput.height = height;
return measureOutput;
}
public void updateProperties(Map<String, Object> props) {
if (props == null || mHost == null) {
return;
}
for(String key : props.keySet()) {
Object param = props.get(key);
if(!setProperty(key, param)){
Invoker invoker = mHolder.getMethod(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],props.get(key));
invoker.invoke(this, param);
} catch (Exception e) {
WXLogUtils.e("[WXComponent] updateProperties :" + "class:" + getClass() + "method:" + invoker.toString() + " function " + WXLogUtils.getStackTrace(e));
}
}
}
}
}
/**
* 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.DISABLED:
Boolean disabled = WXUtils.getBoolean(param,null);
if (disabled != null)
setDisabled(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.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.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;
}
}
public void addEvent(String type) {
if (TextUtils.isEmpty(type)) {
return;
}
mDomObj.addEvent(type);
if (type.equals(Constants.Event.CLICK) && getRealView() != 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());
getInstance().fireEvent(mCurrentRef,
hasFocus ? Constants.Event.FOCUS : Constants.Event.BLUR, params);
}
});
} else if (getRealView() != null &&
needGestureDetector(type)) {
if (getRealView() instanceof WXGestureObservable) {
if (wxGesture == null) {
wxGesture = new WXGesture(this, mContext);
}
mGestureType.add(type);
((WXGestureObservable) getRealView()).registerGestureListener(wxGesture);
} else {
WXLogUtils.e(getRealView().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
*
* @param parent
* @param index
*/
public final void createView(WXVContainer parent, int index) {
if(!isLazy()) {
createViewImpl(parent, index);
}
}
protected void createViewImpl(WXVContainer parent, int index) {
if (mContext != null) {
mHost = initComponentHostView(mContext);
if (mHost == null) {
//compatible
initView();
}
onHostViewInitialized(mHost);
if (parent != null) {
parent.addSubView(mHost, index);
}
}else{
WXLogUtils.e("createViewImpl","Context is null");
}
}
/**
* Use {@link #initComponentHostView(Context context)} instead.
*/
@Deprecated
protected void initView() {
if (mContext != null)
mHost = initComponentHostView(mContext);
}
protected T initComponentHostView(@NonNull Context context){
/**
* compatible old initView
* TODO: change to abstract method in next V1.0 .
*/
return null;
}
/**
* After view init.
*/
protected void onHostViewInitialized(T host){}
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;
}
public final void removeEvent(String type) {
if (TextUtils.isEmpty(type)) {
return;
}
mDomObj.removeEvent(type);
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);
}
mDomObj.clearEvents();
mGestureType.clear();
wxGesture = null;
if (getRealView() != null &&
getRealView() instanceof WXGestureObservable) {
((WXGestureObservable) getRealView()).registerGestureListener(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 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));
break;
case Constants.Name.BORDER_TOP_LEFT_RADIUS:
getOrCreateBorder().setBorderRadius(BorderDrawable.BORDER_TOP_LEFT_RADIUS, WXViewUtils.getRealSubPxByWidth(borderRadius));
break;
case Constants.Name.BORDER_TOP_RIGHT_RADIUS:
getOrCreateBorder().setBorderRadius(BorderDrawable.BORDER_TOP_RIGHT_RADIUS, WXViewUtils.getRealSubPxByWidth(borderRadius));
break;
case Constants.Name.BORDER_BOTTOM_RIGHT_RADIUS:
getOrCreateBorder().setBorderRadius(BorderDrawable.BORDER_BOTTOM_RIGHT_RADIUS, WXViewUtils.getRealSubPxByWidth(borderRadius));
break;
case Constants.Name.BORDER_BOTTOM_LEFT_RADIUS:
getOrCreateBorder().setBorderRadius(BorderDrawable.BORDER_BOTTOM_LEFT_RADIUS, WXViewUtils.getRealSubPxByWidth(borderRadius));
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));
break;
case Constants.Name.BORDER_TOP_WIDTH:
getOrCreateBorder().setBorderWidth(Spacing.TOP, WXViewUtils.getRealSubPxByWidth(borderWidth));
break;
case Constants.Name.BORDER_RIGHT_WIDTH:
getOrCreateBorder().setBorderWidth(Spacing.RIGHT, WXViewUtils.getRealSubPxByWidth(borderWidth));
break;
case Constants.Name.BORDER_BOTTOM_WIDTH:
getOrCreateBorder().setBorderWidth(Spacing.BOTTOM, WXViewUtils.getRealSubPxByWidth(borderWidth));
break;
case Constants.Name.BORDER_LEFT_WIDTH:
getOrCreateBorder().setBorderWidth(Spacing.LEFT, WXViewUtils.getRealSubPxByWidth(borderWidth));
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);
}
}
}
public void registerActivityStateListener() {
if (mInstance != null) {
mInstance.registerActivityStateListener(this);
}
}
@Override
public void onActivityCreate() {
}
@Override
public void onActivityStart() {
}
@Override
public void onActivityPause() {
}
@Override
public void onActivityResume() {
}
@Override
public void onActivityStop() {
}
@Override
public void onActivityDestroy() {
}
@Override
public boolean onActivityBack() {
return false;
}
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.destroy();
}
}
/**
* 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
* (e.g. {@link WXListComponent#computeVisiblePointInViewCoordinate(PointF)} )
* <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());
}
public void notifyAppearStateChange(String wxEventType,String direction){
if(getDomObject().containsEvent(Constants.Event.APPEAR) || getDomObject().containsEvent(Constants.Event.DISAPPEAR)) {
Map<String, Object> params = new HashMap<>();
params.put("direction", direction);
getInstance().fireEvent(getRef(), wxEventType, params,null);
}
}
public boolean isUsing() {
return isUsing;
}
public void setUsing(boolean using) {
isUsing = using;
}
public static class MeasureOutput {
public int width;
public int height;
}
public boolean hasScrollParent(WXComponent component) {
if (component.getParent() == null) {
return true;
} else if (component.getParent() instanceof WXScroller) {
return false;
} else {
return hasScrollParent(component.getParent());
}
}
}