From bc6ea406e05667712f7084b268bb16f81c2298fd Mon Sep 17 00:00:00 2001 From: YorkShen Date: Tue, 22 Aug 2017 11:37:04 +0800 Subject: [PATCH 01/10] * [android] Init commit for flatGUI --- .../adapter/PicassoBasedDrawableLoader.java | 112 ++++++++++++++ .../alibaba/weex/benchmark/BenchmarkTest.java | 29 ++-- .../java/com/alibaba/weex/WXApplication.java | 2 + .../java/com/taobao/weex/WXSDKInstance.java | 12 +- .../taobao/weex/adapter/DrawableStrategy.java | 5 + .../com/taobao/weex/common/Constants.java | 2 + .../taobao/weex/common/WXImageStrategy.java | 8 +- .../taobao/weex/dom/ImmutableDomObject.java | 21 ++- .../taobao/weex/ui/component/WXComponent.java | 127 +++++++++++---- .../com/taobao/weex/ui/component/WXDiv.java | 70 ++++++++- .../taobao/weex/ui/component/WXSlider.java | 4 +- .../com/taobao/weex/ui/component/WXText.java | 65 ++++---- .../weex/ui/component/WXVContainer.java | 44 ++++-- .../taobao/weex/ui/component/list/WXCell.java | 38 ++++- .../ui/component/list/WXListComponent.java | 53 +++---- .../taobao/weex/ui/flat/FlatComponent.java | 33 ++++ .../taobao/weex/ui/flat/FlatGUIIContext.java | 113 ++++++++++++++ .../taobao/weex/ui/flat/WidgetContainer.java | 92 +++++++++++ .../ui/flat/widget/AndroidViewWidget.java | 58 +++++++ .../weex/ui/flat/widget/BaseWidget.java | 146 ++++++++++++++++++ .../weex/ui/flat/widget/ImageWidget.java | 102 ++++++++++++ .../weex/ui/flat/widget/TextWidget.java | 49 ++++++ .../taobao/weex/ui/flat/widget/Widget.java | 63 ++++++++ .../weex/ui/flat/widget/WidgetGroup.java | 50 ++++++ .../taobao/weex/ui/view/WXFrameLayout.java | 50 +++++- 25 files changed, 1202 insertions(+), 146 deletions(-) create mode 100644 android/commons/src/main/java/com/alibaba/weex/commons/adapter/PicassoBasedDrawableLoader.java create mode 100644 android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatComponent.java create mode 100644 android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java create mode 100644 android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java create mode 100644 android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java create mode 100644 android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java create mode 100644 android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/ImageWidget.java create mode 100644 android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java create mode 100644 android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java create mode 100644 android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java diff --git a/android/commons/src/main/java/com/alibaba/weex/commons/adapter/PicassoBasedDrawableLoader.java b/android/commons/src/main/java/com/alibaba/weex/commons/adapter/PicassoBasedDrawableLoader.java new file mode 100644 index 0000000000..0d03934e58 --- /dev/null +++ b/android/commons/src/main/java/com/alibaba/weex/commons/adapter/PicassoBasedDrawableLoader.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package com.alibaba.weex.commons.adapter; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.PixelFormat; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.view.Gravity; + +import com.squareup.picasso.Picasso; +import com.squareup.picasso.Target; +import com.taobao.weex.WXSDKManager; +import com.taobao.weex.adapter.DrawableStrategy; +import com.taobao.weex.adapter.IDrawableLoader; + + +public class PicassoBasedDrawableLoader implements IDrawableLoader { + + private Context mContext; + + public PicassoBasedDrawableLoader(Context context) { + mContext = context; + } + + @Override + public void setDrawable(final String url, + final DrawableTarget drawableTarget, + final DrawableStrategy drawableStrategy) { + WXSDKManager.getInstance().postOnUiThread(new Runnable() { + @Override + public void run() { + String temp = url; + if (url.startsWith("//")) { + temp = "http:" + url; + } + + /** This is a hack for picasso, as Picasso hold weakReference to Target. + * http://stackoverflow.com/questions/24180805/onbitmaploaded-of-target-object-not-called-on-first-load + */ + class PlaceHolderDrawableTarget extends Drawable implements Target { + + @Override + public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { + BitmapDrawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap); + bitmapDrawable.setGravity(Gravity.FILL); + if(drawableTarget instanceof StaticTarget) { + ((StaticTarget) drawableTarget).setDrawable(bitmapDrawable, true); + } + } + + @Override + public void onBitmapFailed(Drawable errorDrawable) { + + } + + @Override + public void onPrepareLoad(Drawable placeHolderDrawable) { + if(drawableTarget instanceof StaticTarget) { + ((StaticTarget) drawableTarget).setDrawable(this, true); + } + } + + @Override + public void draw(Canvas canvas) { + + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + + } + + @Override + public int getOpacity() { + return PixelFormat.UNKNOWN; + } + } + Picasso. + with(mContext). + load(temp). + into(new PlaceHolderDrawableTarget()); + } + }, 0); + + } +} \ No newline at end of file diff --git a/android/playground/app/src/androidTest/java/com/alibaba/weex/benchmark/BenchmarkTest.java b/android/playground/app/src/androidTest/java/com/alibaba/weex/benchmark/BenchmarkTest.java index dddada7add..2c5f8e773b 100644 --- a/android/playground/app/src/androidTest/java/com/alibaba/weex/benchmark/BenchmarkTest.java +++ b/android/playground/app/src/androidTest/java/com/alibaba/weex/benchmark/BenchmarkTest.java @@ -19,6 +19,10 @@ package com.alibaba.weex.benchmark; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.matcher.ViewMatchers.withClassName; +import static org.hamcrest.MatcherAssert.assertThat; + import android.support.test.InstrumentationRegistry; import android.support.test.espresso.contrib.RecyclerViewActions; import android.support.test.filters.SdkSuppress; @@ -30,18 +34,9 @@ import android.support.test.uiautomator.Until; import android.text.TextUtils; import android.util.Log; - import com.alibaba.weex.BenchmarkActivity; import com.taobao.weex.ui.view.listview.WXRecyclerView; import com.taobao.weex.utils.WXLogUtils; - -import org.hamcrest.Matchers; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; @@ -49,10 +44,12 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; - -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.matcher.ViewMatchers.withClassName; -import static org.hamcrest.MatcherAssert.assertThat; +import org.hamcrest.Matchers; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class BenchmarkTest { @@ -68,9 +65,7 @@ public class BenchmarkTest { private static List firstScreenRenderTime = new LinkedList<>(); private static List flingFrameSeconds = new LinkedList<>(); private static List scrollFrameSeconds = new LinkedList<>(); - private static final String DUMP_START = "Flags,IntendedVsync,Vsync,OldestInputEvent,NewestInputEvent," - + "HandleInputStart,AnimationStart,PerformTraversalsStart,DrawStart," - + "SyncQueued,SyncStart,IssueDrawCommandsStart,SwapBuffers,FrameCompleted,\n"; + private static final String DUMP_START = "QueueBufferDuration,\n"; private static final String DUMP_END = "---PROFILEDATA---"; private static final String DUMP_COMMAND = "dumpsys gfxinfo com.alibaba.weex framestats reset"; @@ -195,7 +190,7 @@ private List createList(BufferedReader bufferedReader) throws IOException private long calcTime() { BenchmarkActivity benchmarkActivity = mActivityRule.getActivity(); - benchmarkActivity.loadWeexPage(); + benchmarkActivity.loadWeexPage("http://30.8.53.163:8080/complicated.js"); onView(withClassName(Matchers.is(WXRecyclerView.class.getName()))).perform (RecyclerViewActions.scrollToPosition(0)); return benchmarkActivity.getWXInstance().getWXPerformance().screenRenderTime; diff --git a/android/playground/app/src/main/java/com/alibaba/weex/WXApplication.java b/android/playground/app/src/main/java/com/alibaba/weex/WXApplication.java index 561d2921b4..584434137f 100644 --- a/android/playground/app/src/main/java/com/alibaba/weex/WXApplication.java +++ b/android/playground/app/src/main/java/com/alibaba/weex/WXApplication.java @@ -25,6 +25,7 @@ import com.alibaba.weex.commons.adapter.DefaultWebSocketAdapterFactory; import com.alibaba.weex.commons.adapter.ImageAdapter; import com.alibaba.weex.commons.adapter.JSExceptionAdapter; +import com.alibaba.weex.commons.adapter.PicassoBasedDrawableLoader; import com.alibaba.weex.extend.PlayDebugAdapter; import com.alibaba.weex.extend.adapter.InterceptWXHttpAdapter; import com.alibaba.weex.extend.component.RichText; @@ -70,6 +71,7 @@ public void onCreate() { .setWebSocketAdapterFactory(new DefaultWebSocketAdapterFactory()) .setJSExceptionAdapter(new JSExceptionAdapter()) .setHttpAdapter(new InterceptWXHttpAdapter()) + .setDrawableLoader(new PicassoBasedDrawableLoader(this)) .build() ); diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java index d1bbd52aaa..a3ae67e505 100644 --- a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java +++ b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java @@ -28,6 +28,8 @@ import android.os.Message; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.RestrictTo; +import android.support.annotation.RestrictTo.Scope; import android.text.TextUtils; import android.util.Log; import android.view.Menu; @@ -68,6 +70,7 @@ import com.taobao.weex.ui.component.WXBasicComponentType; import com.taobao.weex.ui.component.WXComponent; import com.taobao.weex.ui.component.WXComponentFactory; +import com.taobao.weex.ui.flat.FlatGUIIContext; import com.taobao.weex.ui.view.WXScrollView; import com.taobao.weex.ui.view.WXScrollView.WXScrollViewListener; import com.taobao.weex.utils.Trace; @@ -88,7 +91,6 @@ import static com.taobao.weex.http.WXHttpUtil.KEY_USER_AGENT; - /** * Each instance of WXSDKInstance represents an running weex instance. * It can be a pure weex view, or mixed with native view @@ -120,6 +122,8 @@ public class WXSDKInstance implements IWXActivityStateListener,DomContext, View. private boolean mNeedReLoad = false; private static volatile int mViewPortWidth = 750; private int mInstanceViewPortWidth = 750; + private final @NonNull + FlatGUIIContext mUIImp =new FlatGUIIContext(); public long mRenderStartNanos; public int mExecJSTraceId = WXTracing.nextId(); @@ -200,6 +204,11 @@ public void enableLayerType(boolean enable) { enableLayerType = enable; } + public @NonNull + FlatGUIIContext getFlatUIContext(){ + return mUIImp; + } + public boolean isNeedValidate() { return mNeedValidate; } @@ -251,6 +260,7 @@ public WXSDKInstance(Context context) { /** * For unittest only. */ + @RestrictTo(Scope.TESTS) WXSDKInstance(Context context,String id) { mInstanceId = id; init(context); diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/DrawableStrategy.java b/android/sdk/src/main/java/com/taobao/weex/adapter/DrawableStrategy.java index c6daa5a3e2..6c01aa81ff 100644 --- a/android/sdk/src/main/java/com/taobao/weex/adapter/DrawableStrategy.java +++ b/android/sdk/src/main/java/com/taobao/weex/adapter/DrawableStrategy.java @@ -20,8 +20,13 @@ package com.taobao.weex.adapter; +import com.taobao.weex.common.WXImageStrategy; +import com.taobao.weex.dom.WXImageQuality; + public class DrawableStrategy { public int width; public int height; + public WXImageStrategy imageStrategy; + public WXImageQuality imageQuality; } diff --git a/android/sdk/src/main/java/com/taobao/weex/common/Constants.java b/android/sdk/src/main/java/com/taobao/weex/common/Constants.java index 06fb668b09..4be1f28756 100644 --- a/android/sdk/src/main/java/com/taobao/weex/common/Constants.java +++ b/android/sdk/src/main/java/com/taobao/weex/common/Constants.java @@ -181,6 +181,8 @@ public interface Name { String ARIA_LABEL = "ariaLabel"; String ARIA_HIDDEN = "ariaHidden"; String UNDEFINED = "undefined"; + + String FLAT = "flat"; } public interface Value { diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXImageStrategy.java b/android/sdk/src/main/java/com/taobao/weex/common/WXImageStrategy.java index 994c99bf2c..de2572eebe 100644 --- a/android/sdk/src/main/java/com/taobao/weex/common/WXImageStrategy.java +++ b/android/sdk/src/main/java/com/taobao/weex/common/WXImageStrategy.java @@ -19,7 +19,7 @@ package com.taobao.weex.common; import android.widget.ImageView; - +import com.taobao.weex.adapter.IDrawableLoader.DrawableTarget; import java.util.Map; public class WXImageStrategy { @@ -58,6 +58,12 @@ public void setImageListener(ImageListener imageListener) { ImageListener imageListener; + WidgetListener widgetListener; + + public interface WidgetListener{ + public void onImageFinish(String url,DrawableTarget drawableTarget,boolean result,Map extra); + } + public interface ImageListener{ public void onImageFinish(String url,ImageView imageView,boolean result,Map extra); } diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/ImmutableDomObject.java b/android/sdk/src/main/java/com/taobao/weex/dom/ImmutableDomObject.java index 55439c39ac..c19ca59ddf 100644 --- a/android/sdk/src/main/java/com/taobao/weex/dom/ImmutableDomObject.java +++ b/android/sdk/src/main/java/com/taobao/weex/dom/ImmutableDomObject.java @@ -19,11 +19,8 @@ package com.taobao.weex.dom; import android.support.annotation.NonNull; - import com.taobao.weex.dom.flex.Spacing; -import static com.taobao.weex.dom.WXDomObject.DESTROYED; - /** * Created by sospartan on 25/10/2016. */ @@ -33,8 +30,26 @@ public interface ImmutableDomObject { @NonNull Spacing getMargin(); float getLayoutWidth(); float getLayoutHeight(); + + /** + * Use {@link #getCSSLayoutLeft()} ()} instead + */ + @Deprecated float getLayoutX(); + + /** + * Use {@link #getCSSLayoutTop()} instead + */ + @Deprecated float getLayoutY(); + + public float getCSSLayoutTop(); + + public float getCSSLayoutBottom(); + + public float getCSSLayoutLeft(); + + public float getCSSLayoutRight(); boolean isFixed(); @NonNull WXStyle getStyles(); @NonNull WXEvent getEvents(); diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java index dd7e4705ed..d18354463e 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java @@ -22,6 +22,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.Color; +import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Shader; @@ -39,8 +40,8 @@ import android.view.Menu; import android.view.View; import android.view.ViewGroup; +import android.view.ViewGroup.MarginLayoutParams; import android.widget.FrameLayout; - import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.taobao.weex.ComponentObserver; @@ -66,6 +67,11 @@ 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.flat.FlatComponent; +import com.taobao.weex.ui.flat.WidgetContainer; +import com.taobao.weex.ui.flat.FlatGUIIContext; +import com.taobao.weex.ui.flat.widget.AndroidViewWidget; +import com.taobao.weex.ui.flat.widget.Widget; import com.taobao.weex.ui.view.border.BorderDrawable; import com.taobao.weex.ui.view.gesture.WXGesture; import com.taobao.weex.ui.view.gesture.WXGestureObservable; @@ -76,7 +82,6 @@ import com.taobao.weex.utils.WXResourceUtils; import com.taobao.weex.utils.WXUtils; import com.taobao.weex.utils.WXViewUtils; - import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -393,15 +398,17 @@ 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})); + if (mHost != null) { + Drawable backgroundDrawable = mHost.getBackground(); + WXViewUtils.setBackGround(mHost, null); + 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; @@ -432,6 +439,9 @@ public final void setLayout(ImmutableDomObject domObject) { parentBorder.get(Spacing.TOP)) + siblingOffset; int realRight = (int) margin.get(Spacing.RIGHT); int realBottom = (int) margin.get(Spacing.BOTTOM); + Point rawOffset = new Point( + (int) mDomObj.getCSSLayoutLeft(), + (int) mDomObj.getCSSLayoutTop()); if (mPreRealWidth == realWidth && mPreRealHeight == realHeight && mPreRealLeft == realLeft && mPreRealTop == realTop) { return; @@ -445,32 +455,71 @@ public final void setLayout(ImmutableDomObject domObject) { 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(); + setComponentLayoutParams(realWidth, realHeight, realLeft, realTop, realRight, realBottom, rawOffset); } + private void setComponentLayoutParams(int realWidth, int realHeight, int realLeft, int realTop, + int realRight, int realBottom, Point rawOffset) { + FlatGUIIContext UIImp = getInstance().getFlatUIContext(); + WidgetContainer ancestor; + Widget widget; + if ((ancestor = UIImp.getFlatComponentAncestor(this)) != null) { + if (this instanceof FlatComponent && !((FlatComponent) this).promoteToView(true)) { + widget = ((FlatComponent) this).getOrCreateFlatWidget(); + } else { + //TODO Be careful with nested hierarchy, such as widget, view, widget hierarchy. + widget = UIImp.getAndroidViewWidget(this); + } + setWidgetParams(widget, UIImp, rawOffset, realWidth, realHeight, realLeft, realRight, realTop, + realBottom); + } else if (mHost != null) { + 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(); + } + } + + private void setWidgetParams(Widget widget, FlatGUIIContext UIImp, Point rawoffset, + int width, int height, int left, int right, int top, int bottom) { + Point childOffset = new Point(rawoffset.x, rawoffset.y); + if (mParent != null) { + if (mParent instanceof FlatComponent && + UIImp.getFlatComponentAncestor(mParent) != null && + UIImp.getAndroidViewWidget(mParent) == null) { + Point parentLayoutOffset = ((FlatComponent) mParent).getOrCreateFlatWidget().getLocInFlatContainer(); + childOffset.offset(parentLayoutOffset.x, parentLayoutOffset.y); + } + ViewGroup.LayoutParams lp = mParent + .getChildLayoutParams(this, mHost, width, height, left, right, top, bottom); + if (lp instanceof MarginLayoutParams) { + width = lp.width; + height = lp.height; + left = ((MarginLayoutParams) lp).leftMargin; + right = ((MarginLayoutParams) lp).rightMargin; + top = ((MarginLayoutParams) lp).topMargin; + bottom = ((MarginLayoutParams) lp).bottomMargin; + } + } + widget.setLayout(width, height, left, right, top, bottom, childOffset); - public int getLayoutTopOffsetForSibling(){ - return 0; + if (widget instanceof AndroidViewWidget) { + //TODO generic method if ever possible + setHostLayoutParams((T) ((AndroidViewWidget) widget).getView(), + width, height, childOffset.x, right, childOffset.y, bottom); + } } protected void setHostLayoutParams(T host, int width, int height, int left, int right, int top, int bottom){ @@ -513,6 +562,10 @@ protected void onFinishLayout() { } } + public int getLayoutTopOffsetForSibling(){ + return 0; + } + public float getLayoutWidth(){ float w = 0f; if (mDomObj != null) { @@ -537,10 +590,11 @@ public void setPadding(Spacing padding, Spacing border) { 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; + if (this instanceof FlatComponent && !((FlatComponent) this).promoteToView(true)) { + ((FlatComponent) this).getOrCreateFlatWidget().setContentBox(left, top, right, bottom); + } else if (mHost != null) { + mHost.setPadding(left, top, right, bottom); } - mHost.setPadding(left, top, right, bottom); } private void addEvents() { @@ -610,6 +664,13 @@ public void updateProperties(Map props) { } } readyToRender(); + if (this instanceof FlatComponent && mBackgroundDrawable != null) { + FlatComponent flatComponent = (FlatComponent) this; + if (!flatComponent.promoteToView(true) && !(flatComponent + .getOrCreateFlatWidget() instanceof AndroidViewWidget)) { + flatComponent.getOrCreateFlatWidget().setBackgroundAndBorder(mBackgroundDrawable); + } + } } /** @@ -644,7 +705,7 @@ protected boolean setProperty(String key, Object param) { return true; case Constants.Name.BACKGROUND_IMAGE: String bgImage = WXUtils.getString(param, null); - if (bgImage != null && mHost != null) { + if (bgImage != null) { setBackgroundImage(bgImage); } return true; @@ -1098,7 +1159,7 @@ public void setSticky(String sticky) { } public void setBackgroundColor(String color) { - if (!TextUtils.isEmpty(color)&& mHost!=null) { + if (!TextUtils.isEmpty(color)) { int colorInt = WXResourceUtils.getColor(color); if (!(colorInt == Color.TRANSPARENT && mBackgroundDrawable == null)){ getOrCreateBorder().setColor(colorInt); diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java index 2772cc6217..18c734ed11 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java @@ -20,41 +20,95 @@ import android.content.Context; import android.support.annotation.NonNull; - import com.taobao.weex.WXSDKInstance; import com.taobao.weex.annotation.Component; import com.taobao.weex.dom.WXDomObject; import com.taobao.weex.ui.ComponentCreator; +import com.taobao.weex.ui.flat.FlatComponent; +import com.taobao.weex.ui.flat.WidgetContainer; +import com.taobao.weex.ui.flat.widget.WidgetGroup; import com.taobao.weex.ui.view.WXFrameLayout; - import java.lang.reflect.InvocationTargetException; /** * div component */ @Component(lazyload = false) -public class WXDiv extends WXVContainer { +public class WXDiv extends WidgetContainer implements FlatComponent { + + private WidgetGroup mWidgetGroup; public static class Ceator implements ComponentCreator { - public WXComponent createInstance(WXSDKInstance instance, WXDomObject node, WXVContainer parent) throws IllegalAccessException, InvocationTargetException, InstantiationException { - return new WXDiv(instance,node,parent); + + public WXComponent createInstance(WXSDKInstance instance, WXDomObject node, WXVContainer parent) + throws IllegalAccessException, InvocationTargetException, InstantiationException { + return new WXDiv(instance, node, parent); } } @Deprecated - public WXDiv(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, String instanceId, boolean isLazy) { - this(instance,dom,parent); + public WXDiv(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, String instanceId, + boolean isLazy) { + this(instance, dom, parent); } public WXDiv(WXSDKInstance instance, WXDomObject node, WXVContainer parent) { super(instance, node, parent); } + @Override protected WXFrameLayout initComponentHostView(@NonNull Context context) { - WXFrameLayout frameLayout =new WXFrameLayout(context); + WXFrameLayout frameLayout = new WXFrameLayout(context); frameLayout.holdComponent(this); return frameLayout; } + @Override + public boolean promoteToView(boolean checkAncestor) { + return !intendToBeFlatContainer() || + getInstance().getFlatUIContext().promoteToView(this, checkAncestor, WXDiv.class); + } + + /** + * Create View tree there. Either this method or {@link #createViewImpl()} get called. + * If this object will be promoted to view, then getOrCreateFlatWidget() should never be called. + */ + @Override + @NonNull + public WidgetGroup getOrCreateFlatWidget() { + if (mWidgetGroup == null) { + mWidgetGroup = new WidgetGroup(getInstance().getFlatUIContext().getFlatComponentAncestor(this).getHostView()); + for (int i = 0; i < getChildCount(); i++) { + createChildViewAt(i); + } + mountFlatGUI(); + } + return mWidgetGroup; + } + + @Override + protected void mountFlatGUI() { + if (promoteToView(true)) { + getHostView().mountFlatGUI(widgets); + } else { + mWidgetGroup.replaceAll(widgets); + } + } + + @Override + public void unmountFlatGUI() { + //TODO unmout must be called before you mount FlatGUI second times. + } + + @Override + public boolean intendToBeFlatContainer() { + return getInstance().getFlatUIContext().isFlatUIEnabled() && WXDiv.class.equals(getClass()); + } + + @Override + public boolean isVirtualComponent() { + return !promoteToView(true); + } + } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSlider.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSlider.java index 4ef51f3808..1023e3e45f 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSlider.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSlider.java @@ -29,7 +29,6 @@ import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.widget.FrameLayout; - import com.taobao.weex.WXEnvironment; import com.taobao.weex.WXSDKInstance; import com.taobao.weex.WXSDKManager; @@ -45,7 +44,6 @@ import com.taobao.weex.utils.WXLogUtils; import com.taobao.weex.utils.WXUtils; import com.taobao.weex.utils.WXViewUtils; - import java.lang.ref.WeakReference; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; @@ -132,7 +130,7 @@ protected FrameLayout initComponentHostView(@NonNull Context context) { */ @Override public LayoutParams getChildLayoutParams(WXComponent child,View childView, int width, int height, int left, int right, int top, int bottom) { - ViewGroup.LayoutParams lp = childView.getLayoutParams(); + ViewGroup.LayoutParams lp = childView == null ? null : childView.getLayoutParams(); if (lp == null) { lp = new FrameLayout.LayoutParams(width, height); } else { diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXText.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXText.java index aad2bf4451..e07a0372d0 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXText.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXText.java @@ -33,6 +33,8 @@ import com.taobao.weex.common.Constants; import com.taobao.weex.dom.WXDomObject; import com.taobao.weex.ui.ComponentCreator; +import com.taobao.weex.ui.flat.FlatComponent; +import com.taobao.weex.ui.flat.widget.TextWidget; import com.taobao.weex.ui.view.WXTextView; import com.taobao.weex.utils.FontDO; import com.taobao.weex.utils.TypefaceUtil; @@ -44,7 +46,9 @@ * Text component */ @Component(lazyload = false) -public class WXText extends WXComponent { +public class WXText extends WXComponent implements FlatComponent { + + private TextWidget mTextWidget; /** * The default text size @@ -53,6 +57,25 @@ public class WXText extends WXComponent { private BroadcastReceiver mTypefaceObserver; private String mFontFamily; + @Override + public boolean promoteToView(boolean checkAncestor) { + return getInstance().getFlatUIContext().promoteToView(this, checkAncestor, WXText.class); + } + + @Override + @NonNull + public TextWidget getOrCreateFlatWidget() { + if (mTextWidget == null) { + mTextWidget = new TextWidget(getInstance().getFlatUIContext().getFlatComponentAncestor(this).getHostView()); + } + return mTextWidget; + } + + @Override + public boolean isVirtualComponent() { + return !promoteToView(true); + } + public static class Creator implements ComponentCreator { public WXComponent createInstance(WXSDKInstance instance, WXDomObject node, WXVContainer parent) throws IllegalAccessException, InvocationTargetException, InstantiationException { @@ -79,11 +102,14 @@ protected WXTextView initComponentHostView(@NonNull Context context) { @Override public void updateExtra(Object extra) { - if (extra instanceof Layout && - getHostView() != null && !extra.equals(getHostView().getTextLayout())) { + if(extra instanceof Layout) { final Layout layout = (Layout) extra; - getHostView().setTextLayout(layout); - getHostView().invalidate(); + if (!promoteToView(true)) { + getOrCreateFlatWidget().updateTextDrawable(layout); + } else if (getHostView() != null && !extra.equals(getHostView().getTextLayout())) { + getHostView().setTextLayout(layout); + getHostView().invalidate(); + } } } @@ -127,28 +153,6 @@ protected boolean setProperty(String key, Object param) { } } - /** - * Flush view no matter what height and width the {@link WXDomObject} specifies. - * @param extra must be a {@link Layout} object, otherwise, nothing will happen. - */ - private void flushView(Object extra) { - if (extra instanceof Layout && - getHostView() != null && !extra.equals(getHostView().getTextLayout())) { - final Layout layout = (Layout) extra; - /**The following if block change the height of the width of the textView. - * other part of the code is the same to updateExtra - */ - ViewGroup.LayoutParams layoutParams = getHostView().getLayoutParams(); - if (layoutParams != null) { - layoutParams.height = layout.getHeight(); - layoutParams.width = layout.getWidth(); - getHostView().setLayoutParams(layoutParams); - } - getHostView().setTextLayout(layout); - getHostView().invalidate(); - } - } - @Override protected Object convertEmptyProperty(String propName, Object originalValue) { switch (propName) { @@ -160,6 +164,13 @@ protected Object convertEmptyProperty(String propName, Object originalValue) { return super.convertEmptyProperty(propName, originalValue); } + @Override + protected void createViewImpl() { + if(promoteToView(true)) { + super.createViewImpl(); + } + } + @Override public void destroy() { super.destroy(); diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java index f769c2af65..43b45a711d 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java @@ -19,15 +19,14 @@ package com.taobao.weex.ui.component; import android.content.Intent; +import android.util.Pair; import android.support.annotation.Nullable; import android.view.Menu; import android.view.View; import android.view.ViewGroup; - import com.taobao.weex.WXSDKInstance; import com.taobao.weex.common.Constants; import com.taobao.weex.dom.WXDomObject; - import java.util.ArrayList; /** @@ -115,7 +114,11 @@ public void applyLayoutAndEvent(WXComponent component) { * */ public ViewGroup.LayoutParams getChildLayoutParams(WXComponent child,View childView, int width, int height, int left, int right, int top, int bottom){ - ViewGroup.LayoutParams lp = childView.getLayoutParams(); + ViewGroup.LayoutParams lp = null; + if (childView != null) { + lp = childView.getLayoutParams(); + } + if(lp == null) { lp = new ViewGroup.LayoutParams(width,height); }else{ @@ -228,6 +231,11 @@ public View detachViewAndClearPreInfo(){ return original; } + /** + * Use {@link #getChildCount()} instead + * @return + */ + @Deprecated public int childCount() { return mChildren == null ? 0 : mChildren.size(); } @@ -242,7 +250,7 @@ public WXComponent getChild(int index) { } public int getChildCount() { - return mChildren.size(); + return childCount(); } public void addChild(WXComponent child) { @@ -268,21 +276,31 @@ public final int indexOf(WXComponent comp){ return mChildren.indexOf(comp); } - public void createChildViewAt(int index){ + public void createChildViewAt(int index) { long startNanos = System.nanoTime(); + Pair ret = rearrangeIndexAndGetChild(index); + if (ret.first != null) { + WXComponent child = ret.first; + child.createView(); + if (!child.isVirtualComponent()) { + addSubView(child.getHostView(), ret.second); + } + } + mTraceInfo.uiThreadNanos += (System.nanoTime() - startNanos); + } + + protected Pair rearrangeIndexAndGetChild(int index){ int indexToCreate = index; if(indexToCreate < 0){ indexToCreate = childCount()-1; - if(indexToCreate < 0 ){ - return; - } } - WXComponent child = getChild(indexToCreate); - child.createView(); - if(!child.isVirtualComponent()){ - addSubView(child.getHostView(),indexToCreate); + + if (indexToCreate<0){ + return new Pair<>(null, indexToCreate); + } + else { + return new Pair<>(getChild(indexToCreate), indexToCreate); } - mTraceInfo.uiThreadNanos += (System.nanoTime() - startNanos); } protected void addSubView(View child, int index) { diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java index 3095c04dbb..cac3048703 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java @@ -20,22 +20,25 @@ import android.content.Context; import android.support.annotation.NonNull; +import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; - import com.taobao.weex.WXSDKInstance; import com.taobao.weex.annotation.Component; +import com.taobao.weex.common.Constants.Name; import com.taobao.weex.dom.WXDomObject; import com.taobao.weex.ui.component.WXVContainer; +import com.taobao.weex.ui.flat.WidgetContainer; import com.taobao.weex.ui.view.WXFrameLayout; +import com.taobao.weex.utils.WXUtils; /** * Root component for components in {@link WXListComponent} */ @Component(lazyload = false) -public class WXCell extends WXVContainer { +public class WXCell extends WidgetContainer { private int mLastLocationY = 0; private ViewGroup mRealView; @@ -49,11 +52,11 @@ public class WXCell extends WXVContainer { @Deprecated public WXCell(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, String instanceId, boolean isLazy) { - this(instance,dom,parent,isLazy); + super(instance, dom, parent); } public WXCell(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, boolean isLazy) { - super(instance, dom, parent,true ); + super(instance, dom, parent); } @Override @@ -82,6 +85,17 @@ protected WXFrameLayout initComponentHostView(@NonNull Context context) { } } + @Override + protected boolean setProperty(String key, Object param) { + if(TextUtils.equals(Name.FLAT, key)){ + getInstance().getFlatUIContext().setFlatUIEnabled(WXUtils.getBoolean(param, false)); + return true; + } + else { + return super.setProperty(key, param); + } + } + public int getLocationFromStart(){ return mLastLocationY; } @@ -127,4 +141,20 @@ public void recoverySticky() { mHeadView.setTranslationX(0); mHeadView.setTranslationY(0); } + + @Override + protected void mountFlatGUI() { + getHostView().mountFlatGUI(widgets); + } + + @Override + public void unmountFlatGUI() { + + } + + @Override + public boolean intendToBeFlatContainer() { + //TODO Is it possible to remove the cell class judge + return getInstance().getFlatUIContext().isFlatUIEnabled() && WXCell.class.equals(getClass()); + } } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXListComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXListComponent.java index ab53f78820..c5ef8b59f7 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXListComponent.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXListComponent.java @@ -19,6 +19,7 @@ package com.taobao.weex.ui.component.list; import android.content.Context; +import android.util.Pair; import com.taobao.weex.WXSDKInstance; import com.taobao.weex.annotation.Component; @@ -187,35 +188,31 @@ public void updateProperties(Map props) { @Override public void createChildViewAt(int index) { - int indexToCreate = index; - if (indexToCreate < 0) { - indexToCreate = childCount() - 1; - if (indexToCreate < 0) { - return; - } - } - final WXComponent child = getChild(indexToCreate); - if (child instanceof WXBaseRefresh) { - child.createView(); - if (child instanceof WXRefresh) { - getHostView().setOnRefreshListener((WXRefresh) child); - getHostView().postDelayed(new Runnable() { - @Override - public void run() { - getHostView().setHeaderView(child); - } - }, 100); - } else if (child instanceof WXLoading) { - getHostView().setOnLoadingListener((WXLoading) child); - getHostView().postDelayed(new Runnable() { - @Override - public void run() { - getHostView().setFooterView(child); - } - }, 100); + Pair ret = rearrangeIndexAndGetChild(index); + if(ret.first != null) { + final WXComponent child = getChild(ret.second); + if (child instanceof WXBaseRefresh) { + child.createView(); + if (child instanceof WXRefresh) { + getHostView().setOnRefreshListener((WXRefresh) child); + getHostView().postDelayed(new Runnable() { + @Override + public void run() { + getHostView().setHeaderView(child); + } + }, 100); + } else if (child instanceof WXLoading) { + getHostView().setOnLoadingListener((WXLoading) child); + getHostView().postDelayed(new Runnable() { + @Override + public void run() { + getHostView().setFooterView(child); + } + }, 100); + } + } else { + super.createChildViewAt(ret.second); } - } else { - super.createChildViewAt(indexToCreate); } } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatComponent.java new file mode 100644 index 0000000000..2c0cc46966 --- /dev/null +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatComponent.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.taobao.weex.ui.flat; + + +import android.support.annotation.NonNull; +import android.support.annotation.RestrictTo; +import android.support.annotation.RestrictTo.Scope; +import com.taobao.weex.ui.flat.widget.Widget; + +@RestrictTo(Scope.LIBRARY) +public interface FlatComponent { + + boolean promoteToView(boolean checkAncestor); + + @NonNull T getOrCreateFlatWidget(); +} diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java new file mode 100644 index 0000000000..1026730fd7 --- /dev/null +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java @@ -0,0 +1,113 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.taobao.weex.ui.flat; + + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.RestrictTo; +import android.support.annotation.RestrictTo.Scope; +import android.support.v4.util.ArrayMap; +import android.text.TextUtils; +import com.taobao.weex.common.Constants.Name; +import com.taobao.weex.dom.ImmutableDomObject; +import com.taobao.weex.dom.WXAttr; +import com.taobao.weex.dom.WXDomObject; +import com.taobao.weex.dom.WXStyle; +import com.taobao.weex.ui.component.WXComponent; +import com.taobao.weex.ui.flat.widget.AndroidViewWidget; +import java.util.Map; + +//TODO when Weex instance is destroyed, there is a work of garbage collection. +//TODO !!!!The index of weex playground show empty cell sometimes. +//TODO The constructor of FlatGUIContext should have a flag decide whether to enable flagGUI. + +@RestrictTo(Scope.LIBRARY) +public class FlatGUIIContext { + + private boolean mFlatUIEnabled; + private Map mWidgetRegistry = new ArrayMap<>(); + private Map mViewWidgetRegistry = new ArrayMap<>(); + + @RestrictTo(Scope.LIBRARY) + public void setFlatUIEnabled(boolean flag){ + mFlatUIEnabled = flag; + } + + public boolean isFlatUIEnabled() { + return mFlatUIEnabled; + } + + public void register(@NonNull WXComponent descendant, @NonNull WidgetContainer ancestor) { + if (!(ancestor instanceof FlatComponent) || + ((FlatComponent) ancestor).promoteToView(true)) { + mWidgetRegistry.put(descendant, ancestor); + } + } + + public void register(@NonNull WXComponent component, @NonNull AndroidViewWidget viewWidget){ + mViewWidgetRegistry.put(component, viewWidget); + } + + public + @Nullable + WidgetContainer getFlatComponentAncestor(@NonNull WXComponent flatWidget) { + return mWidgetRegistry.get(flatWidget); + } + + public + @Nullable + AndroidViewWidget getAndroidViewWidget(@NonNull WXComponent component) { + return mViewWidgetRegistry.get(component); + } + + public boolean promoteToView(@NonNull WXComponent component, boolean checkAncestor, + @NonNull Class> expectedClass) { + return !isFlatUIEnabled() || + !expectedClass.equals(component.getClass()) || + TextUtils.equals(component.getRef(), WXDomObject.ROOT) || + (checkAncestor && getFlatComponentAncestor(component) == null) || + checkComponent(component); + } + + private boolean checkComponent(@NonNull WXComponent component) { + boolean ret = false; + ImmutableDomObject domObject = component.getDomObject(); + if (domObject != null) { + WXStyle style = domObject.getStyles(); + WXAttr attr = domObject.getAttrs(); + //disabled && pro_fixed_size, attr or style + if (style.containsKey(Name.OPACITY) || + style.containsKey(Name.TRANSFORM) || + attr.containsKey(Name.ELEVATION) || + attr.containsKey(Name.ARIA_HIDDEN) || + attr.containsKey(Name.ARIA_LABEL) || + attr.containsKey(WXComponent.PROP_FIXED_SIZE) || + style.containsKey(Name.VISIBILITY) || + style.containsKey(Name.POSITION) || + attr.containsKey(Name.DISABLED) || + attr.containsKey(Name.PREVENT_MOVE_EVENT) || + !style.getPesudoStyles().isEmpty() || + domObject.getEvents().size() > 0) { + ret = true; + } + } + return ret; + } +} diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java new file mode 100644 index 0000000000..d501802a74 --- /dev/null +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java @@ -0,0 +1,92 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.taobao.weex.ui.flat; + + +import android.support.annotation.RestrictTo; +import android.support.annotation.RestrictTo.Scope; +import android.util.Pair; +import android.view.ViewGroup; +import com.taobao.weex.WXSDKInstance; +import com.taobao.weex.dom.WXDomObject; +import com.taobao.weex.ui.component.WXComponent; +import com.taobao.weex.ui.component.WXVContainer; +import com.taobao.weex.ui.flat.widget.AndroidViewWidget; +import com.taobao.weex.ui.flat.widget.Widget; +import java.util.LinkedList; +import java.util.List; + +@RestrictTo(Scope.LIBRARY) +public abstract class WidgetContainer extends WXVContainer { + + protected List widgets = new LinkedList<>(); + + public WidgetContainer(WXSDKInstance instance, WXDomObject node, WXVContainer parent) { + super(instance, node, parent); + } + + protected abstract void mountFlatGUI(); + + protected abstract void unmountFlatGUI(); + + public boolean intendToBeFlatContainer() { + return false; + } + + @Override + public void createChildViewAt(int index) { + if (intendToBeFlatContainer()) { + Pair ret = rearrangeIndexAndGetChild(index); + if (ret.first != null) { + WXComponent child = ret.first; + Widget flatChild; + FlatGUIIContext uiImp = getInstance().getFlatUIContext(); + WidgetContainer parent = uiImp.getFlatComponentAncestor(this); + if (parent == null || uiImp.getAndroidViewWidget(this) != null) { + parent = this; + } + uiImp.register(child, parent); + + if (child instanceof FlatComponent && !((FlatComponent) child).promoteToView(false)) { + flatChild = ((FlatComponent) child).getOrCreateFlatWidget(); + } else { + flatChild = new AndroidViewWidget(parent.getHostView()); + uiImp.register(child, (AndroidViewWidget) flatChild); + child.createView(); + ((AndroidViewWidget) flatChild).setContentView(child.getHostView()); + //TODO Use a sort algorithm to decide the childIndex of AndroidViewWidget + parent.addSubView(child.getHostView(), -1); + } + addFlatChild(flatChild, ret.second); + } + } else { + super.createChildViewAt(index); + } + } + + private void addFlatChild(Widget widget, int index) { + if (index >= widgets.size()) { + widgets.add(widget); + } else { + widgets.add(index, widget); + } + //TODO do a partial update, not mount the whole flatContainer. + mountFlatGUI(); + } +} diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java new file mode 100644 index 0000000000..c33c2a9a11 --- /dev/null +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java @@ -0,0 +1,58 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.taobao.weex.ui.flat.widget; + + +import android.graphics.Canvas; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.RestrictTo; +import android.support.annotation.RestrictTo.Scope; +import android.view.View; + +@RestrictTo(Scope.LIBRARY) +public class AndroidViewWidget extends BaseWidget { + + private @Nullable View mView; + public AndroidViewWidget(@NonNull View flatContainer) { + super(flatContainer); + } + + public void setContentView(@NonNull View view){ + this.mView = view; + } + + @Override + public void setContentBox(int leftOffset, int topOffset, int rightOffset, int bottomOffset) { + if(mView!=null) { + mView.setPadding(leftOffset, topOffset, rightOffset, bottomOffset); + } + } + + @Override + public void onDraw(@NonNull Canvas canvas) { + if(mView!=null) { + mView.draw(canvas); + } + } + + public @Nullable View getView() { + return mView; + } +} diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java new file mode 100644 index 0000000000..f0964d86e5 --- /dev/null +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java @@ -0,0 +1,146 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.taobao.weex.ui.flat.widget; + + +import android.graphics.Canvas; +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.RestrictTo; +import android.support.annotation.RestrictTo.Scope; +import android.view.View; +import com.taobao.weex.ui.view.border.BorderDrawable; + +@RestrictTo(Scope.LIBRARY) +abstract class BaseWidget implements Widget { + + //TODO Reconsider the field parameter in this class and the operation during draw(); Make a CPU/Memory balance. + //TODO use float to avoid 1px problem + private BorderDrawable backgroundBorder; + private int leftOffset, topOffset, rightOffset, bottomOffset; + private Rect borderBox = new Rect(); + private Point offsetOfContainer = new Point(); + private View flatContainer; + + BaseWidget(@NonNull View flatContainer){ + //TODO maybe FlatUIImp is better. + this.flatContainer = flatContainer; + } + + @Override + public void setLayout(int width, int height, int left, int right, int top, int bottom, Point offset) { + this.offsetOfContainer = offset; + borderBox.set(left, top, left + width, top + height); + if (backgroundBorder != null) { + setBackgroundAndBorder(backgroundBorder); + } + invalidate(); + } + + @Override + public void setContentBox(int leftOffset, int topOffset, int rightOffset, int bottomOffset) { + this.leftOffset = leftOffset; + this.topOffset = topOffset; + this.rightOffset = rightOffset; + this.bottomOffset = bottomOffset; + invalidate(); + } + + @Override + public void setBackgroundAndBorder(@NonNull BorderDrawable backgroundBorder) { + //TODO Change the code of BorderDrawable is more appropriate as it draws the borderLine from (0,0) not from getBounds + //TODO If the above is finished, no more traslate in draw in needed, only clip is enough. + this.backgroundBorder = backgroundBorder; + Rect backgroundBox = new Rect(borderBox); + backgroundBox.offset(-borderBox.left, -borderBox.top); + backgroundBorder.setBounds(backgroundBox); + setCallback(backgroundBorder); + invalidate(); + } + + @Override + public + @NonNull + Rect getBorderBox() { + return borderBox; + } + + @NonNull + @Override + public Point getLocInFlatContainer() { + return offsetOfContainer; + } + + @Nullable + @Override + public BorderDrawable getBackgroundAndBorder() { + return backgroundBorder; + } + + @Override + public int getLeftOffset() { + return leftOffset; + } + + @Override + public int getTopOffset() { + return topOffset; + } + + @Override + public int getRightOffset() { + return rightOffset; + } + + @Override + public int getBottomOffset() { + return bottomOffset; + } + + @Override + public final void draw(@NonNull Canvas canvas) { + canvas.save(); + canvas.clipRect(borderBox); + canvas.translate(borderBox.left, borderBox.top); + if (backgroundBorder != null) { + backgroundBorder.draw(canvas); + } + canvas.clipRect(leftOffset, topOffset, borderBox.width()-rightOffset, borderBox.height() - bottomOffset); + canvas.translate(leftOffset, topOffset); + onDraw(canvas); + canvas.restore(); + } + + @Override + public void invalidate() { + Rect dirtyRegion= new Rect(borderBox); + dirtyRegion.offset(offsetOfContainer.x, offsetOfContainer.y); + flatContainer.invalidate(dirtyRegion); + } + + protected void setCallback(@NonNull Drawable drawable){ + if(flatContainer!=null){ + drawable.setCallback(flatContainer); + } + } +} + diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/ImageWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/ImageWidget.java new file mode 100644 index 0000000000..5054119eb1 --- /dev/null +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/ImageWidget.java @@ -0,0 +1,102 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.taobao.weex.ui.flat.widget; + + +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.RestrictTo; +import android.support.annotation.RestrictTo.Scope; +import android.view.View; +import android.widget.ImageView.ScaleType; +import com.taobao.weex.adapter.IDrawableLoader.AnimatedTarget; +import com.taobao.weex.adapter.IDrawableLoader.StaticTarget; +import com.taobao.weex.ui.component.WXImage; +import com.taobao.weex.utils.ImageDrawable; +import java.util.Arrays; + +@RestrictTo(Scope.LIBRARY) +public class ImageWidget extends BaseWidget implements StaticTarget, AnimatedTarget { + + //TODO WXImage.src.readyToRender + //TODO blur + private Drawable mImageDrawable; + private ScaleType mScaleType = WXImage.DEFAULT_SCALE_TYPE; + private float[] borderRadius; + + public ImageWidget(@NonNull View flatContainer) { + super(flatContainer); + } + + @Override + public void onDraw(@NonNull Canvas canvas) { + if (mImageDrawable != null) { + mImageDrawable.draw(canvas); + } + } + + @Override + public void setAnimatedDrawable(@Nullable Drawable drawable) { + mImageDrawable = drawable; + initDrawable(); + } + + @Override + public void setDrawable(@Nullable Drawable drawable, boolean resetBounds) { + setDrawable(drawable); + } + + public void setDrawable(@Nullable Drawable imageDrawable) { + //As there is a translate operation in BaseWidget, + //width and height of the widget instead of borderBox should be passed to ImageDrawable. + mImageDrawable = ImageDrawable + .createImageDrawable(imageDrawable, mScaleType, null, + getBorderBox().width() - getLeftOffset() - getRightOffset(), + getBorderBox().height() - getTopOffset() - getBottomOffset(), false); + if (mImageDrawable instanceof ImageDrawable) { + if (!Arrays.equals(((ImageDrawable) mImageDrawable).getCornerRadii(), borderRadius)) { + ((ImageDrawable) mImageDrawable).setCornerRadii(borderRadius); + } + } + initDrawable(); + } + + public void setScaleType(ScaleType scaleType) { + this.mScaleType = scaleType; + setDrawable(mImageDrawable); + } + + public void setBorderRadius(float[] borderRadius) { + this.borderRadius = borderRadius; + } + + public @Nullable Drawable getDrawable(){ + return mImageDrawable; + } + + private void initDrawable(){ + if(mImageDrawable!=null) { + mImageDrawable.setBounds(0, 0, getBorderBox().width(), getBorderBox().height()); + setCallback(mImageDrawable); + invalidate(); + } + } +} diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java new file mode 100644 index 0000000000..992a01b861 --- /dev/null +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java @@ -0,0 +1,49 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.taobao.weex.ui.flat.widget; + + +import android.graphics.Canvas; +import android.support.annotation.NonNull; +import android.support.annotation.RestrictTo; +import android.support.annotation.RestrictTo.Scope; +import android.text.Layout; +import android.view.View; + +@RestrictTo(Scope.LIBRARY) +public class TextWidget extends BaseWidget { + + private Layout mLayout; + + public TextWidget(@NonNull View flatContainer) { + super(flatContainer); + } + + @Override + public void onDraw(@NonNull Canvas canvas) { + if (mLayout != null) { + mLayout.draw(canvas); + } + } + + public void updateTextDrawable(Layout layout) { + this.mLayout = layout; + invalidate(); + } +} diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java new file mode 100644 index 0000000000..0b4e7245ce --- /dev/null +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java @@ -0,0 +1,63 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.taobao.weex.ui.flat.widget; + + +import android.graphics.Canvas; +import android.graphics.Point; +import android.graphics.Rect; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.RestrictTo; +import android.support.annotation.RestrictTo.Scope; +import com.taobao.weex.ui.view.border.BorderDrawable; + +@RestrictTo(Scope.LIBRARY) +public interface Widget { + + public static final String TAG = "Widget"; + + void draw(@NonNull Canvas canvas); + + void onDraw(@NonNull Canvas canvas); + + void setBackgroundAndBorder(@NonNull BorderDrawable backgroundBorder); + + void setLayout(int width, int height, int left, int right, int top, int bottom, Point offset); + + void setContentBox(int leftOffset, int topOffset, int rightOffset, int bottomOffset); + + @NonNull Rect getBorderBox(); + + @Nullable + BorderDrawable getBackgroundAndBorder(); + + @NonNull Point getLocInFlatContainer(); + + int getLeftOffset(); + + int getTopOffset(); + + int getRightOffset(); + + int getBottomOffset(); + + void invalidate(); + +} diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java new file mode 100644 index 0000000000..297cd4eced --- /dev/null +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.taobao.weex.ui.flat.widget; + + +import android.graphics.Canvas; +import android.support.annotation.NonNull; +import android.support.annotation.RestrictTo; +import android.support.annotation.RestrictTo.Scope; +import android.view.View; +import java.util.LinkedList; +import java.util.List; + +@RestrictTo(Scope.LIBRARY) +public class WidgetGroup extends BaseWidget { + + private List mChildren = new LinkedList<>(); + + public WidgetGroup(@NonNull View flatContainer) { + super(flatContainer); + } + + public void replaceAll(@NonNull List widgets) { + mChildren = widgets; + invalidate(); + } + + @Override + public void onDraw(@NonNull Canvas canvas) { + for (Widget child : mChildren) { + child.draw(canvas); + } + } +} diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java index ec39462856..db9a8ec83e 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java @@ -20,27 +20,32 @@ import android.content.Context; import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.MotionEvent; import android.widget.FrameLayout; - import com.taobao.weex.ui.component.WXDiv; +import com.taobao.weex.ui.flat.widget.Widget; import com.taobao.weex.ui.view.gesture.WXGesture; import com.taobao.weex.ui.view.gesture.WXGestureObservable; import com.taobao.weex.utils.WXViewUtils; - import java.lang.ref.WeakReference; +import java.util.List; /** * FrameLayout wrapper * */ +//TODO Read the code of View.draw, and override the correct method. public class WXFrameLayout extends FrameLayout implements WXGestureObservable,IRenderStatus,IRenderResult { private WXGesture wxGesture; private WeakReference mWeakReference; + private List mWidgets; + public WXFrameLayout(Context context) { super(context); } @@ -59,12 +64,6 @@ public boolean onTouchEvent(MotionEvent event) { return result; } - @Override - protected void onDraw(Canvas canvas) { - WXViewUtils.clipCanvasWithinBorderBox(this, canvas); - super.onDraw(canvas); - } - @Override public void holdComponent(WXDiv component) { mWeakReference = new WeakReference(component); @@ -75,4 +74,39 @@ public void holdComponent(WXDiv component) { public WXDiv getComponent() { return null != mWeakReference ? mWeakReference.get() : null; } + + public void mountFlatGUI(List widgets){ + this.mWidgets = widgets; + if (mWidgets != null) { + setWillNotDraw(true); + } + invalidate(); + } + + public void unmountFlatGUI(){ + mWidgets = null; + setWillNotDraw(false); + invalidate(); + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return mWidgets != null || super.verifyDrawable(who); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (mWidgets != null) { + canvas.save(); + //TODO need clip here + canvas.translate(getPaddingLeft(), getPaddingTop()); + for (Widget widget : mWidgets) { + widget.draw(canvas); + } + canvas.restore(); + } else { + WXViewUtils.clipCanvasWithinBorderBox(this, canvas); + super.dispatchDraw(canvas); + } + } } From 878c3a9ea589cb77a87b9fd61d57aef8e089ddbe Mon Sep 17 00:00:00 2001 From: YorkShen Date: Fri, 25 Aug 2017 16:40:26 +0800 Subject: [PATCH 02/10] * [android] Update FlatGUI testcase --- .../taobao/weex/ui/component/WXDivTest.java | 12 +++++------- .../taobao/weex/ui/component/WXTextTest.java | 18 +++++++++--------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXDivTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXDivTest.java index 53b52c3624..3aa9674a6b 100644 --- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXDivTest.java +++ b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXDivTest.java @@ -18,6 +18,8 @@ */ package com.taobao.weex.ui.component; +import static org.junit.Assert.assertEquals; + import com.taobao.weappplus_sdk.BuildConfig; import com.taobao.weex.WXSDKInstance; import com.taobao.weex.WXSDKInstanceTest; @@ -25,21 +27,15 @@ import com.taobao.weex.dom.WXDomObject; import com.taobao.weex.dom.WXEvent; import com.taobao.weex.dom.flex.Spacing; - +import com.taobao.weex.ui.flat.FlatGUIIContext; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import static org.junit.Assert.*; - /** * Created by gulin on 16/2/24. */ @@ -65,6 +61,7 @@ public static WXDiv create(WXVContainer parent){ public void setUp() throws Exception { WXSDKInstance instance = Mockito.mock(WXSDKInstance.class); Mockito.when(instance.getContext()).thenReturn(RuntimeEnvironment.application); + Mockito.when(instance.getFlatUIContext()).thenReturn(new FlatGUIIContext()); WXDomObject divDom = new WXDomObject(); WXDomObject spy = Mockito.spy(divDom); @@ -80,6 +77,7 @@ public void setUp() throws Exception { public void testAddChild(){ WXSDKInstance instance = Mockito.mock(WXSDKInstance.class); Mockito.when(instance.getContext()).thenReturn(RuntimeEnvironment.application); + Mockito.when(instance.getFlatUIContext()).thenReturn(new FlatGUIIContext()); WXDomObject testDom = Mockito.mock(WXDomObject.class); Mockito.when(testDom.getPadding()).thenReturn(new Spacing()); diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXTextTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXTextTest.java index 0181457bbe..a12095e749 100644 --- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXTextTest.java +++ b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXTextTest.java @@ -18,6 +18,11 @@ */ package com.taobao.weex.ui.component; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import com.taobao.weappplus_sdk.BuildConfig; import com.taobao.weex.WXEnvironment; import com.taobao.weex.WXSDKInstance; @@ -27,7 +32,9 @@ import com.taobao.weex.dom.WXTextDomObject; import com.taobao.weex.dom.flex.Spacing; import com.taobao.weex.ui.SimpleComponentHolder; - +import com.taobao.weex.ui.flat.FlatGUIIContext; +import java.util.HashMap; +import java.util.Map; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -36,14 +43,6 @@ import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import java.util.HashMap; -import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - /** * Created by gulin on 16/2/4. */ @@ -60,6 +59,7 @@ public void setUp() throws Exception { WXEnvironment.sApplication = RuntimeEnvironment.application; WXSDKInstance instance = Mockito.mock(WXSDKInstance.class); Mockito.when(instance.getContext()).thenReturn(RuntimeEnvironment.application); + Mockito.when(instance.getFlatUIContext()).thenReturn(new FlatGUIIContext()); mParentDomObj = Mockito.spy(new WXDomObject()); Mockito.when(mParentDomObj.getPadding()).thenReturn(new Spacing()); From 23ca407a5e3acd010240e24c0911bfd732041ea8 Mon Sep 17 00:00:00 2001 From: YorkShen Date: Mon, 28 Aug 2017 15:11:17 +0800 Subject: [PATCH 03/10] * [android] Fix the problem of NPE and AndroidViewWidget's layout --- .../com/taobao/weex/ui/component/WXComponent.java | 12 ++++++++++-- .../java/com/taobao/weex/ui/component/WXDiv.java | 4 +++- .../com/taobao/weex/ui/component/list/WXCell.java | 4 +++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java index d18354463e..6f20d1dcd9 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java @@ -494,8 +494,16 @@ private void setComponentLayoutParams(int realWidth, int realHeight, int realLef private void setWidgetParams(Widget widget, FlatGUIIContext UIImp, Point rawoffset, int width, int height, int left, int right, int top, int bottom) { - Point childOffset = new Point(rawoffset.x, rawoffset.y); + Point childOffset = new Point(); if (mParent != null) { + if (mParent instanceof FlatComponent && + UIImp.getFlatComponentAncestor(mParent) != null && + UIImp.getAndroidViewWidget(mParent) == null) { + childOffset.set(rawoffset.x, rawoffset.y); + } else { + childOffset.set(left, top); + } + if (mParent instanceof FlatComponent && UIImp.getFlatComponentAncestor(mParent) != null && UIImp.getAndroidViewWidget(mParent) == null) { @@ -515,7 +523,7 @@ private void setWidgetParams(Widget widget, FlatGUIIContext UIImp, Point rawoffs } widget.setLayout(width, height, left, right, top, bottom, childOffset); - if (widget instanceof AndroidViewWidget) { + if (widget instanceof AndroidViewWidget && ((AndroidViewWidget) widget).getView()!=null) { //TODO generic method if ever possible setHostLayoutParams((T) ((AndroidViewWidget) widget).getView(), width, height, childOffset.x, right, childOffset.y, bottom); diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java index 18c734ed11..f533989c4b 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java @@ -90,7 +90,9 @@ public WidgetGroup getOrCreateFlatWidget() { @Override protected void mountFlatGUI() { if (promoteToView(true)) { - getHostView().mountFlatGUI(widgets); + if(getHostView()!=null) { + getHostView().mountFlatGUI(widgets); + } } else { mWidgetGroup.replaceAll(widgets); } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java index cac3048703..7981701897 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java @@ -144,7 +144,9 @@ public void recoverySticky() { @Override protected void mountFlatGUI() { + if(getHostView()!=null) { getHostView().mountFlatGUI(widgets); + } } @Override @@ -155,6 +157,6 @@ public void unmountFlatGUI() { @Override public boolean intendToBeFlatContainer() { //TODO Is it possible to remove the cell class judge - return getInstance().getFlatUIContext().isFlatUIEnabled() && WXCell.class.equals(getClass()); + return getInstance().getFlatUIContext().isFlatUIEnabled() && WXCell.class.equals(getClass()) && !isSticky(); } } From e225aaa76c36d885817bde72cb70259d864078e0 Mon Sep 17 00:00:00 2001 From: YorkShen Date: Fri, 1 Sep 2017 16:01:07 +0800 Subject: [PATCH 04/10] * [android] Make BaseWidget depend on FlatContext, not views. --- .../com/taobao/weex/ui/component/WXDiv.java | 2 +- .../com/taobao/weex/ui/component/WXText.java | 2 +- .../taobao/weex/ui/flat/FlatGUIIContext.java | 24 +++++++++++++++++++ .../taobao/weex/ui/flat/WidgetContainer.java | 3 ++- .../ui/flat/widget/AndroidViewWidget.java | 5 ++-- .../weex/ui/flat/widget/BaseWidget.java | 22 ++++++++++------- .../weex/ui/flat/widget/ImageWidget.java | 6 ++--- .../weex/ui/flat/widget/TextWidget.java | 6 ++--- .../weex/ui/flat/widget/WidgetGroup.java | 6 ++--- 9 files changed, 53 insertions(+), 23 deletions(-) diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java index f533989c4b..3080bbc677 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java @@ -78,7 +78,7 @@ public boolean promoteToView(boolean checkAncestor) { @NonNull public WidgetGroup getOrCreateFlatWidget() { if (mWidgetGroup == null) { - mWidgetGroup = new WidgetGroup(getInstance().getFlatUIContext().getFlatComponentAncestor(this).getHostView()); + mWidgetGroup = new WidgetGroup(getInstance().getFlatUIContext()); for (int i = 0; i < getChildCount(); i++) { createChildViewAt(i); } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXText.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXText.java index e07a0372d0..ea7b9ea030 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXText.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXText.java @@ -66,7 +66,7 @@ public boolean promoteToView(boolean checkAncestor) { @NonNull public TextWidget getOrCreateFlatWidget() { if (mTextWidget == null) { - mTextWidget = new TextWidget(getInstance().getFlatUIContext().getFlatComponentAncestor(this).getHostView()); + mTextWidget = new TextWidget(getInstance().getFlatUIContext()); } return mTextWidget; } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java index 1026730fd7..a5677b1bf8 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java @@ -25,6 +25,7 @@ import android.support.annotation.RestrictTo.Scope; import android.support.v4.util.ArrayMap; import android.text.TextUtils; +import android.view.View; import com.taobao.weex.common.Constants.Name; import com.taobao.weex.dom.ImmutableDomObject; import com.taobao.weex.dom.WXAttr; @@ -32,6 +33,7 @@ import com.taobao.weex.dom.WXStyle; import com.taobao.weex.ui.component.WXComponent; import com.taobao.weex.ui.flat.widget.AndroidViewWidget; +import com.taobao.weex.ui.flat.widget.Widget; import java.util.Map; //TODO when Weex instance is destroyed, there is a work of garbage collection. @@ -44,6 +46,7 @@ public class FlatGUIIContext { private boolean mFlatUIEnabled; private Map mWidgetRegistry = new ArrayMap<>(); private Map mViewWidgetRegistry = new ArrayMap<>(); + private Map widgetToComponent = new ArrayMap<>(); @RestrictTo(Scope.LIBRARY) public void setFlatUIEnabled(boolean flag){ @@ -65,6 +68,10 @@ public void register(@NonNull WXComponent component, @NonNull AndroidViewWidget mViewWidgetRegistry.put(component, viewWidget); } + public void register(@NonNull Widget widget, @NonNull WXComponent component){ + widgetToComponent.put(widget, component); + } + public @Nullable WidgetContainer getFlatComponentAncestor(@NonNull WXComponent flatWidget) { @@ -86,6 +93,23 @@ public boolean promoteToView(@NonNull WXComponent component, boolean checkAncest checkComponent(component); } + public + @Nullable + View getWidgetContainerView(Widget widget) { + WXComponent component, ancestor; + View ret = null; + if ((component = getComponent(widget)) != null) { + if ((ancestor = getFlatComponentAncestor(component)) != null) { + ret = ancestor.getHostView(); + } + } + return ret; + } + + private @Nullable WXComponent getComponent(@NonNull Widget widget){ + return widgetToComponent.get(widget); + } + private boolean checkComponent(@NonNull WXComponent component) { boolean ret = false; ImmutableDomObject domObject = component.getDomObject(); diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java index d501802a74..68e68a44d2 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java @@ -66,13 +66,14 @@ public void createChildViewAt(int index) { if (child instanceof FlatComponent && !((FlatComponent) child).promoteToView(false)) { flatChild = ((FlatComponent) child).getOrCreateFlatWidget(); } else { - flatChild = new AndroidViewWidget(parent.getHostView()); + flatChild = new AndroidViewWidget(uiImp); uiImp.register(child, (AndroidViewWidget) flatChild); child.createView(); ((AndroidViewWidget) flatChild).setContentView(child.getHostView()); //TODO Use a sort algorithm to decide the childIndex of AndroidViewWidget parent.addSubView(child.getHostView(), -1); } + uiImp.register(flatChild, child); addFlatChild(flatChild, ret.second); } } else { diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java index c33c2a9a11..8f1b873ff0 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java @@ -25,13 +25,14 @@ import android.support.annotation.RestrictTo; import android.support.annotation.RestrictTo.Scope; import android.view.View; +import com.taobao.weex.ui.flat.FlatGUIIContext; @RestrictTo(Scope.LIBRARY) public class AndroidViewWidget extends BaseWidget { private @Nullable View mView; - public AndroidViewWidget(@NonNull View flatContainer) { - super(flatContainer); + public AndroidViewWidget(@NonNull FlatGUIIContext context) { + super(context); } public void setContentView(@NonNull View view){ diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java index f0964d86e5..aba912f91b 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java @@ -28,6 +28,7 @@ import android.support.annotation.RestrictTo; import android.support.annotation.RestrictTo.Scope; import android.view.View; +import com.taobao.weex.ui.flat.FlatGUIIContext; import com.taobao.weex.ui.view.border.BorderDrawable; @RestrictTo(Scope.LIBRARY) @@ -39,11 +40,10 @@ abstract class BaseWidget implements Widget { private int leftOffset, topOffset, rightOffset, bottomOffset; private Rect borderBox = new Rect(); private Point offsetOfContainer = new Point(); - private View flatContainer; + private final @NonNull FlatGUIIContext context; - BaseWidget(@NonNull View flatContainer){ - //TODO maybe FlatUIImp is better. - this.flatContainer = flatContainer; + BaseWidget(@NonNull FlatGUIIContext context){ + this.context = context; } @Override @@ -132,14 +132,18 @@ public final void draw(@NonNull Canvas canvas) { @Override public void invalidate() { - Rect dirtyRegion= new Rect(borderBox); + Rect dirtyRegion = new Rect(borderBox); dirtyRegion.offset(offsetOfContainer.x, offsetOfContainer.y); - flatContainer.invalidate(dirtyRegion); + View widgetContainer; + if ((widgetContainer = context.getWidgetContainerView(this)) != null) { + widgetContainer.invalidate(dirtyRegion); + } } - protected void setCallback(@NonNull Drawable drawable){ - if(flatContainer!=null){ - drawable.setCallback(flatContainer); + protected void setCallback(@NonNull Drawable drawable) { + View widgetContainer; + if ((widgetContainer = context.getWidgetContainerView(this)) != null) { + drawable.setCallback(widgetContainer); } } } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/ImageWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/ImageWidget.java index 5054119eb1..db370db589 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/ImageWidget.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/ImageWidget.java @@ -25,11 +25,11 @@ import android.support.annotation.Nullable; import android.support.annotation.RestrictTo; import android.support.annotation.RestrictTo.Scope; -import android.view.View; import android.widget.ImageView.ScaleType; import com.taobao.weex.adapter.IDrawableLoader.AnimatedTarget; import com.taobao.weex.adapter.IDrawableLoader.StaticTarget; import com.taobao.weex.ui.component.WXImage; +import com.taobao.weex.ui.flat.FlatGUIIContext; import com.taobao.weex.utils.ImageDrawable; import java.util.Arrays; @@ -42,8 +42,8 @@ public class ImageWidget extends BaseWidget implements StaticTarget, AnimatedTar private ScaleType mScaleType = WXImage.DEFAULT_SCALE_TYPE; private float[] borderRadius; - public ImageWidget(@NonNull View flatContainer) { - super(flatContainer); + public ImageWidget(@NonNull FlatGUIIContext context) { + super(context); } @Override diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java index 992a01b861..afabc7b8da 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java @@ -24,15 +24,15 @@ import android.support.annotation.RestrictTo; import android.support.annotation.RestrictTo.Scope; import android.text.Layout; -import android.view.View; +import com.taobao.weex.ui.flat.FlatGUIIContext; @RestrictTo(Scope.LIBRARY) public class TextWidget extends BaseWidget { private Layout mLayout; - public TextWidget(@NonNull View flatContainer) { - super(flatContainer); + public TextWidget(@NonNull FlatGUIIContext context) { + super(context); } @Override diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java index 297cd4eced..433e133acf 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java @@ -23,7 +23,7 @@ import android.support.annotation.NonNull; import android.support.annotation.RestrictTo; import android.support.annotation.RestrictTo.Scope; -import android.view.View; +import com.taobao.weex.ui.flat.FlatGUIIContext; import java.util.LinkedList; import java.util.List; @@ -32,8 +32,8 @@ public class WidgetGroup extends BaseWidget { private List mChildren = new LinkedList<>(); - public WidgetGroup(@NonNull View flatContainer) { - super(flatContainer); + public WidgetGroup(@NonNull FlatGUIIContext context) { + super(context); } public void replaceAll(@NonNull List widgets) { From 58546e6d66dac82f5f8d7c3aefcaca5a682d7701 Mon Sep 17 00:00:00 2001 From: YorkShen Date: Mon, 4 Sep 2017 14:47:50 +0800 Subject: [PATCH 05/10] * [android] Make flat flag like lazy flag and enable it only if it's Android 4.4 or below. * [android] Fix LayoutParams in Nested Widget/Views. --- .../taobao/weex/ui/component/WXComponent.java | 13 ++++- .../com/taobao/weex/ui/component/WXDiv.java | 2 +- .../taobao/weex/ui/component/list/WXCell.java | 47 +++++++++++++------ .../taobao/weex/ui/flat/FlatGUIIContext.java | 17 +++---- 4 files changed, 50 insertions(+), 29 deletions(-) diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java index 6f20d1dcd9..c2313b2607 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java @@ -35,6 +35,8 @@ import android.support.annotation.IntDef; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.RestrictTo; +import android.support.annotation.RestrictTo.Scope; import android.support.v4.view.ViewCompat; import android.text.TextUtils; import android.view.Menu; @@ -68,8 +70,8 @@ import com.taobao.weex.ui.component.pesudo.PesudoStatus; import com.taobao.weex.ui.component.pesudo.TouchActivePseudoListener; import com.taobao.weex.ui.flat.FlatComponent; -import com.taobao.weex.ui.flat.WidgetContainer; import com.taobao.weex.ui.flat.FlatGUIIContext; +import com.taobao.weex.ui.flat.WidgetContainer; import com.taobao.weex.ui.flat.widget.AndroidViewWidget; import com.taobao.weex.ui.flat.widget.Widget; import com.taobao.weex.ui.view.border.BorderDrawable; @@ -147,6 +149,12 @@ public void postAnimation(WXAnimationModule.AnimationHolder holder) { this.mAnimationHolder = holder; } + //This method will be removed once flatGUI is completed. + @RestrictTo(Scope.LIBRARY) + public boolean isFlatUIEnabled(){ + return mParent != null && mParent.isFlatUIEnabled(); + } + private OnClickListener mClickEventListener = new OnClickListener() { @Override public void onHostViewClick() { @@ -500,7 +508,8 @@ private void setWidgetParams(Widget widget, FlatGUIIContext UIImp, Point rawoffs UIImp.getFlatComponentAncestor(mParent) != null && UIImp.getAndroidViewWidget(mParent) == null) { childOffset.set(rawoffset.x, rawoffset.y); - } else { + } + else{ childOffset.set(left, top); } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java index 3080bbc677..bdc98919d8 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java @@ -105,7 +105,7 @@ public void unmountFlatGUI() { @Override public boolean intendToBeFlatContainer() { - return getInstance().getFlatUIContext().isFlatUIEnabled() && WXDiv.class.equals(getClass()); + return getInstance().getFlatUIContext().isFlatUIEnabled(this) && WXDiv.class.equals(getClass()); } @Override diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java index 7981701897..bf575b5eb2 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java @@ -19,18 +19,23 @@ package com.taobao.weex.ui.component.list; import android.content.Context; +import android.os.Build; +import android.os.Build.VERSION_CODES; import android.support.annotation.NonNull; -import android.text.TextUtils; +import android.support.annotation.RestrictTo; +import android.support.annotation.RestrictTo.Scope; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import com.taobao.weex.WXSDKInstance; import com.taobao.weex.annotation.Component; import com.taobao.weex.common.Constants.Name; +import com.taobao.weex.dom.WXAttr; import com.taobao.weex.dom.WXDomObject; import com.taobao.weex.ui.component.WXVContainer; import com.taobao.weex.ui.flat.WidgetContainer; import com.taobao.weex.ui.view.WXFrameLayout; +import com.taobao.weex.utils.WXLogUtils; import com.taobao.weex.utils.WXUtils; /** @@ -48,7 +53,7 @@ public class WXCell extends WidgetContainer { /** used in list sticky detect **/ private int mScrollPositon = -1; - + private boolean mFlatUIEnabled = false; @Deprecated public WXCell(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, String instanceId, boolean isLazy) { @@ -57,6 +62,17 @@ public WXCell(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, Stri public WXCell(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, boolean isLazy) { super(instance, dom, parent); + if(Build.VERSION.SDK_INT< VERSION_CODES.LOLLIPOP) { + try { + //TODO a WTF is necessary if anyone try to change the flat flag during update attrs. + WXAttr attr = getDomObject().getAttrs(); + if (attr.containsKey(Name.FLAT)) { + mFlatUIEnabled = WXUtils.getBoolean(attr.get(Name.FLAT), false); + } + } catch (NullPointerException e) { + WXLogUtils.e("Cell", WXLogUtils.getStackTrace(e)); + } + } } @Override @@ -68,6 +84,12 @@ public void lazy(boolean lazy) { mLazy = lazy; } + @Override + @RestrictTo(Scope.LIBRARY) + public boolean isFlatUIEnabled() { + return mFlatUIEnabled; + } + /** * If Cell is Sticky, need wraped FrameLayout */ @@ -77,25 +99,21 @@ protected WXFrameLayout initComponentHostView(@NonNull Context context) { WXFrameLayout view = new WXFrameLayout(context); mRealView = new WXFrameLayout(context); view.addView(mRealView); + //TODO Maybe there is a better solution for hardware-acceleration view's display list. + if (isFlatUIEnabled()) { + view.setLayerType(View.LAYER_TYPE_HARDWARE, null); + } return view; } else { WXFrameLayout view = new WXFrameLayout(context); mRealView = view; + if (isFlatUIEnabled()) { + view.setLayerType(View.LAYER_TYPE_HARDWARE, null); + } return view; } } - @Override - protected boolean setProperty(String key, Object param) { - if(TextUtils.equals(Name.FLAT, key)){ - getInstance().getFlatUIContext().setFlatUIEnabled(WXUtils.getBoolean(param, false)); - return true; - } - else { - return super.setProperty(key, param); - } - } - public int getLocationFromStart(){ return mLastLocationY; } @@ -156,7 +174,6 @@ public void unmountFlatGUI() { @Override public boolean intendToBeFlatContainer() { - //TODO Is it possible to remove the cell class judge - return getInstance().getFlatUIContext().isFlatUIEnabled() && WXCell.class.equals(getClass()) && !isSticky(); + return getInstance().getFlatUIContext().isFlatUIEnabled(this) && WXCell.class.equals(getClass()) && !isSticky(); } } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java index a5677b1bf8..dde41182cb 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java @@ -43,18 +43,13 @@ @RestrictTo(Scope.LIBRARY) public class FlatGUIIContext { - private boolean mFlatUIEnabled; + private boolean mFlatUIEnabled = true; private Map mWidgetRegistry = new ArrayMap<>(); private Map mViewWidgetRegistry = new ArrayMap<>(); private Map widgetToComponent = new ArrayMap<>(); - @RestrictTo(Scope.LIBRARY) - public void setFlatUIEnabled(boolean flag){ - mFlatUIEnabled = flag; - } - - public boolean isFlatUIEnabled() { - return mFlatUIEnabled; + public boolean isFlatUIEnabled(WXComponent component) { + return mFlatUIEnabled && component.isFlatUIEnabled(); } public void register(@NonNull WXComponent descendant, @NonNull WidgetContainer ancestor) { @@ -86,7 +81,7 @@ AndroidViewWidget getAndroidViewWidget(@NonNull WXComponent component) { public boolean promoteToView(@NonNull WXComponent component, boolean checkAncestor, @NonNull Class> expectedClass) { - return !isFlatUIEnabled() || + return !isFlatUIEnabled(component) || !expectedClass.equals(component.getClass()) || TextUtils.equals(component.getRef(), WXDomObject.ROOT) || (checkAncestor && getFlatComponentAncestor(component) == null) || @@ -124,9 +119,9 @@ private boolean checkComponent(@NonNull WXComponent component) { attr.containsKey(Name.ARIA_LABEL) || attr.containsKey(WXComponent.PROP_FIXED_SIZE) || style.containsKey(Name.VISIBILITY) || - style.containsKey(Name.POSITION) || attr.containsKey(Name.DISABLED) || - attr.containsKey(Name.PREVENT_MOVE_EVENT) || + style.isFixed() || + style.isSticky() || !style.getPesudoStyles().isEmpty() || domObject.getEvents().size() > 0) { ret = true; From 60b6aad7ddda3d83f37c4d366dea00e6493d75b8 Mon Sep 17 00:00:00 2001 From: YorkShen Date: Fri, 8 Sep 2017 12:11:28 +0800 Subject: [PATCH 06/10] * [android] Remove useless method and TODOs, rename class. --- .../adapter/PicassoBasedDrawableLoader.java | 112 ------------------ .../java/com/alibaba/weex/WXApplication.java | 2 - .../java/com/taobao/weex/WXSDKInstance.java | 7 +- .../taobao/weex/adapter/DrawableStrategy.java | 5 - .../taobao/weex/common/WXImageStrategy.java | 8 +- .../taobao/weex/ui/component/WXComponent.java | 7 +- ...atGUIIContext.java => FlatGUIContext.java} | 8 +- .../taobao/weex/ui/flat/WidgetContainer.java | 2 +- .../ui/flat/widget/AndroidViewWidget.java | 4 +- .../weex/ui/flat/widget/BaseWidget.java | 45 +------ .../weex/ui/flat/widget/ImageWidget.java | 102 ---------------- .../weex/ui/flat/widget/TextWidget.java | 4 +- .../taobao/weex/ui/flat/widget/Widget.java | 17 --- .../weex/ui/flat/widget/WidgetGroup.java | 4 +- .../taobao/weex/ui/view/WXFrameLayout.java | 2 - .../taobao/weex/ui/component/WXDivTest.java | 6 +- .../taobao/weex/ui/component/WXTextTest.java | 4 +- 17 files changed, 28 insertions(+), 311 deletions(-) delete mode 100644 android/commons/src/main/java/com/alibaba/weex/commons/adapter/PicassoBasedDrawableLoader.java rename android/sdk/src/main/java/com/taobao/weex/ui/flat/{FlatGUIIContext.java => FlatGUIContext.java} (94%) delete mode 100644 android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/ImageWidget.java diff --git a/android/commons/src/main/java/com/alibaba/weex/commons/adapter/PicassoBasedDrawableLoader.java b/android/commons/src/main/java/com/alibaba/weex/commons/adapter/PicassoBasedDrawableLoader.java deleted file mode 100644 index 0d03934e58..0000000000 --- a/android/commons/src/main/java/com/alibaba/weex/commons/adapter/PicassoBasedDrawableLoader.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.alibaba.weex.commons.adapter; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.PixelFormat; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.view.Gravity; - -import com.squareup.picasso.Picasso; -import com.squareup.picasso.Target; -import com.taobao.weex.WXSDKManager; -import com.taobao.weex.adapter.DrawableStrategy; -import com.taobao.weex.adapter.IDrawableLoader; - - -public class PicassoBasedDrawableLoader implements IDrawableLoader { - - private Context mContext; - - public PicassoBasedDrawableLoader(Context context) { - mContext = context; - } - - @Override - public void setDrawable(final String url, - final DrawableTarget drawableTarget, - final DrawableStrategy drawableStrategy) { - WXSDKManager.getInstance().postOnUiThread(new Runnable() { - @Override - public void run() { - String temp = url; - if (url.startsWith("//")) { - temp = "http:" + url; - } - - /** This is a hack for picasso, as Picasso hold weakReference to Target. - * http://stackoverflow.com/questions/24180805/onbitmaploaded-of-target-object-not-called-on-first-load - */ - class PlaceHolderDrawableTarget extends Drawable implements Target { - - @Override - public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { - BitmapDrawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap); - bitmapDrawable.setGravity(Gravity.FILL); - if(drawableTarget instanceof StaticTarget) { - ((StaticTarget) drawableTarget).setDrawable(bitmapDrawable, true); - } - } - - @Override - public void onBitmapFailed(Drawable errorDrawable) { - - } - - @Override - public void onPrepareLoad(Drawable placeHolderDrawable) { - if(drawableTarget instanceof StaticTarget) { - ((StaticTarget) drawableTarget).setDrawable(this, true); - } - } - - @Override - public void draw(Canvas canvas) { - - } - - @Override - public void setAlpha(int alpha) { - - } - - @Override - public void setColorFilter(ColorFilter colorFilter) { - - } - - @Override - public int getOpacity() { - return PixelFormat.UNKNOWN; - } - } - Picasso. - with(mContext). - load(temp). - into(new PlaceHolderDrawableTarget()); - } - }, 0); - - } -} \ No newline at end of file diff --git a/android/playground/app/src/main/java/com/alibaba/weex/WXApplication.java b/android/playground/app/src/main/java/com/alibaba/weex/WXApplication.java index 584434137f..561d2921b4 100644 --- a/android/playground/app/src/main/java/com/alibaba/weex/WXApplication.java +++ b/android/playground/app/src/main/java/com/alibaba/weex/WXApplication.java @@ -25,7 +25,6 @@ import com.alibaba.weex.commons.adapter.DefaultWebSocketAdapterFactory; import com.alibaba.weex.commons.adapter.ImageAdapter; import com.alibaba.weex.commons.adapter.JSExceptionAdapter; -import com.alibaba.weex.commons.adapter.PicassoBasedDrawableLoader; import com.alibaba.weex.extend.PlayDebugAdapter; import com.alibaba.weex.extend.adapter.InterceptWXHttpAdapter; import com.alibaba.weex.extend.component.RichText; @@ -71,7 +70,6 @@ public void onCreate() { .setWebSocketAdapterFactory(new DefaultWebSocketAdapterFactory()) .setJSExceptionAdapter(new JSExceptionAdapter()) .setHttpAdapter(new InterceptWXHttpAdapter()) - .setDrawableLoader(new PicassoBasedDrawableLoader(this)) .build() ); diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java index a3ae67e505..93191a83c7 100644 --- a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java +++ b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java @@ -70,7 +70,7 @@ import com.taobao.weex.ui.component.WXBasicComponentType; import com.taobao.weex.ui.component.WXComponent; import com.taobao.weex.ui.component.WXComponentFactory; -import com.taobao.weex.ui.flat.FlatGUIIContext; +import com.taobao.weex.ui.flat.FlatGUIContext; import com.taobao.weex.ui.view.WXScrollView; import com.taobao.weex.ui.view.WXScrollView.WXScrollViewListener; import com.taobao.weex.utils.Trace; @@ -79,7 +79,6 @@ import com.taobao.weex.utils.WXLogUtils; import com.taobao.weex.utils.WXReflectionUtils; import com.taobao.weex.utils.WXViewUtils; -import com.taobao.weex.WXSDKEngine; import java.io.Serializable; import java.util.ArrayList; @@ -123,7 +122,7 @@ public class WXSDKInstance implements IWXActivityStateListener,DomContext, View. private static volatile int mViewPortWidth = 750; private int mInstanceViewPortWidth = 750; private final @NonNull - FlatGUIIContext mUIImp =new FlatGUIIContext(); + FlatGUIContext mUIImp =new FlatGUIContext(); public long mRenderStartNanos; public int mExecJSTraceId = WXTracing.nextId(); @@ -205,7 +204,7 @@ public void enableLayerType(boolean enable) { } public @NonNull - FlatGUIIContext getFlatUIContext(){ + FlatGUIContext getFlatUIContext(){ return mUIImp; } diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/DrawableStrategy.java b/android/sdk/src/main/java/com/taobao/weex/adapter/DrawableStrategy.java index 6c01aa81ff..c6daa5a3e2 100644 --- a/android/sdk/src/main/java/com/taobao/weex/adapter/DrawableStrategy.java +++ b/android/sdk/src/main/java/com/taobao/weex/adapter/DrawableStrategy.java @@ -20,13 +20,8 @@ package com.taobao.weex.adapter; -import com.taobao.weex.common.WXImageStrategy; -import com.taobao.weex.dom.WXImageQuality; - public class DrawableStrategy { public int width; public int height; - public WXImageStrategy imageStrategy; - public WXImageQuality imageQuality; } diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXImageStrategy.java b/android/sdk/src/main/java/com/taobao/weex/common/WXImageStrategy.java index de2572eebe..994c99bf2c 100644 --- a/android/sdk/src/main/java/com/taobao/weex/common/WXImageStrategy.java +++ b/android/sdk/src/main/java/com/taobao/weex/common/WXImageStrategy.java @@ -19,7 +19,7 @@ package com.taobao.weex.common; import android.widget.ImageView; -import com.taobao.weex.adapter.IDrawableLoader.DrawableTarget; + import java.util.Map; public class WXImageStrategy { @@ -58,12 +58,6 @@ public void setImageListener(ImageListener imageListener) { ImageListener imageListener; - WidgetListener widgetListener; - - public interface WidgetListener{ - public void onImageFinish(String url,DrawableTarget drawableTarget,boolean result,Map extra); - } - public interface ImageListener{ public void onImageFinish(String url,ImageView imageView,boolean result,Map extra); } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java index c2313b2607..3d9749d931 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java @@ -70,7 +70,7 @@ import com.taobao.weex.ui.component.pesudo.PesudoStatus; import com.taobao.weex.ui.component.pesudo.TouchActivePseudoListener; import com.taobao.weex.ui.flat.FlatComponent; -import com.taobao.weex.ui.flat.FlatGUIIContext; +import com.taobao.weex.ui.flat.FlatGUIContext; import com.taobao.weex.ui.flat.WidgetContainer; import com.taobao.weex.ui.flat.widget.AndroidViewWidget; import com.taobao.weex.ui.flat.widget.Widget; @@ -473,14 +473,13 @@ public final void setLayout(ImmutableDomObject domObject) { private void setComponentLayoutParams(int realWidth, int realHeight, int realLeft, int realTop, int realRight, int realBottom, Point rawOffset) { - FlatGUIIContext UIImp = getInstance().getFlatUIContext(); + FlatGUIContext UIImp = getInstance().getFlatUIContext(); WidgetContainer ancestor; Widget widget; if ((ancestor = UIImp.getFlatComponentAncestor(this)) != null) { if (this instanceof FlatComponent && !((FlatComponent) this).promoteToView(true)) { widget = ((FlatComponent) this).getOrCreateFlatWidget(); } else { - //TODO Be careful with nested hierarchy, such as widget, view, widget hierarchy. widget = UIImp.getAndroidViewWidget(this); } setWidgetParams(widget, UIImp, rawOffset, realWidth, realHeight, realLeft, realRight, realTop, @@ -500,7 +499,7 @@ private void setComponentLayoutParams(int realWidth, int realHeight, int realLef } } - private void setWidgetParams(Widget widget, FlatGUIIContext UIImp, Point rawoffset, + private void setWidgetParams(Widget widget, FlatGUIContext UIImp, Point rawoffset, int width, int height, int left, int right, int top, int bottom) { Point childOffset = new Point(); if (mParent != null) { diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIContext.java similarity index 94% rename from android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java rename to android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIContext.java index dde41182cb..e208f4ca54 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIContext.java @@ -37,19 +37,17 @@ import java.util.Map; //TODO when Weex instance is destroyed, there is a work of garbage collection. -//TODO !!!!The index of weex playground show empty cell sometimes. //TODO The constructor of FlatGUIContext should have a flag decide whether to enable flagGUI. @RestrictTo(Scope.LIBRARY) -public class FlatGUIIContext { +public class FlatGUIContext { - private boolean mFlatUIEnabled = true; private Map mWidgetRegistry = new ArrayMap<>(); private Map mViewWidgetRegistry = new ArrayMap<>(); private Map widgetToComponent = new ArrayMap<>(); public boolean isFlatUIEnabled(WXComponent component) { - return mFlatUIEnabled && component.isFlatUIEnabled(); + return component.isFlatUIEnabled(); } public void register(@NonNull WXComponent descendant, @NonNull WidgetContainer ancestor) { @@ -111,7 +109,7 @@ private boolean checkComponent(@NonNull WXComponent component) { if (domObject != null) { WXStyle style = domObject.getStyles(); WXAttr attr = domObject.getAttrs(); - //disabled && pro_fixed_size, attr or style + //TODO disabled && pro_fixed_size, attr or style if (style.containsKey(Name.OPACITY) || style.containsKey(Name.TRANSFORM) || attr.containsKey(Name.ELEVATION) || diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java index 68e68a44d2..f68aaeb089 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java @@ -56,7 +56,7 @@ public void createChildViewAt(int index) { if (ret.first != null) { WXComponent child = ret.first; Widget flatChild; - FlatGUIIContext uiImp = getInstance().getFlatUIContext(); + FlatGUIContext uiImp = getInstance().getFlatUIContext(); WidgetContainer parent = uiImp.getFlatComponentAncestor(this); if (parent == null || uiImp.getAndroidViewWidget(this) != null) { parent = this; diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java index 8f1b873ff0..b7968af878 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java @@ -25,13 +25,13 @@ import android.support.annotation.RestrictTo; import android.support.annotation.RestrictTo.Scope; import android.view.View; -import com.taobao.weex.ui.flat.FlatGUIIContext; +import com.taobao.weex.ui.flat.FlatGUIContext; @RestrictTo(Scope.LIBRARY) public class AndroidViewWidget extends BaseWidget { private @Nullable View mView; - public AndroidViewWidget(@NonNull FlatGUIIContext context) { + public AndroidViewWidget(@NonNull FlatGUIContext context) { super(context); } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java index aba912f91b..6e226be20c 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java @@ -24,11 +24,10 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.annotation.RestrictTo; import android.support.annotation.RestrictTo.Scope; import android.view.View; -import com.taobao.weex.ui.flat.FlatGUIIContext; +import com.taobao.weex.ui.flat.FlatGUIContext; import com.taobao.weex.ui.view.border.BorderDrawable; @RestrictTo(Scope.LIBRARY) @@ -40,9 +39,10 @@ abstract class BaseWidget implements Widget { private int leftOffset, topOffset, rightOffset, bottomOffset; private Rect borderBox = new Rect(); private Point offsetOfContainer = new Point(); - private final @NonNull FlatGUIIContext context; + private final @NonNull + FlatGUIContext context; - BaseWidget(@NonNull FlatGUIIContext context){ + BaseWidget(@NonNull FlatGUIContext context){ this.context = context; } @@ -77,48 +77,16 @@ public void setBackgroundAndBorder(@NonNull BorderDrawable backgroundBorder) { invalidate(); } - @Override - public - @NonNull - Rect getBorderBox() { - return borderBox; - } - @NonNull @Override public Point getLocInFlatContainer() { return offsetOfContainer; } - @Nullable - @Override - public BorderDrawable getBackgroundAndBorder() { - return backgroundBorder; - } - - @Override - public int getLeftOffset() { - return leftOffset; - } - - @Override - public int getTopOffset() { - return topOffset; - } - - @Override - public int getRightOffset() { - return rightOffset; - } - - @Override - public int getBottomOffset() { - return bottomOffset; - } - @Override public final void draw(@NonNull Canvas canvas) { canvas.save(); + //TODO clip according to path, not borderBox canvas.clipRect(borderBox); canvas.translate(borderBox.left, borderBox.top); if (backgroundBorder != null) { @@ -130,8 +98,7 @@ public final void draw(@NonNull Canvas canvas) { canvas.restore(); } - @Override - public void invalidate() { + protected void invalidate() { Rect dirtyRegion = new Rect(borderBox); dirtyRegion.offset(offsetOfContainer.x, offsetOfContainer.y); View widgetContainer; diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/ImageWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/ImageWidget.java deleted file mode 100644 index db370db589..0000000000 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/ImageWidget.java +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package com.taobao.weex.ui.flat.widget; - - -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.RestrictTo; -import android.support.annotation.RestrictTo.Scope; -import android.widget.ImageView.ScaleType; -import com.taobao.weex.adapter.IDrawableLoader.AnimatedTarget; -import com.taobao.weex.adapter.IDrawableLoader.StaticTarget; -import com.taobao.weex.ui.component.WXImage; -import com.taobao.weex.ui.flat.FlatGUIIContext; -import com.taobao.weex.utils.ImageDrawable; -import java.util.Arrays; - -@RestrictTo(Scope.LIBRARY) -public class ImageWidget extends BaseWidget implements StaticTarget, AnimatedTarget { - - //TODO WXImage.src.readyToRender - //TODO blur - private Drawable mImageDrawable; - private ScaleType mScaleType = WXImage.DEFAULT_SCALE_TYPE; - private float[] borderRadius; - - public ImageWidget(@NonNull FlatGUIIContext context) { - super(context); - } - - @Override - public void onDraw(@NonNull Canvas canvas) { - if (mImageDrawable != null) { - mImageDrawable.draw(canvas); - } - } - - @Override - public void setAnimatedDrawable(@Nullable Drawable drawable) { - mImageDrawable = drawable; - initDrawable(); - } - - @Override - public void setDrawable(@Nullable Drawable drawable, boolean resetBounds) { - setDrawable(drawable); - } - - public void setDrawable(@Nullable Drawable imageDrawable) { - //As there is a translate operation in BaseWidget, - //width and height of the widget instead of borderBox should be passed to ImageDrawable. - mImageDrawable = ImageDrawable - .createImageDrawable(imageDrawable, mScaleType, null, - getBorderBox().width() - getLeftOffset() - getRightOffset(), - getBorderBox().height() - getTopOffset() - getBottomOffset(), false); - if (mImageDrawable instanceof ImageDrawable) { - if (!Arrays.equals(((ImageDrawable) mImageDrawable).getCornerRadii(), borderRadius)) { - ((ImageDrawable) mImageDrawable).setCornerRadii(borderRadius); - } - } - initDrawable(); - } - - public void setScaleType(ScaleType scaleType) { - this.mScaleType = scaleType; - setDrawable(mImageDrawable); - } - - public void setBorderRadius(float[] borderRadius) { - this.borderRadius = borderRadius; - } - - public @Nullable Drawable getDrawable(){ - return mImageDrawable; - } - - private void initDrawable(){ - if(mImageDrawable!=null) { - mImageDrawable.setBounds(0, 0, getBorderBox().width(), getBorderBox().height()); - setCallback(mImageDrawable); - invalidate(); - } - } -} diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java index afabc7b8da..2a69b461c7 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java @@ -24,14 +24,14 @@ import android.support.annotation.RestrictTo; import android.support.annotation.RestrictTo.Scope; import android.text.Layout; -import com.taobao.weex.ui.flat.FlatGUIIContext; +import com.taobao.weex.ui.flat.FlatGUIContext; @RestrictTo(Scope.LIBRARY) public class TextWidget extends BaseWidget { private Layout mLayout; - public TextWidget(@NonNull FlatGUIIContext context) { + public TextWidget(@NonNull FlatGUIContext context) { super(context); } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java index 0b4e7245ce..7de3990738 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java @@ -21,9 +21,7 @@ import android.graphics.Canvas; import android.graphics.Point; -import android.graphics.Rect; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.annotation.RestrictTo; import android.support.annotation.RestrictTo.Scope; import com.taobao.weex.ui.view.border.BorderDrawable; @@ -43,21 +41,6 @@ public interface Widget { void setContentBox(int leftOffset, int topOffset, int rightOffset, int bottomOffset); - @NonNull Rect getBorderBox(); - - @Nullable - BorderDrawable getBackgroundAndBorder(); - @NonNull Point getLocInFlatContainer(); - int getLeftOffset(); - - int getTopOffset(); - - int getRightOffset(); - - int getBottomOffset(); - - void invalidate(); - } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java index 433e133acf..de8ed56747 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java @@ -23,7 +23,7 @@ import android.support.annotation.NonNull; import android.support.annotation.RestrictTo; import android.support.annotation.RestrictTo.Scope; -import com.taobao.weex.ui.flat.FlatGUIIContext; +import com.taobao.weex.ui.flat.FlatGUIContext; import java.util.LinkedList; import java.util.List; @@ -32,7 +32,7 @@ public class WidgetGroup extends BaseWidget { private List mChildren = new LinkedList<>(); - public WidgetGroup(@NonNull FlatGUIIContext context) { + public WidgetGroup(@NonNull FlatGUIContext context) { super(context); } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java index db9a8ec83e..4156de86e4 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java @@ -37,7 +37,6 @@ * FrameLayout wrapper * */ -//TODO Read the code of View.draw, and override the correct method. public class WXFrameLayout extends FrameLayout implements WXGestureObservable,IRenderStatus,IRenderResult { private WXGesture wxGesture; @@ -98,7 +97,6 @@ protected boolean verifyDrawable(@NonNull Drawable who) { protected void dispatchDraw(Canvas canvas) { if (mWidgets != null) { canvas.save(); - //TODO need clip here canvas.translate(getPaddingLeft(), getPaddingTop()); for (Widget widget : mWidgets) { widget.draw(canvas); diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXDivTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXDivTest.java index 3aa9674a6b..480d5a65ae 100644 --- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXDivTest.java +++ b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXDivTest.java @@ -27,7 +27,7 @@ import com.taobao.weex.dom.WXDomObject; import com.taobao.weex.dom.WXEvent; import com.taobao.weex.dom.flex.Spacing; -import com.taobao.weex.ui.flat.FlatGUIIContext; +import com.taobao.weex.ui.flat.FlatGUIContext; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -61,7 +61,7 @@ public static WXDiv create(WXVContainer parent){ public void setUp() throws Exception { WXSDKInstance instance = Mockito.mock(WXSDKInstance.class); Mockito.when(instance.getContext()).thenReturn(RuntimeEnvironment.application); - Mockito.when(instance.getFlatUIContext()).thenReturn(new FlatGUIIContext()); + Mockito.when(instance.getFlatUIContext()).thenReturn(new FlatGUIContext()); WXDomObject divDom = new WXDomObject(); WXDomObject spy = Mockito.spy(divDom); @@ -77,7 +77,7 @@ public void setUp() throws Exception { public void testAddChild(){ WXSDKInstance instance = Mockito.mock(WXSDKInstance.class); Mockito.when(instance.getContext()).thenReturn(RuntimeEnvironment.application); - Mockito.when(instance.getFlatUIContext()).thenReturn(new FlatGUIIContext()); + Mockito.when(instance.getFlatUIContext()).thenReturn(new FlatGUIContext()); WXDomObject testDom = Mockito.mock(WXDomObject.class); Mockito.when(testDom.getPadding()).thenReturn(new Spacing()); diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXTextTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXTextTest.java index a12095e749..3b6700f68e 100644 --- a/android/sdk/src/test/java/com/taobao/weex/ui/component/WXTextTest.java +++ b/android/sdk/src/test/java/com/taobao/weex/ui/component/WXTextTest.java @@ -32,7 +32,7 @@ import com.taobao.weex.dom.WXTextDomObject; import com.taobao.weex.dom.flex.Spacing; import com.taobao.weex.ui.SimpleComponentHolder; -import com.taobao.weex.ui.flat.FlatGUIIContext; +import com.taobao.weex.ui.flat.FlatGUIContext; import java.util.HashMap; import java.util.Map; import org.junit.Before; @@ -59,7 +59,7 @@ public void setUp() throws Exception { WXEnvironment.sApplication = RuntimeEnvironment.application; WXSDKInstance instance = Mockito.mock(WXSDKInstance.class); Mockito.when(instance.getContext()).thenReturn(RuntimeEnvironment.application); - Mockito.when(instance.getFlatUIContext()).thenReturn(new FlatGUIIContext()); + Mockito.when(instance.getFlatUIContext()).thenReturn(new FlatGUIContext()); mParentDomObj = Mockito.spy(new WXDomObject()); Mockito.when(mParentDomObj.getPadding()).thenReturn(new Spacing()); From 67ea39888a9299e05c5d2a145e950830f2134f53 Mon Sep 17 00:00:00 2001 From: YorkShen Date: Tue, 12 Sep 2017 11:38:34 +0800 Subject: [PATCH 07/10] * [android] Invalidate AndroidViewWidget and its corresponding view. --- .../taobao/weex/ui/flat/widget/AndroidViewWidget.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java index b7968af878..3edba743d0 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java @@ -35,7 +35,7 @@ public AndroidViewWidget(@NonNull FlatGUIContext context) { super(context); } - public void setContentView(@NonNull View view){ + public void setContentView(@Nullable View view){ this.mView = view; } @@ -43,6 +43,7 @@ public void setContentView(@NonNull View view){ public void setContentBox(int leftOffset, int topOffset, int rightOffset, int bottomOffset) { if(mView!=null) { mView.setPadding(leftOffset, topOffset, rightOffset, bottomOffset); + invalidate(); } } @@ -53,6 +54,14 @@ public void onDraw(@NonNull Canvas canvas) { } } + @Override + public void invalidate() { + super.invalidate(); + if (mView != null) { + mView.invalidate(); + } + } + public @Nullable View getView() { return mView; } From 94b4d41801b0388c58c82f2e2dd7e1b1a4fd5a6d Mon Sep 17 00:00:00 2001 From: YorkShen Date: Fri, 8 Sep 2017 11:42:33 +0800 Subject: [PATCH 08/10] + [android] Add garbage collection for FlatGUI. * [android] Fix the problem of WXSDKInstance.destroy() invoked twice if WXEmbed present. WXSDKInstance.destroy() will be called by WXSDKInstance.onActivityDestroy()->WXEmbed.onActivityDestroy() ->WXSDKInstance.onActivityDestroy() -> WXSDKInstance.destroy() and WXSDKInstance.onActivityDestroy() -> WXSDKInstance.destroy() -> WXEmbed.destroy() -> WXSDKInstance.destroy(). --- .../java/com/taobao/weex/WXSDKInstance.java | 68 ++++++++++--------- .../com/taobao/weex/ui/component/WXDiv.java | 4 +- .../taobao/weex/ui/component/list/WXCell.java | 4 +- .../taobao/weex/ui/flat/FlatGUIContext.java | 24 +++++-- .../ui/flat/widget/AndroidViewWidget.java | 10 ++- 5 files changed, 71 insertions(+), 39 deletions(-) diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java index 93191a83c7..69fc64962f 100644 --- a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java +++ b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java @@ -18,6 +18,8 @@ */ package com.taobao.weex; +import static com.taobao.weex.http.WXHttpUtil.KEY_USER_AGENT; + import android.app.AlertDialog; import android.content.Context; import android.content.Intent; @@ -36,7 +38,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ScrollView; - import com.alibaba.fastjson.JSONObject; import com.taobao.weex.adapter.IDrawableLoader; import com.taobao.weex.adapter.IWXHttpAdapter; @@ -79,7 +80,6 @@ import com.taobao.weex.utils.WXLogUtils; import com.taobao.weex.utils.WXReflectionUtils; import com.taobao.weex.utils.WXViewUtils; - import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; @@ -88,8 +88,6 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import static com.taobao.weex.http.WXHttpUtil.KEY_USER_AGENT; - /** * Each instance of WXSDKInstance represents an running weex instance. * It can be a pure weex view, or mixed with native view @@ -121,8 +119,8 @@ public class WXSDKInstance implements IWXActivityStateListener,DomContext, View. private boolean mNeedReLoad = false; private static volatile int mViewPortWidth = 750; private int mInstanceViewPortWidth = 750; - private final @NonNull - FlatGUIContext mUIImp =new FlatGUIContext(); + private @NonNull + FlatGUIContext mFlatGUIContext =new FlatGUIContext(); public long mRenderStartNanos; public int mExecJSTraceId = WXTracing.nextId(); @@ -203,9 +201,10 @@ public void enableLayerType(boolean enable) { enableLayerType = enable; } + @RestrictTo(Scope.LIBRARY) public @NonNull FlatGUIContext getFlatUIContext(){ - return mUIImp; + return mFlatGUIContext; } public boolean isNeedValidate() { @@ -1258,36 +1257,41 @@ private void destroyView(View rootView) { } public synchronized void destroy() { - WXSDKManager.getInstance().destroyInstance(mInstanceId); - WXComponentFactory.removeComponentTypesByInstanceId(getInstanceId()); + if(!isDestroy()) { + WXSDKManager.getInstance().destroyInstance(mInstanceId); + WXComponentFactory.removeComponentTypesByInstanceId(getInstanceId()); - if(mGlobalEventReceiver!=null){ - getContext().unregisterReceiver(mGlobalEventReceiver); - mGlobalEventReceiver=null; - } - if(mRootComp != null ) { - mRootComp.destroy(); - destroyView(mRenderContainer); - mRootComp = null; - } + if (mGlobalEventReceiver != null) { + getContext().unregisterReceiver(mGlobalEventReceiver); + mGlobalEventReceiver = null; + } + if (mRootComp != null) { + mRootComp.destroy(); + destroyView(mRenderContainer); + mRootComp = null; + } - if(mGlobalEvents!=null){ - mGlobalEvents.clear(); - } + if (mGlobalEvents != null) { + mGlobalEvents.clear(); + } - if(mComponentObserver != null){ + if (mComponentObserver != null) { mComponentObserver = null; + } + + getFlatUIContext().destroy(); + mFlatGUIContext = null; + + mWXScrollListeners = null; + mRenderContainer = null; + mNestedInstanceInterceptor = null; + mUserTrackAdapter = null; + mScrollView = null; + mContext = null; + mRenderListener = null; + isDestroy = true; + mStatisticsListener = null; } - - mWXScrollListeners = null; - mRenderContainer = null; - mNestedInstanceInterceptor = null; - mUserTrackAdapter = null; - mScrollView = null; - mContext = null; - mRenderListener = null; - isDestroy = true; - mStatisticsListener = null; } public boolean isDestroy(){ diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java index bdc98919d8..b9b97e1cc1 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java @@ -100,7 +100,9 @@ protected void mountFlatGUI() { @Override public void unmountFlatGUI() { - //TODO unmout must be called before you mount FlatGUI second times. + if (getHostView() != null) { + getHostView().unmountFlatGUI(); + } } @Override diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java index bf575b5eb2..6ba985f49c 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java @@ -169,7 +169,9 @@ protected void mountFlatGUI() { @Override public void unmountFlatGUI() { - + if (getHostView() != null) { + getHostView().unmountFlatGUI(); + } } @Override diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIContext.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIContext.java index e208f4ca54..4004bc840d 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIContext.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIContext.java @@ -27,6 +27,7 @@ import android.text.TextUtils; import android.view.View; import com.taobao.weex.common.Constants.Name; +import com.taobao.weex.common.Destroyable; import com.taobao.weex.dom.ImmutableDomObject; import com.taobao.weex.dom.WXAttr; import com.taobao.weex.dom.WXDomObject; @@ -35,12 +36,12 @@ import com.taobao.weex.ui.flat.widget.AndroidViewWidget; import com.taobao.weex.ui.flat.widget.Widget; import java.util.Map; +import java.util.Map.Entry; -//TODO when Weex instance is destroyed, there is a work of garbage collection. //TODO The constructor of FlatGUIContext should have a flag decide whether to enable flagGUI. @RestrictTo(Scope.LIBRARY) -public class FlatGUIContext { +public class FlatGUIContext implements Destroyable{ private Map mWidgetRegistry = new ArrayMap<>(); private Map mViewWidgetRegistry = new ArrayMap<>(); @@ -99,6 +100,22 @@ View getWidgetContainerView(Widget widget) { return ret; } + @Override + @RestrictTo(Scope.LIBRARY) + public void destroy(){ + widgetToComponent.clear(); + + for(Entry entry: mViewWidgetRegistry.entrySet()){ + entry.getValue().destroy(); + } + mViewWidgetRegistry.clear(); + + for(Entry entry:mWidgetRegistry.entrySet()){ + entry.getValue().unmountFlatGUI(); + } + mWidgetRegistry.clear(); + } + private @Nullable WXComponent getComponent(@NonNull Widget widget){ return widgetToComponent.get(widget); } @@ -109,14 +126,13 @@ private boolean checkComponent(@NonNull WXComponent component) { if (domObject != null) { WXStyle style = domObject.getStyles(); WXAttr attr = domObject.getAttrs(); - //TODO disabled && pro_fixed_size, attr or style if (style.containsKey(Name.OPACITY) || style.containsKey(Name.TRANSFORM) || + style.containsKey(Name.VISIBILITY) || attr.containsKey(Name.ELEVATION) || attr.containsKey(Name.ARIA_HIDDEN) || attr.containsKey(Name.ARIA_LABEL) || attr.containsKey(WXComponent.PROP_FIXED_SIZE) || - style.containsKey(Name.VISIBILITY) || attr.containsKey(Name.DISABLED) || style.isFixed() || style.isSticky() || diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java index 3edba743d0..0610a8ecf5 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java @@ -25,10 +25,11 @@ import android.support.annotation.RestrictTo; import android.support.annotation.RestrictTo.Scope; import android.view.View; +import com.taobao.weex.common.Destroyable; import com.taobao.weex.ui.flat.FlatGUIContext; @RestrictTo(Scope.LIBRARY) -public class AndroidViewWidget extends BaseWidget { +public class AndroidViewWidget extends BaseWidget implements Destroyable { private @Nullable View mView; public AndroidViewWidget(@NonNull FlatGUIContext context) { @@ -65,4 +66,11 @@ public void invalidate() { public @Nullable View getView() { return mView; } + + @Override + public void destroy() { + if (mView != null) { + mView = null; + } + } } From 942d03202500019d665e29401eb91ba345e8e871 Mon Sep 17 00:00:00 2001 From: YorkShen Date: Fri, 8 Sep 2017 11:43:41 +0800 Subject: [PATCH 09/10] * [android] Add try catch for FlatGUI --- .../taobao/weex/ui/view/WXFrameLayout.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java index 4156de86e4..28c7cef780 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java @@ -29,6 +29,7 @@ import com.taobao.weex.ui.flat.widget.Widget; import com.taobao.weex.ui.view.gesture.WXGesture; import com.taobao.weex.ui.view.gesture.WXGestureObservable; +import com.taobao.weex.utils.WXLogUtils; import com.taobao.weex.utils.WXViewUtils; import java.lang.ref.WeakReference; import java.util.List; @@ -95,16 +96,20 @@ protected boolean verifyDrawable(@NonNull Drawable who) { @Override protected void dispatchDraw(Canvas canvas) { - if (mWidgets != null) { - canvas.save(); - canvas.translate(getPaddingLeft(), getPaddingTop()); - for (Widget widget : mWidgets) { - widget.draw(canvas); + try { + if (mWidgets != null) { + canvas.save(); + canvas.translate(getPaddingLeft(), getPaddingTop()); + for (Widget widget : mWidgets) { + widget.draw(canvas); + } + canvas.restore(); + } else { + WXViewUtils.clipCanvasWithinBorderBox(this, canvas); + super.dispatchDraw(canvas); } - canvas.restore(); - } else { - WXViewUtils.clipCanvasWithinBorderBox(this, canvas); - super.dispatchDraw(canvas); + }catch (Throwable e){ + WXLogUtils.e("FlatGUI Crashed when dispatchDraw", WXLogUtils.getStackTrace(e)); } } } From f9019f4a89d6594e8d9241125077a1686a9f6519 Mon Sep 17 00:00:00 2001 From: YorkShen Date: Wed, 13 Sep 2017 16:59:52 +0800 Subject: [PATCH 10/10] * [android] Clip widget according to their border-radius. --- .../weex/ui/flat/widget/BaseWidget.java | 19 ++++++++++-- .../taobao/weex/ui/flat/widget/Widget.java | 5 +++ .../weex/ui/flat/widget/WidgetGroup.java | 4 +++ .../com/taobao/weex/utils/WXViewUtils.java | 31 +++++++++++++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java index 6e226be20c..02432dcefd 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java @@ -24,11 +24,13 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.annotation.RestrictTo; import android.support.annotation.RestrictTo.Scope; import android.view.View; import com.taobao.weex.ui.flat.FlatGUIContext; import com.taobao.weex.ui.view.border.BorderDrawable; +import com.taobao.weex.utils.WXViewUtils; @RestrictTo(Scope.LIBRARY) abstract class BaseWidget implements Widget { @@ -79,15 +81,26 @@ public void setBackgroundAndBorder(@NonNull BorderDrawable backgroundBorder) { @NonNull @Override - public Point getLocInFlatContainer() { + public final Point getLocInFlatContainer() { return offsetOfContainer; } + @Nullable + @Override + public final BorderDrawable getBackgroundAndBorder() { + return backgroundBorder; + } + + @NonNull + @Override + public final Rect getBorderBox() { + return borderBox; + } + @Override public final void draw(@NonNull Canvas canvas) { canvas.save(); - //TODO clip according to path, not borderBox - canvas.clipRect(borderBox); + WXViewUtils.clipCanvasWithinBorderBox(this, canvas); canvas.translate(borderBox.left, borderBox.top); if (backgroundBorder != null) { backgroundBorder.draw(canvas); diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java index 7de3990738..761d3b0872 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java @@ -21,7 +21,9 @@ import android.graphics.Canvas; import android.graphics.Point; +import android.graphics.Rect; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.annotation.RestrictTo; import android.support.annotation.RestrictTo.Scope; import com.taobao.weex.ui.view.border.BorderDrawable; @@ -43,4 +45,7 @@ public interface Widget { @NonNull Point getLocInFlatContainer(); + @Nullable BorderDrawable getBackgroundAndBorder(); + + @NonNull Rect getBorderBox(); } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java index de8ed56747..42ca263f9f 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java @@ -41,6 +41,10 @@ public void replaceAll(@NonNull List widgets) { invalidate(); } + public List getChildren() { + return mChildren; + } + @Override public void onDraw(@NonNull Canvas canvas) { for (Widget child : mChildren) { diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java index fb9ab8bcd6..7d11d5a2ac 100644 --- a/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java +++ b/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java @@ -40,6 +40,8 @@ import com.taobao.weex.WXSDKManager; import com.taobao.weex.common.Constants; import com.taobao.weex.common.WXRuntimeException; +import com.taobao.weex.ui.flat.widget.Widget; +import com.taobao.weex.ui.flat.widget.WidgetGroup; import com.taobao.weex.ui.view.border.BorderDrawable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -389,6 +391,22 @@ public static void clipCanvasWithinBorderBox(View targetView, Canvas canvas) { } } + public static void clipCanvasWithinBorderBox(Widget widget, Canvas canvas) { + BorderDrawable borderDrawable; + if (clipCanvasDueToAndroidVersion(canvas) && + clipCanvasIfAnimationExist() && + (borderDrawable=widget.getBackgroundAndBorder())!=null ) { + if (borderDrawable.isRounded() && clipCanvasIfBackgroundImageExist(widget, borderDrawable)) { + Path path = borderDrawable.getContentPath( + new RectF(0, 0, widget.getBorderBox().width(), widget.getBorderBox().height())); + canvas.clipPath(path); + } + else { + canvas.clipRect(widget.getBorderBox()); + } + } + } + /** * According to https://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported API 18 or higher supports clipPath to canvas based on hardware acceleration. @@ -436,4 +454,17 @@ private static boolean clipCanvasIfBackgroundImageExist(@NonNull View targetView } return true; } + + private static boolean clipCanvasIfBackgroundImageExist(@NonNull Widget widget, + @NonNull BorderDrawable borderDrawable) { + if (widget instanceof WidgetGroup) { + for (Widget child : ((WidgetGroup) widget).getChildren()) { + if (child.getBackgroundAndBorder().hasImage() && + Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + return false; + } + } + } + return true; + } }