Skip to content

Commit

Permalink
feat(android): support opacity for rich text
Browse files Browse the repository at this point in the history
  • Loading branch information
iPel committed Nov 17, 2023
1 parent e7b8241 commit 11d2f89
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
String ARRAY = "array";
String MAP = "map";

String name() default "name";
String name();

/*
* defaultType Number boolean string else default is do not check
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,15 @@ private static void initComponentPropsMap() {
HippyControllerProps controllerProps = method
.getAnnotation(HippyControllerProps.class);
if (controllerProps != null) {
if (!sComponentPropsMethodMap.containsKey(controllerProps.name())) {
sTextPropsSet.add(controllerProps.name());
String name = controllerProps.name();
if (!sComponentPropsMethodMap.containsKey(name)) {
sTextPropsSet.add(name);
}
sRenderPropsList.add(controllerProps.name());
sRenderPropsList.add(name);
}
}
// Special case: property "opacity" in TextVirtualNode also need to process in HippyViewController
sTextPropsSet.remove(NodeProps.OPACITY);
Collections.addAll(sRenderPropsList, sLayoutStyleList);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ public class TextImageSpan extends ImageSpan {
@Nullable
private Paint mBackgroundPaint = null;
private int mTintColor;
private final int mAlpha;

public TextImageSpan(Drawable drawable, String source, @NonNull ImageVirtualNode node,
@NonNull NativeRender nativeRenderer) {
Expand All @@ -120,6 +121,8 @@ public TextImageSpan(Drawable drawable, String source, @NonNull ImageVirtualNode
mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBackgroundPaint.setColor(node.getBackgroundColor());
}
// multiple alpha bits (0xFF) to convert opacity into alpha
mAlpha = Math.round(node.getFinalOpacity() * 255);
setUrl(source);
}

Expand Down Expand Up @@ -173,7 +176,7 @@ public void draw(Canvas canvas, CharSequence text, int start, int end, float x,
if (mMeasuredWidth == 0 || mMeasuredHeight == 0) {
return;
}
canvas.save();
int count = canvas.save();
int transY;
assert mVerticalAlign != null;
switch (mVerticalAlign) {
Expand All @@ -193,6 +196,9 @@ public void draw(Canvas canvas, CharSequence text, int start, int end, float x,
}

canvas.translate(x + mMarginLeft, transY);
if (mAlpha < 255) {
canvas.saveLayerAlpha(0, 0, mMeasuredWidth, mMeasuredHeight, mAlpha);
}
if (mBackgroundPaint != null) {
canvas.drawRect(0, 0, mMeasuredWidth, mMeasuredHeight, mBackgroundPaint);
}
Expand All @@ -211,7 +217,7 @@ public void draw(Canvas canvas, CharSequence text, int start, int end, float x,
canvas.scale(scaleX, scaleY, 0, 0);
drawable.draw(canvas);
}
canvas.restore();
canvas.restoreToCount(count);
}

private void legacyDraw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,11 @@ public void setVerticalAlign(String align) {
markDirty();
}

@HippyControllerProps(name = NodeProps.OPACITY, defaultType = HippyControllerProps.NUMBER, defaultNumber = 1f)
public void setOpacity(float opacity) {
super.setOpacity(opacity);
}

@SuppressWarnings("unused")
@HippyControllerProps(name = "defaultSource", defaultType = HippyControllerProps.STRING)
public void setDefaultSource(String defaultSource) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,8 +394,8 @@ protected void createChildrenSpanOperation(@NonNull List<SpanOperation> ops,
}
}

protected TextForegroundColorSpan createForegroundColorSpan() {
return new TextForegroundColorSpan(mColor);
protected TextForegroundColorSpan createForegroundColorSpan(float opacity) {
return new TextForegroundColorSpan(colorWithOpacity(mColor, opacity));
}

protected void createSpanOperationImpl(@NonNull List<SpanOperation> ops,
Expand All @@ -412,9 +412,13 @@ protected void createSpanOperationImpl(@NonNull List<SpanOperation> ops,
TextVerticalAlignSpan span = new TextVerticalAlignSpan(verticalAlign);
ops.add(new SpanOperation(start, end, span, SpanOperation.PRIORITY_LOWEST));
}
ops.add(new SpanOperation(start, end, createForegroundColorSpan()));
float opacity = getFinalOpacity();
ops.add(new SpanOperation(start, end, createForegroundColorSpan(opacity)));
if (mBackgroundColor != Color.TRANSPARENT && mParent != null) {
ops.add(new SpanOperation(start, end, new BackgroundColorSpan(mBackgroundColor)));
int color = colorWithOpacity(mBackgroundColor, opacity);
if (color != Color.TRANSPARENT) {
ops.add(new SpanOperation(start, end, new BackgroundColorSpan(color)));
}
}
if (mLetterSpacing != 0) {
ops.add(new SpanOperation(start, end,
Expand All @@ -434,9 +438,11 @@ protected void createSpanOperationImpl(@NonNull List<SpanOperation> ops,
ops.add(new SpanOperation(start, end, new StrikethroughSpan()));
}
if (mShadowOffsetDx != 0 || mShadowOffsetDy != 0) {
ops.add(new SpanOperation(start, end,
new TextShadowSpan(mShadowOffsetDx, mShadowOffsetDy, mShadowRadius,
mShadowColor)));
int color = colorWithOpacity(mShadowColor, opacity);
if (color != Color.TRANSPARENT) {
ops.add(new SpanOperation(start, end,
new TextShadowSpan(mShadowOffsetDx, mShadowOffsetDy, mShadowRadius, color)));
}
}
if (mGestureTypes != null && mGestureTypes.size() > 0) {
TextGestureSpan span = new TextGestureSpan(mId);
Expand All @@ -460,6 +466,16 @@ protected void createSpanOperationImpl(@NonNull List<SpanOperation> ops,
}
}

public static int colorWithOpacity(int color, float opacity) {
if (opacity >= 1) {
return color;
} else if (opacity > 0) {
int alpha = (color >> 24) & 0xFF;
return (Math.round(alpha * opacity) << 24) | (color & 0xFFFFFF);
}
return Color.TRANSPARENT;
}

protected float getLineSpacingMultiplier() {
return mLineSpacingMultiplier <= 0 ? 1.0f : mLineSpacingMultiplier;
}
Expand Down Expand Up @@ -778,4 +794,13 @@ public String getVerticalAlign() {
}
return null;
}

@HippyControllerProps(name = NodeProps.OPACITY, defaultType = HippyControllerProps.NUMBER, defaultNumber = 1f)
public void setOpacity(float opacity) {
// top-level opacity will be handled by HippyViewController, so only sub-level opacity needs to be considered
if (mParent != null) {
super.setOpacity(opacity);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public abstract class VirtualNode {
protected VirtualNode mParent;
@Nullable
protected List<String> mGestureTypes;
protected float mOpacity = 1f;

public VirtualNode(int rootId, int id, int pid, int index) {
mRootId = rootId;
Expand Down Expand Up @@ -133,6 +134,18 @@ public int getChildCount() {
return mChildren.size();
}

public void setOpacity(float opacity) {
opacity = Math.min(Math.max(0, opacity), 1);
if (opacity != mOpacity) {
mOpacity = opacity;
markDirty();
}
}

public float getFinalOpacity() {
return mParent == null ? mOpacity : mParent.getFinalOpacity() * mOpacity;
}

protected static class SpanOperation {

public static final int PRIORITY_DEFAULT = 1;
Expand Down

0 comments on commit 11d2f89

Please sign in to comment.