diff --git a/renderer/native/android/src/main/cpp/src/renderer/native_render_manager.cc b/renderer/native/android/src/main/cpp/src/renderer/native_render_manager.cc index f00a79290ad..91057b551b1 100644 --- a/renderer/native/android/src/main/cpp/src/renderer/native_render_manager.cc +++ b/renderer/native/android/src/main/cpp/src/renderer/native_render_manager.cc @@ -42,7 +42,6 @@ constexpr char kHeight[] = "height"; constexpr char kLeft[] = "left"; constexpr char kTop[] = "top"; constexpr char kProps[] = "props"; -constexpr char kMeasureNode[] = "Text"; constexpr char kDeleteProps[] = "deleteProps"; constexpr char kFontStyle[] = "fontStyle"; constexpr char kLetterSpacing[] = "letterSpacing"; @@ -73,6 +72,10 @@ namespace hippy { inline namespace render { inline namespace native { +static bool IsMeasureNode(const std::string &name) { + return name == "Text" || name == "TextInput"; +} + std::atomic NativeRenderManager::unique_native_render_manager_id_{1}; footstone::utils::PersistentObjectMap> NativeRenderManager::persistent_map_; @@ -112,7 +115,7 @@ void NativeRenderManager::CreateRenderNode(std::weak_ptr root_node, dom_node[kIndex] = footstone::value::HippyValue(render_info.index); dom_node[kName] = footstone::value::HippyValue(nodes[i]->GetViewName()); - if (nodes[i]->GetViewName() == kMeasureNode) { + if (IsMeasureNode(nodes[i]->GetViewName())) { int32_t id = footstone::check::checked_numeric_cast(nodes[i]->GetId()); MeasureFunction measure_function = [WEAK_THIS, root_id, id](float width, LayoutMeasureMode width_measure_mode, float height, LayoutMeasureMode height_measure_mode, @@ -329,7 +332,7 @@ void NativeRenderManager::UpdateLayout(std::weak_ptr root_node, dom_node[kHeight] = footstone::value::HippyValue(DpToPx(result.height)); dom_node[kLeft] = footstone::value::HippyValue(DpToPx(result.left)); dom_node[kTop] = footstone::value::HippyValue(DpToPx(result.top)); - if (nodes[i]->GetViewName() == kMeasureNode) { + if (IsMeasureNode(nodes[i]->GetViewName())) { dom_node["paddingLeft"] = footstone::value::HippyValue(DpToPx(result.paddingLeft)); dom_node["paddingTop"] = footstone::value::HippyValue(DpToPx(result.paddingTop)); dom_node["paddingRight"] = footstone::value::HippyValue(DpToPx(result.paddingRight)); diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/dom/node/NodeProps.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/dom/node/NodeProps.java index 7bdaea851fc..9c7b24dd62f 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/dom/node/NodeProps.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/dom/node/NodeProps.java @@ -137,9 +137,9 @@ public class NodeProps { public static final String VIEW_CLASS_NAME = "View"; public static final String TEXT_CLASS_NAME = "Text"; public static final String IMAGE_CLASS_NAME = "Image"; + public static final String TEXT_INPUT_CLASS_NAME = "TextInput"; public static final String IMAGE_SPAN_TEXT = "[img]"; - public static final String STYLE = "style"; public static final String PROPS = "props"; public static final String ROOT_NODE = "RootNode"; public static final String CUSTOM_PROP = "customProp"; diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java index f99d85fcf63..41ae371ee2d 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java @@ -125,7 +125,8 @@ void findViewPropsMethod(Class cls, private void invokePropMethod(@NonNull Object obj, @NonNull Object arg1, Map props, String key, @NonNull PropertyMethodHolder methodHolder) { try { - if (props.get(key) == null) { + Object value = props.get(key); + if (value == null) { switch (methodHolder.defaultType) { case HippyControllerProps.BOOLEAN: methodHolder.method.invoke(obj, arg1, methodHolder.defaultBoolean); @@ -147,7 +148,6 @@ private void invokePropMethod(@NonNull Object obj, @NonNull Object arg1, break; } } else { - Object value = props.get(key); if (methodHolder.paramTypes == null) { methodHolder.paramTypes = methodHolder.method.getGenericParameterTypes(); } diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java b/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java index 28264f50091..0d13b16a34d 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java @@ -737,8 +737,9 @@ public void exec() { public long measure(int rootId, int nodeId, float width, int widthMode, float height, int heightMode) { try { - FlexMeasureMode flexMeasureMode = FlexMeasureMode.fromInt(widthMode); - return mVirtualNodeManager.measure(rootId, nodeId, width, flexMeasureMode); + FlexMeasureMode wm = FlexMeasureMode.fromInt(widthMode); + FlexMeasureMode hm = FlexMeasureMode.fromInt(heightMode); + return mVirtualNodeManager.measure(rootId, nodeId, width, wm, height, hm); } catch (NativeRenderException e) { handleRenderException(e); } diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/node/ImageVirtualNode.java b/renderer/native/android/src/main/java/com/tencent/renderer/node/ImageVirtualNode.java index ad2cb288ddc..3c2cd3e91bd 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/node/ImageVirtualNode.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/node/ImageVirtualNode.java @@ -92,10 +92,12 @@ protected TextImageSpan createImageSpan() { if (mDefaultSource != null && imageLoader != null) { ImageDataSupplier supplier = imageLoader.fetchImageSync(mDefaultSource, null, mWidth, mHeight); - Bitmap bitmap = supplier.getBitmap(); - if (bitmap != null) { - Resources resources = ContextHolder.getAppContext().getResources(); - drawable = new BitmapDrawable(resources, bitmap); + if (supplier != null) { + Bitmap bitmap = supplier.getBitmap(); + if (bitmap != null) { + Resources resources = ContextHolder.getAppContext().getResources(); + drawable = new BitmapDrawable(resources, bitmap); + } } } if (drawable == null) { diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/node/TextInputVirtualNode.java b/renderer/native/android/src/main/java/com/tencent/renderer/node/TextInputVirtualNode.java new file mode 100644 index 00000000000..5cd3eaaae59 --- /dev/null +++ b/renderer/native/android/src/main/java/com/tencent/renderer/node/TextInputVirtualNode.java @@ -0,0 +1,86 @@ +/* Tencent is pleased to support the open source community by making Hippy available. + * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. + * + * 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.tencent.renderer.node; + +import android.text.SpannableStringBuilder; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; + +import androidx.annotation.NonNull; +import com.tencent.mtt.hippy.annotation.HippyControllerProps; +import com.tencent.mtt.hippy.dom.node.NodeProps; +import com.tencent.mtt.hippy.utils.ContextHolder; +import com.tencent.mtt.hippy.utils.PixelUtil; +import com.tencent.renderer.utils.FlexUtils; +import com.tencent.renderer.utils.FlexUtils.FlexMeasureMode; +import java.util.List; + +public class TextInputVirtualNode extends VirtualNode { + + protected long mMeasureSize = 0; + protected int mNumberOfLines = 0; + protected int mFontSize = (int) Math.ceil(PixelUtil.dp2px(NodeProps.FONT_SIZE_SP)); + @NonNull + private final EditText mEditText; + + public TextInputVirtualNode(int rootId, int id, int pid, int index) { + super(rootId, id, pid, index); + mEditText = new EditText(ContextHolder.getAppContext()); + mEditText.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + } + + protected void createSpanOperation(List ops, + SpannableStringBuilder builder, boolean useChild) { + // Need do nothing by default + } + + @SuppressWarnings("unused") + @HippyControllerProps(name = NodeProps.NUMBER_OF_LINES, defaultType = HippyControllerProps.NUMBER) + public void setNumberOfLines(int numberOfLines) { + mNumberOfLines = numberOfLines; + } + + @SuppressWarnings("unused") + @HippyControllerProps(name = NodeProps.FONT_SIZE, defaultType = HippyControllerProps.NUMBER, + defaultNumber = NodeProps.FONT_SIZE_SP) + public void setFontSize(float size) { + mFontSize = (int) Math.ceil(PixelUtil.dp2px(size)); + } + + private int getMeasureSpec(float size, FlexMeasureMode mode) { + switch (mode) { + case EXACTLY: + return View.MeasureSpec.makeMeasureSpec((int) size, View.MeasureSpec.EXACTLY); + case AT_MOST: + return View.MeasureSpec.makeMeasureSpec((int) size, View.MeasureSpec.AT_MOST); + default: + return View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + } + } + + public long measure(float width, FlexMeasureMode widthMode, float height, FlexMeasureMode heightMode) { + mEditText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mFontSize); + if (mNumberOfLines > 0) { + mEditText.setLines(mNumberOfLines); + } + mEditText.measure(getMeasureSpec(width, widthMode), getMeasureSpec(height, heightMode)); + return FlexUtils.makeSizeToLong(mEditText.getMeasuredWidth(), mEditText.getMeasuredHeight()); + } +} diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/node/VirtualNodeManager.java b/renderer/native/android/src/main/java/com/tencent/renderer/node/VirtualNodeManager.java index f2bea6a9fa3..7380a9a2d06 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/node/VirtualNodeManager.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/node/VirtualNodeManager.java @@ -22,6 +22,7 @@ import static com.tencent.mtt.hippy.dom.node.NodeProps.PADDING_RIGHT; import static com.tencent.mtt.hippy.dom.node.NodeProps.PADDING_TOP; import static com.tencent.mtt.hippy.dom.node.NodeProps.TEXT_CLASS_NAME; +import static com.tencent.mtt.hippy.dom.node.NodeProps.TEXT_INPUT_CLASS_NAME; import static com.tencent.renderer.NativeRenderException.ExceptionCode.INVALID_MEASURE_STATE_ERR; import static com.tencent.renderer.NativeRenderer.NODE_ID; import static com.tencent.renderer.NativeRenderer.NODE_INDEX; @@ -32,7 +33,6 @@ import androidx.annotation.Nullable; import com.tencent.mtt.hippy.annotation.HippyControllerProps; -import com.tencent.mtt.hippy.dom.node.NodeProps; import com.tencent.mtt.hippy.utils.LogUtils; import com.tencent.renderer.NativeRender; import com.tencent.renderer.NativeRenderException; @@ -101,7 +101,7 @@ public VirtualNode checkVirtualParent(int rootId, int nodeId) { */ public boolean updateEventListener(int rootId, int nodeId, @NonNull Map props) { VirtualNode node = getVirtualNode(rootId, nodeId); - if (node == null) { + if (node == null || node instanceof TextInputVirtualNode) { return false; } boolean isChanged = false; @@ -169,9 +169,13 @@ public TextRenderSupplier updateLayout(int rootId, int nodeId, float width, rightPadding, bottomPadding); } - public long measure(int rootId, int nodeId, float width, FlexMeasureMode widthMode) + public long measure(int rootId, int nodeId, float width, FlexMeasureMode widthMode, + float height, FlexMeasureMode heightMode) throws NativeRenderException { VirtualNode node = getVirtualNode(rootId, nodeId); + if (node instanceof TextInputVirtualNode) { + return ((TextInputVirtualNode) node).measure(width, widthMode, height, heightMode); + } if (!(node instanceof TextVirtualNode) || node.mParent != null) { throw new NativeRenderException(INVALID_MEASURE_STATE_ERR, TAG + ": measure: encounter wrong state when check node, " @@ -215,15 +219,10 @@ private void findPropertyMethod(Class nodeClass, @SuppressWarnings("rawtypes") private void invokePropertyMethod(@NonNull VirtualNode node, @NonNull Map props, - @NonNull String key, @Nullable PropertyMethodHolder methodHolder) { - if (methodHolder == null) { - if (key.equals(NodeProps.STYLE) && (props.get(key) instanceof Map)) { - updateProps(node, (Map) props.get(key)); - } - return; - } + @NonNull String key, @NonNull PropertyMethodHolder methodHolder) { try { - if (props.get(key) == null) { + Object value = props.get(key); + if (value == null) { switch (methodHolder.defaultType) { case HippyControllerProps.BOOLEAN: methodHolder.method.invoke(node, methodHolder.defaultBoolean); @@ -248,7 +247,7 @@ private void invokePropertyMethod(@NonNull VirtualNode node, @NonNull Map props, } } else { methodHolder.method.invoke(node, - PropertyUtils.convertProperty(methodHolder.paramTypes[0], props.get(key))); + PropertyUtils.convertProperty(methodHolder.paramTypes[0], value)); } } catch (Exception exception) { mNativeRenderer.handleRenderException( @@ -271,7 +270,9 @@ private void updateProps(@NonNull VirtualNode node, @Nullable Map keySet = props.keySet(); for (String key : keySet) { PropertyMethodHolder methodHolder = methodMap.get(key); - invokePropertyMethod(node, props, key, methodHolder); + if (methodHolder != null) { + invokePropertyMethod(node, props, key, methodHolder); + } } } @@ -281,7 +282,7 @@ private VirtualNode createVirtualNode(int rootId, int id, int pid, int index, VirtualNode node = mNativeRenderer.createVirtualNode(rootId, id, pid, index, className, props); VirtualNode parent = getVirtualNode(rootId, pid); - // Only text or text child need to create virtual node. + // Only text、text child and text input need to create virtual node. if (className.equals(TEXT_CLASS_NAME)) { if (!(node instanceof TextVirtualNode)) { node = new TextVirtualNode(rootId, id, pid, index, mNativeRenderer); @@ -290,6 +291,10 @@ private VirtualNode createVirtualNode(int rootId, int id, int pid, int index, if (!(node instanceof ImageVirtualNode)) { node = new ImageVirtualNode(rootId, id, pid, index, mNativeRenderer); } + } else if (className.equals(TEXT_INPUT_CLASS_NAME)) { + if (!(node instanceof TextInputVirtualNode)) { + node = new TextInputVirtualNode(rootId, id, pid, index); + } } return node; } @@ -331,6 +336,11 @@ public void updateNode(int rootId, int id, @Nullable Map diffPro } } updateProps(node, propsToUpdate); + // The text input node is only used for measurement purposes and does not + // require any layout updates + if (node instanceof TextInputVirtualNode) { + return; + } // add the top VirtualNode to mUpdateNodes while (node.mParent != null) { node = node.mParent; @@ -374,7 +384,7 @@ public void moveNode(int rootId, @NonNull VirtualNode parent, @NonNull List findResetStyles(@Nullable Map fromProps, - @Nullable Map toProps) { - Map diffStyles = null; - Map fromStyle = - (fromProps != null) ? (Map) fromProps.get(NodeProps.STYLE) : null; - if (fromStyle == null) { - return null; - } - Map toStyle = (toProps != null) ? (Map) toProps.get(NodeProps.STYLE) : null; - Set styleKeys = fromStyle.keySet(); - for (String styleKey : styleKeys) { - if (toStyle == null || !toStyle.containsKey(styleKey)) { - if (diffStyles == null) { - diffStyles = new HashMap<>(); - } - diffStyles.put(styleKey, null); - } - } - return diffStyles; - } - /** * Find the attribute that exists in the from node but does not exist in the to node. * @@ -79,18 +54,9 @@ public static Map findResetProps(@Nullable Map f return null; } Map diffProps = null; - Map diffStyles; Set fromKeys = fromProps.keySet(); try { - diffStyles = findResetStyles(fromProps, toProps); - if (diffStyles != null) { - diffProps = new HashMap<>(); - diffProps.put(NodeProps.STYLE, diffStyles); - } for (String fromKey : fromKeys) { - if (fromKey.equals(NodeProps.STYLE)) { - continue; - } if (toProps == null || !toProps.containsKey(fromKey)) { if (diffProps == null) { diffProps = new HashMap<>(); @@ -162,9 +128,6 @@ private static void diffProperty(@NonNull String fromKey, @Nullable Object fromV if (diffResult.isEmpty()) { return; } - } else if (diffLevel == 0 && fromKey.equals(NodeProps.STYLE)) { - diffResult = diffMap((Map) fromValue, new HashMap(), - diffLevel + 1, controllerManager, componentProps); } updateProps.put(fromKey, diffResult); }