/** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.react.views.text; import javax.annotation.Nullable; import android.text.Spannable; import android.text.Spanned; import android.text.TextUtils; import android.view.Gravity; import android.widget.TextView; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.CatalystStylesDiffMap; import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.ReactProp; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.UIProp; import com.facebook.react.uimanager.ViewDefaults; import com.facebook.react.uimanager.ViewProps; import com.facebook.react.common.annotations.VisibleForTesting; /** * Manages instances of spannable {@link TextView}. * * This is a "shadowing" view manager, which means that the {@link NativeViewHierarchyManager} will * not manage children of native {@link TextView} instances returned by this manager. Instead we use * @{link ReactTextShadowNode} hierarchy to calculate a {@link Spannable} text representing the * whole text subtree. */ public class ReactTextViewManager extends BaseViewManager<ReactTextView, ReactTextShadowNode> { @VisibleForTesting public static final String REACT_CLASS = "RCTText"; @Override public String getName() { return REACT_CLASS; } @Override public ReactTextView createViewInstance(ThemedReactContext context) { return new ReactTextView(context); } // maxLines can only be set in master view (block), doesn't really make sense to set in a span @ReactProp(name = ViewProps.NUMBER_OF_LINES, defaultInt = ViewDefaults.NUMBER_OF_LINES) public void setNumberOfLines(ReactTextView view, int numberOfLines) { view.setMaxLines(numberOfLines); view.setEllipsize(TextUtils.TruncateAt.END); } @ReactProp(name = ViewProps.TEXT_ALIGN) public void setTextAlign(ReactTextView view, @Nullable String textAlign) { if (textAlign == null || "auto".equals(textAlign)) { view.setGravity(Gravity.NO_GRAVITY); } else if ("left".equals(textAlign)) { view.setGravity(Gravity.LEFT); } else if ("right".equals(textAlign)) { view.setGravity(Gravity.RIGHT); } else if ("center".equals(textAlign)) { view.setGravity(Gravity.CENTER_HORIZONTAL); } else { throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign); } } @ReactProp(name = ViewProps.LINE_HEIGHT, defaultFloat = Float.NaN) public void setLineHeight(ReactTextView view, float lineHeight) { if (Float.isNaN(lineHeight)) { // NaN will be used if property gets reset view.setLineSpacing(0, 1); } else { view.setLineSpacing(PixelUtil.toPixelFromSP(lineHeight), 0); } } @Override public void updateExtraData(ReactTextView view, Object extraData) { view.setText((Spanned) extraData); } @Override public ReactTextShadowNode createShadowNodeInstance() { return new ReactTextShadowNode(false); } @Override public Class<ReactTextShadowNode> getShadowNodeClass() { return ReactTextShadowNode.class; } }