You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by ky...@apache.org on 2017/09/13 09:41:26 UTC

[02/12] incubator-weex git commit: * [android] Init commit for flatGUI

* [android] Init commit for flatGUI


Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/bc6ea406
Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/bc6ea406
Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/bc6ea406

Branch: refs/heads/0.16-dev
Commit: bc6ea406e05667712f7084b268bb16f81c2298fd
Parents: 701c4b9
Author: YorkShen <sh...@gmail.com>
Authored: Tue Aug 22 11:37:04 2017 +0800
Committer: YorkShen <sh...@gmail.com>
Committed: Wed Sep 13 16:54:07 2017 +0800

----------------------------------------------------------------------
 .../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 +
 .../java/com/taobao/weex/common/Constants.java  |   2 +
 .../com/taobao/weex/common/WXImageStrategy.java |   8 +-
 .../com/taobao/weex/dom/ImmutableDomObject.java |  21 ++-
 .../taobao/weex/ui/component/WXComponent.java   | 127 +++++++++++-----
 .../com/taobao/weex/ui/component/WXDiv.java     |  70 ++++++++-
 .../com/taobao/weex/ui/component/WXSlider.java  |   4 +-
 .../com/taobao/weex/ui/component/WXText.java    |  65 +++++----
 .../taobao/weex/ui/component/WXVContainer.java  |  44 ++++--
 .../taobao/weex/ui/component/list/WXCell.java   |  38 ++++-
 .../weex/ui/component/list/WXListComponent.java |  53 ++++---
 .../com/taobao/weex/ui/flat/FlatComponent.java  |  33 +++++
 .../taobao/weex/ui/flat/FlatGUIIContext.java    | 113 ++++++++++++++
 .../taobao/weex/ui/flat/WidgetContainer.java    |  92 ++++++++++++
 .../weex/ui/flat/widget/AndroidViewWidget.java  |  58 ++++++++
 .../taobao/weex/ui/flat/widget/BaseWidget.java  | 146 +++++++++++++++++++
 .../taobao/weex/ui/flat/widget/ImageWidget.java | 102 +++++++++++++
 .../taobao/weex/ui/flat/widget/TextWidget.java  |  49 +++++++
 .../com/taobao/weex/ui/flat/widget/Widget.java  |  63 ++++++++
 .../taobao/weex/ui/flat/widget/WidgetGroup.java |  50 +++++++
 .../com/taobao/weex/ui/view/WXFrameLayout.java  |  50 ++++++-
 25 files changed, 1202 insertions(+), 146 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/commons/src/main/java/com/alibaba/weex/commons/adapter/PicassoBasedDrawableLoader.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 0000000..0d03934
--- /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

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/playground/app/src/androidTest/java/com/alibaba/weex/benchmark/BenchmarkTest.java
----------------------------------------------------------------------
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 dddada7..2c5f8e7 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.UiObject2;
 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.ArrayList;
 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<Long> firstScreenRenderTime = new LinkedList<>();
   private static List<Long> flingFrameSeconds = new LinkedList<>();
   private static List<Long> 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 @@ public class BenchmarkTest {
 
   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;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/playground/app/src/main/java/com/alibaba/weex/WXApplication.java
----------------------------------------------------------------------
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 561d292..5844341 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 android.os.Bundle;
 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 class WXApplication extends Application {
                                .setWebSocketAdapterFactory(new DefaultWebSocketAdapterFactory())
                                .setJSExceptionAdapter(new JSExceptionAdapter())
                                .setHttpAdapter(new InterceptWXHttpAdapter())
+                               .setDrawableLoader(new PicassoBasedDrawableLoader(this))
                                .build()
                           );
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
----------------------------------------------------------------------
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 d1bbd52..a3ae67e 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.net.Uri;
 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.NestedContainer;
 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 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
@@ -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 class WXSDKInstance implements IWXActivityStateListener,DomContext, View.
     enableLayerType = enable;
   }
 
+  public @NonNull
+  FlatGUIIContext getFlatUIContext(){
+    return mUIImp;
+  }
+
   public boolean isNeedValidate() {
     return mNeedValidate;
   }
@@ -251,6 +260,7 @@ public class WXSDKInstance implements IWXActivityStateListener,DomContext, View.
   /**
    * For unittest only.
    */
+  @RestrictTo(Scope.TESTS)
   WXSDKInstance(Context context,String id) {
     mInstanceId = id;
     init(context);

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/adapter/DrawableStrategy.java
----------------------------------------------------------------------
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 c6daa5a..6c01aa8 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;
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
----------------------------------------------------------------------
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 06fb668..4be1f28 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 class Constants {
     String ARIA_LABEL = "ariaLabel";
     String ARIA_HIDDEN = "ariaHidden";
     String UNDEFINED = "undefined";
+
+    String FLAT = "flat";
   }
 
   public interface Value {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/common/WXImageStrategy.java
----------------------------------------------------------------------
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 994c99b..de2572e 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 class WXImageStrategy {
 
   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);
   }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/dom/ImmutableDomObject.java
----------------------------------------------------------------------
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 55439c3..c19ca59 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();

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
----------------------------------------------------------------------
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 dd7e470..d183544 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.annotation.TargetApi;
 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.text.TextUtils;
 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.animation.WXAnimationModule;
 import com.taobao.weex.ui.component.pesudo.OnActivePseudoListner;
 import com.taobao.weex.ui.component.pesudo.PesudoStatus;
 import com.taobao.weex.ui.component.pesudo.TouchActivePseudoListener;
+import com.taobao.weex.ui.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.WXReflectionUtils;
 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 abstract class  WXComponent<T extends View> implements IWXObject, IWXActi
 
   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 abstract class  WXComponent<T extends View> implements IWXObject, IWXActi
                          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 abstract class  WXComponent<T extends View> implements IWXObject, IWXActi
       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 @@ public abstract class  WXComponent<T extends View> implements IWXObject, IWXActi
     }
   }
 
+  public int getLayoutTopOffsetForSibling(){
+    return 0;
+  }
+
   public float getLayoutWidth(){
     float w = 0f;
     if (mDomObj != null) {
@@ -537,10 +590,11 @@ public abstract class  WXComponent<T extends View> implements IWXObject, IWXActi
     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 abstract class  WXComponent<T extends View> implements IWXObject, IWXActi
       }
     }
     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 @@ public abstract class  WXComponent<T extends View> implements IWXObject, IWXActi
         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 abstract class  WXComponent<T extends View> implements IWXObject, IWXActi
   }
 
   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);

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/component/WXDiv.java
----------------------------------------------------------------------
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 2772cc6..18c734e 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 @@ package com.taobao.weex.ui.component;
 
 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<WXFrameLayout> {
+public class WXDiv extends WidgetContainer<WXFrameLayout> implements FlatComponent<WidgetGroup> {
+
+  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);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSlider.java
----------------------------------------------------------------------
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 4ef51f3..1023e3e 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.View;
 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.ui.view.gesture.WXGestureType;
 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 @@ public class WXSlider extends WXVContainer<FrameLayout> {
    */
   @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 {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/component/WXText.java
----------------------------------------------------------------------
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 aad2bf4..e07a037 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.annotation.Component;
 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 @@ import java.lang.reflect.InvocationTargetException;
  * Text component
  */
 @Component(lazyload = false)
-public class WXText extends WXComponent<WXTextView> {
+public class WXText extends WXComponent<WXTextView> implements FlatComponent<TextWidget> {
+
+  private TextWidget mTextWidget;
 
   /**
    * The default text size
@@ -53,6 +57,25 @@ public class WXText extends WXComponent<WXTextView> {
   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 @@ public class WXText extends WXComponent<WXTextView> {
 
   @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 @@ public class WXText extends WXComponent<WXTextView> {
     }
   }
 
-  /**
-   * 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) {
@@ -161,6 +165,13 @@ public class WXText extends WXComponent<WXTextView> {
   }
 
   @Override
+  protected void createViewImpl() {
+    if(promoteToView(true)) {
+      super.createViewImpl();
+    }
+  }
+
+  @Override
   public void destroy() {
     super.destroy();
     if (WXEnvironment.getApplication() != null && mTypefaceObserver != null) {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
----------------------------------------------------------------------
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 f769c2a..43b45a7 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 abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
    *
    */
   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 abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
     return original;
   }
 
+  /**
+   * Use {@link #getChildCount()} instead
+   * @return
+   */
+  @Deprecated
   public int childCount() {
     return mChildren == null ? 0 : mChildren.size();
   }
@@ -242,7 +250,7 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
   }
 
   public int getChildCount() {
-    return mChildren.size();
+    return childCount();
   }
 
   public void addChild(WXComponent child) {
@@ -268,21 +276,31 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
     return mChildren.indexOf(comp);
   }
 
-  public void createChildViewAt(int index){
+  public void createChildViewAt(int index) {
     long startNanos = System.nanoTime();
+    Pair<WXComponent, Integer> 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<WXComponent, Integer> 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) {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java
----------------------------------------------------------------------
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 3095c04..cac3048 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 @@ package com.taobao.weex.ui.component.list;
 
 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<WXFrameLayout> {
+public class WXCell extends WidgetContainer<WXFrameLayout> {
 
     private int mLastLocationY = 0;
     private ViewGroup mRealView;
@@ -49,11 +52,11 @@ public class WXCell extends WXVContainer<WXFrameLayout> {
 
     @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 @@ public class WXCell extends WXVContainer<WXFrameLayout> {
         }
     }
 
+    @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 class WXCell extends WXVContainer<WXFrameLayout> {
         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());
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXListComponent.java
----------------------------------------------------------------------
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 ab53f78..c5ef8b5 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 class WXListComponent extends BasicListComponent<BounceRecyclerView> {
 
   @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<WXComponent, Integer> 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);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatComponent.java
----------------------------------------------------------------------
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 0000000..2c0cc46
--- /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<T extends Widget> {
+
+  boolean promoteToView(boolean checkAncestor);
+
+  @NonNull T getOrCreateFlatWidget();
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/flat/FlatGUIIContext.java
----------------------------------------------------------------------
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 0000000..1026730
--- /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<WXComponent, WidgetContainer> mWidgetRegistry = new ArrayMap<>();
+  private Map<WXComponent, AndroidViewWidget> 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<? extends WXComponent<?>> 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;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/flat/WidgetContainer.java
----------------------------------------------------------------------
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 0000000..d501802
--- /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<T extends ViewGroup> extends WXVContainer<T> {
+
+  protected List<Widget> 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<WXComponent, Integer> 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();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/AndroidViewWidget.java
----------------------------------------------------------------------
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 0000000..c33c2a9
--- /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;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/BaseWidget.java
----------------------------------------------------------------------
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 0000000..f0964d8
--- /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);
+    }
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/ImageWidget.java
----------------------------------------------------------------------
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 0000000..5054119
--- /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();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/TextWidget.java
----------------------------------------------------------------------
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 0000000..992a01b
--- /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();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/Widget.java
----------------------------------------------------------------------
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 0000000..0b4e724
--- /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();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/flat/widget/WidgetGroup.java
----------------------------------------------------------------------
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 0000000..297cd4e
--- /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<Widget> mChildren = new LinkedList<>();
+
+  public WidgetGroup(@NonNull View flatContainer) {
+    super(flatContainer);
+  }
+
+  public void replaceAll(@NonNull List<Widget> widgets) {
+    mChildren = widgets;
+    invalidate();
+  }
+
+  @Override
+  public void onDraw(@NonNull Canvas canvas) {
+    for (Widget child : mChildren) {
+      child.draw(canvas);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/bc6ea406/android/sdk/src/main/java/com/taobao/weex/ui/view/WXFrameLayout.java
----------------------------------------------------------------------
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 ec39462..db9a8ec 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 @@ package com.taobao.weex.ui.view;
 
 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<WXDiv>,IRenderResult<WXDiv> {
 
   private WXGesture wxGesture;
 
   private WeakReference<WXDiv> mWeakReference;
 
+  private List<Widget> mWidgets;
+
   public WXFrameLayout(Context context) {
     super(context);
   }
@@ -60,12 +65,6 @@ public class WXFrameLayout extends FrameLayout implements WXGestureObservable,IR
   }
 
   @Override
-  protected void onDraw(Canvas canvas) {
-    WXViewUtils.clipCanvasWithinBorderBox(this, canvas);
-    super.onDraw(canvas);
-  }
-
-  @Override
   public void holdComponent(WXDiv component) {
     mWeakReference = new WeakReference<WXDiv>(component);
   }
@@ -75,4 +74,39 @@ public class WXFrameLayout extends FrameLayout implements WXGestureObservable,IR
   public WXDiv getComponent() {
     return null != mWeakReference ? mWeakReference.get() : null;
   }
+
+  public void mountFlatGUI(List<Widget> 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);
+    }
+  }
 }