Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(android): text input support lineHeight #3936

Merged
merged 1 commit into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/api/hippy-react/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ import icon from './qb_icon_new.png';
| keyboardType | 决定弹出的何种软键盘的。 注意,`password`仅在属性 `multiline=false` 单行文本框时生效。 | `enum (default, numeric, password, email, phone-pad)` | `Android、iOS、hippy-react-web、Web-Renderer、Voltron` |
| maxLength | 限制文本框中最多的字符数。使用这个属性而不用JS 逻辑去实现,可以避免闪烁的现象。 | `number` | `Android、iOS、hippy-react-web、Web-Renderer、Voltron` |
| multiline | 如果为 `true` ,文本框中可以输入多行文字。 由于终端特性。 | `boolean` | `Android、iOS、hippy-react-web、Web-Renderer、Voltron` |
| lineSpacingExtra | 多行显示时每行文字的额外行高,如果style里设置的lineHeight属性该属性设置无效 | `number` | `Android` |
| lineSpacingMultiplier | 多行显示时每行文字的行高乘积系数,如果style里设置的lineHeight属性该属性设置无效 | `number` | `Android` |
| numberOfLines | 设置 `TextInput` 最大显示行数,如果 `TextInput` 没有显式设置高度,会根据 `numberOfLines` 来计算高度撑开。在使用的时候必需同时设置 `multiline` 参数为 `true`。 | `number` | `Android、hippy-react-web、Web-Renderer、Voltron` |
| onBlur | 当文本框失去焦点的时候调用此回调函数。 | `Function` | `Android、iOS、hippy-react-web、Web-Renderer、Voltron` |
| onFocus | 当文本框获得焦点的时候调用此回调函数。 | `Function` | `Android、iOS、Voltron` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@ const styles = StyleSheet.create({
fontSize: 16,
color: '#242424',
height: 30,
// you can use lineHeight/lineSpacing/lineHeightMultiple
// to control the space between lines in multi-line input.(iOS only for now)
// you can use lineHeight
// to control the space between lines in multi-line input.
// for example:
lineHeight: 30,
// lineSpacing: 50,
// lineHeightMultiple: 1.5,
},
input_style_block: {
height: 100,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package com.tencent.mtt.hippy.views.textinput;

import static com.tencent.mtt.hippy.views.textinput.HippyTextInputController.UNSET;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.BlendMode;
Expand Down Expand Up @@ -83,10 +85,15 @@ public class HippyTextInput extends AppCompatEditText implements HippyViewBase,
private final ViewTreeObserver.OnGlobalLayoutListener mKeyboardEventObserver = this::checkSendKeyboardEvent;
private boolean mIsKeyBoardShow = false; //键盘是否在显示
private boolean mIsKeyBoardShowBySelf = false;
private boolean mShouldUpdateTypeface = false;
private boolean mShouldUpdateLineHeight = false;
private int mListenerFlag = 0;
private ReactContentSizeWatcher mReactContentSizeWatcher = null;
private boolean mItalic = false;
private int mFontWeight = TypeFaceUtil.WEIGHT_NORMAL;
private float mLineSpacingMultiplier = 1.0f;
private float mLineSpacingExtra = 0.0f;
private int mLineHeight = 0;
@Nullable
private String mFontFamily;
private Paint mTextPaint;
Expand Down Expand Up @@ -177,6 +184,48 @@ void setGravityVertical(int gravityVertical) {
setGravity((getGravity() & ~Gravity.VERTICAL_GRAVITY_MASK) | gravityVertical);
}

public void setLineSpacingMultiplier(float spacingMultiplier) {
if (Float.compare(spacingMultiplier, mLineSpacingMultiplier) != 0) {
mLineSpacingMultiplier = spacingMultiplier;
mShouldUpdateLineHeight = true;
}
}

public void setLineSpacingExtra(float spacingExtra) {
if (Float.compare(spacingExtra, mLineSpacingExtra) != 0) {
mLineSpacingExtra = spacingExtra;
mShouldUpdateLineHeight = true;
}
}

public void setTextLineHeight(int lineHeight) {
if (Float.compare(lineHeight, mLineHeight) != 0) {
mLineHeight = lineHeight;
mShouldUpdateLineHeight = true;
}
}

public void onBatchComplete() {
if (mShouldUpdateTypeface) {
updateTypeface();
mShouldUpdateTypeface = false;
}
if (!mShouldUpdateLineHeight) {
return;
}
if (mLineHeight > 0) {
final int fontHeight = getPaint().getFontMetricsInt(null);
// Make sure we don't setLineSpacing if it's not needed to avoid unnecessary redraw.
if (mLineHeight != fontHeight) {
// Set lineSpacingExtra by the difference of lineSpacing with lineHeight
setLineSpacing(mLineHeight - fontHeight, 1f);
}
} else {
setLineSpacing(mLineSpacingExtra, mLineSpacingMultiplier);
}
mShouldUpdateLineHeight = false;
}

@Override
protected void onDraw(Canvas canvas) {
RenderNode node = RenderManager.getRenderNode(this);
Expand Down Expand Up @@ -702,14 +751,14 @@ public void refreshSoftInput() {
public void setFontStyle(String style) {
if (TypeFaceUtil.TEXT_FONT_STYLE_ITALIC.equals(style) != mItalic) {
mItalic = !mItalic;
updateTypeface();
mShouldUpdateTypeface = true;
}
}

public void setFontFamily(String family) {
if (!Objects.equals(mFontFamily, family)) {
mFontFamily = family;
updateTypeface();
mShouldUpdateTypeface = true;
}
}

Expand All @@ -731,7 +780,7 @@ public void setFontWeight(String weight) {
}
if (fontWeight != mFontWeight) {
mFontWeight = fontWeight;
updateTypeface();
mShouldUpdateTypeface = true;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,30 +37,38 @@
import android.view.inputmethod.InputMethodManager;
import androidx.annotation.NonNull;

import androidx.annotation.Nullable;
import com.tencent.mtt.hippy.annotation.HippyController;
import com.tencent.mtt.hippy.annotation.HippyControllerProps;
import com.tencent.mtt.hippy.common.HippyArray;
import com.tencent.mtt.hippy.dom.node.NodeProps;
import com.tencent.mtt.hippy.modules.Promise;
import com.tencent.mtt.hippy.uimanager.ControllerManager;
import com.tencent.mtt.hippy.uimanager.HippyViewController;
import com.tencent.mtt.hippy.utils.LogUtils;
import com.tencent.mtt.hippy.utils.PixelUtil;
import com.tencent.mtt.hippy.views.view.HippyViewGroup;
import com.tencent.renderer.NativeRender;
import com.tencent.renderer.NativeRenderException;
import com.tencent.renderer.NativeRendererManager;
import com.tencent.renderer.component.text.TextRenderSupplier;
import com.tencent.renderer.node.RenderNode;
import com.tencent.renderer.node.TextInputRenderNode;
import com.tencent.renderer.node.TextVirtualNode;
import com.tencent.renderer.node.ViewPagerRenderNode;
import com.tencent.renderer.utils.ArrayUtils;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import static com.tencent.renderer.NativeRenderException.ExceptionCode.HANDLE_CALL_UI_FUNCTION_ERR;

@HippyController(name = HippyTextInputController.CLASS_NAME, dispatchWithStandardType = true)
public class HippyTextInputController extends HippyViewController<HippyTextInput> {

public static final String CLASS_NAME = "TextInput";
public final static int UNSET = -1;
public static final int DEFAULT_TEXT_COLOR = Color.BLACK;
public static final int DEFAULT_PLACEHOLDER_TEXT_COLOR = Color.GRAY;
private static final String TAG = "HippyTextInputControlle";
Expand All @@ -84,6 +92,17 @@ protected View createViewImpl(Context context) {
return new HippyTextInput(context);
}

@Override
public RenderNode createRenderNode(int rootId, int id, @Nullable Map<String, Object> props,
@NonNull String className, @NonNull ControllerManager controllerManager, boolean isLazy) {
return new TextInputRenderNode(rootId, id, props, className, controllerManager, isLazy);
}

@Override
public void onBatchComplete(@NonNull HippyTextInput textInput) {
textInput.onBatchComplete();
}

@Override
protected void updateExtra(@NonNull View view, Object object) {
super.updateExtra(view, object);
Expand Down Expand Up @@ -276,6 +295,24 @@ public void setLetterSpacing(HippyTextInput view, float letterSpacing) {
view.setLetterSpacing(PixelUtil.dp2px(letterSpacing));
}

@SuppressWarnings("unused")
@HippyControllerProps(name = NodeProps.LINE_HEIGHT, defaultType = HippyControllerProps.NUMBER)
public void setLineHeight(HippyTextInput view, int lineHeight) {
view.setTextLineHeight(Math.round(PixelUtil.dp2px(lineHeight)));
}

@SuppressWarnings("unused")
@HippyControllerProps(name = NodeProps.LINE_SPACING_MULTIPLIER, defaultType = HippyControllerProps.NUMBER, defaultNumber = UNSET)
public void setLineSpacingMultiplier(HippyTextInput view, float lineSpacingMultiplier) {
view.setLineSpacingMultiplier(lineSpacingMultiplier);
}

@SuppressWarnings("unused")
@HippyControllerProps(name = NodeProps.LINE_SPACING_EXTRA, defaultType = HippyControllerProps.NUMBER, defaultNumber = 0.0f)
public void setLineSpacingExtra(HippyTextInput view, float lineSpacingExtra) {
view.setLineSpacingExtra(PixelUtil.dp2px(lineSpacingExtra));
}

@HippyControllerProps(name = "value", defaultType = HippyControllerProps.STRING)
public void value(HippyTextInput view, String value) {
int selectionStart = view.getSelectionStart();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* 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 androidx.annotation.Nullable;
import com.tencent.mtt.hippy.uimanager.ControllerManager;
import java.util.Map;

public class TextInputRenderNode extends RenderNode {

public TextInputRenderNode(int rootId, int id, @Nullable Map<String, Object> props,
String className, ControllerManager componentManager, boolean isLazyLoad) {
super(rootId, id, props, className, componentManager, isLazyLoad);
}

@Override
protected boolean shouldNotifyNonBatchingChange() {
return !isBatching();
}
}
Loading