diff options
author | Jens Ole Lauridsen <jlauridsen@google.com> | 2015-08-26 20:20:24 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2015-08-26 20:20:24 +0000 |
commit | 413d41aac4d573ad4f0270c0fefd94ef4e864225 (patch) | |
tree | e5bc545fc1dbea1b9e038b0668916e9d196e57d7 /tools/layoutlib | |
parent | 7a92c26e20734df4f48ae74def6689691ef2ce29 (diff) | |
parent | 67b73b60bf9c9f433ed282abdc3691ee0cc6dda0 (diff) | |
download | frameworks_base-413d41aac4d573ad4f0270c0fefd94ef4e864225.zip frameworks_base-413d41aac4d573ad4f0270c0fefd94ef4e864225.tar.gz frameworks_base-413d41aac4d573ad4f0270c0fefd94ef4e864225.tar.bz2 |
am 67b73b60: am cd4d5b3f: Support AppBar from Material Design. [DO NOT MERGE]
* commit '67b73b60bf9c9f433ed282abdc3691ee0cc6dda0':
Support AppBar from Material Design. [DO NOT MERGE]
Diffstat (limited to 'tools/layoutlib')
4 files changed, 182 insertions, 1 deletions
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java index b495e26..72d660c 100644 --- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java +++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java @@ -22,6 +22,7 @@ import com.android.ide.common.rendering.api.MergeCookie; import com.android.ide.common.rendering.api.ResourceReference; import com.android.ide.common.rendering.api.ResourceValue; import com.android.layoutlib.bridge.Bridge; +import com.android.layoutlib.bridge.BridgeConstants; import com.android.layoutlib.bridge.android.BridgeContext; import com.android.layoutlib.bridge.android.BridgeXmlBlockParser; import com.android.layoutlib.bridge.impl.ParserFactory; @@ -234,6 +235,13 @@ public final class BridgeInflater extends LayoutInflater { if (viewKey != null) { bc.addViewKey(view, viewKey); } + String scrollPos = attrs.getAttributeValue(BridgeConstants.NS_RESOURCES, "scrollY"); + if (scrollPos != null) { + if (scrollPos.endsWith("px")) { + int value = Integer.parseInt(scrollPos.substring(0, scrollPos.length() - 2)); + bc.setScrollYPos(view, value); + } + } } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 9de908e..7fff0e0 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -37,6 +37,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.annotation.Nullable; +import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; @@ -122,6 +123,7 @@ public final class BridgeContext extends Context { private final LayoutlibCallback mLayoutlibCallback; private final WindowManager mWindowManager; private final DisplayManager mDisplayManager; + private final HashMap<View, Integer> mScrollYPos = new HashMap<View, Integer>(); private Resources.Theme mTheme; @@ -1640,4 +1642,13 @@ public final class BridgeContext extends Context { // pass return new File[0]; } + + public void setScrollYPos(@NonNull View view, int scrollPos) { + mScrollYPos.put(view, scrollPos); + } + + public int getScrollYPos(@NonNull View view) { + Integer pos = mScrollYPos.get(view); + return pos != null ? pos : 0; + } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java new file mode 100644 index 0000000..0426907 --- /dev/null +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.layoutlib.bridge.android.support; + +import com.android.ide.common.rendering.api.LayoutLog; +import com.android.layoutlib.bridge.Bridge; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.view.View; + +import java.lang.reflect.Method; + +import static com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException; +import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod; +import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke; + +/** + * Utility class for working with the design support lib. + */ +public class DesignLibUtil { + + private static final String PKG_PREFIX = "android.support.design.widget."; + public static final String CN_COORDINATOR_LAYOUT = PKG_PREFIX + "CoordinatorLayout"; + public static final String CN_APPBAR_LAYOUT = PKG_PREFIX + "AppBarLayout"; + public static final String CN_COLLAPSING_TOOLBAR_LAYOUT = + PKG_PREFIX + "CollapsingToolbarLayout"; + public static final String CN_TOOLBAR = "android.support.v7.widget.Toolbar"; + public static final int SCROLL_AXIS_VERTICAL = 1 << 1; + + /** + * Tries to set the title of a view. This is used to set the title in a + * CollapsingToolbarLayout. + * <p/> + * Any exceptions thrown during the process are logged in {@link Bridge#getLog()} + */ + public static void setTitle(@NonNull View view, @Nullable String title) { + if (title == null) { + return; + } + try { + Method setTitle = getMethod(view.getClass(), "setTitle", CharSequence.class); + if (setTitle != null) { + invoke(setTitle, view, title); + } + } catch (ReflectionException e) { + Bridge.getLog().warning(LayoutLog.TAG_INFO, + "Error occurred while trying to set title.", e); + } + } +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index 3dec301..9ef5156 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -44,6 +44,7 @@ import com.android.layoutlib.bridge.android.BridgeContext; import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes; import com.android.layoutlib.bridge.android.BridgeXmlBlockParser; import com.android.layoutlib.bridge.android.RenderParamsFlags; +import com.android.layoutlib.bridge.android.support.DesignLibUtil; import com.android.layoutlib.bridge.android.support.RecyclerViewUtil; import com.android.layoutlib.bridge.bars.AppCompatActionBar; import com.android.layoutlib.bridge.bars.BridgeActionBar; @@ -148,7 +149,6 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { private int mTitleBarSize; private int mActionBarSize; - // information being returned through the API private BufferedImage mImage; private List<ViewInfo> mViewInfoList; @@ -424,6 +424,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { // post-inflate process. For now this supports TabHost/TabWidget postInflateProcess(view, params.getLayoutlibCallback(), isPreference ? view : null); + setActiveToolbar(view, context, params); + // get the background drawable if (mWindowBackground != null) { Drawable d = ResourceHelper.getDrawable(mWindowBackground, context); @@ -554,6 +556,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { // now do the layout. mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight); + handleScrolling(mViewRoot); + if (params.isLayoutOnly()) { // delete the canvas and image to reset them on the next full rendering mImage = null; @@ -1360,6 +1364,99 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { } /** + * If the root layout is a CoordinatorLayout with an AppBar: + * Set the title of the AppBar to the title of the activity context. + */ + private void setActiveToolbar(View view, BridgeContext context, SessionParams params) { + View coordinatorLayout = findChildView(view, DesignLibUtil.CN_COORDINATOR_LAYOUT); + if (coordinatorLayout == null) { + return; + } + View appBar = findChildView(coordinatorLayout, DesignLibUtil.CN_APPBAR_LAYOUT); + if (appBar == null) { + return; + } + ViewGroup collapsingToolbar = + (ViewGroup) findChildView(appBar, DesignLibUtil.CN_COLLAPSING_TOOLBAR_LAYOUT); + if (collapsingToolbar == null) { + return; + } + if (!hasToolbar(collapsingToolbar)) { + return; + } + RenderResources res = context.getRenderResources(); + String title = params.getAppLabel(); + ResourceValue titleValue = res.findResValue(title, false); + if (titleValue != null && titleValue.getValue() != null) { + title = titleValue.getValue(); + } + DesignLibUtil.setTitle(collapsingToolbar, title); + } + + private View findChildView(View view, String className) { + if (!(view instanceof ViewGroup)) { + return null; + } + ViewGroup group = (ViewGroup) view; + for (int i = 0; i < group.getChildCount(); i++) { + if (isInstanceOf(group.getChildAt(i), className)) { + return group.getChildAt(i); + } + } + return null; + } + + private boolean hasToolbar(View collapsingToolbar) { + if (!(collapsingToolbar instanceof ViewGroup)) { + return false; + } + ViewGroup group = (ViewGroup) collapsingToolbar; + for (int i = 0; i < group.getChildCount(); i++) { + if (isInstanceOf(group.getChildAt(i), DesignLibUtil.CN_TOOLBAR)) { + return true; + } + } + return false; + } + + /** + * Set the vertical scroll position on all the components with the "scrollY" attribute. If the + * component supports nested scrolling attempt that first, then use the unconsumed scroll part + * to scroll the content in the component. + */ + private void handleScrolling(View view) { + BridgeContext context = getContext(); + int scrollPos = context.getScrollYPos(view); + if (scrollPos != 0) { + if (view.isNestedScrollingEnabled()) { + int[] consumed = new int[2]; + if (view.startNestedScroll(DesignLibUtil.SCROLL_AXIS_VERTICAL)) { + view.dispatchNestedPreScroll(0, scrollPos, consumed, null); + view.dispatchNestedScroll(consumed[0], consumed[1], 0, scrollPos, null); + view.stopNestedScroll(); + scrollPos -= consumed[1]; + } + } + if (scrollPos != 0) { + view.scrollBy(0, scrollPos); + } else { + view.scrollBy(0, scrollPos); + } + } else { + view.scrollBy(0, scrollPos); + } + + if (!(view instanceof ViewGroup)) { + return; + } + ViewGroup group = (ViewGroup) view; + for (int i = 0; i < group.getChildCount(); i++) { + View child = group.getChildAt(i); + handleScrolling(child); + } + } + + /** * Check if the object is an instance of a class named {@code className}. This doesn't work * for interfaces. */ |