Skip to content

Commit 4d066bd

Browse files
committed
fixed useViewFrame for android
1 parent b3b2225 commit 4d066bd

File tree

9 files changed

+83
-97
lines changed

9 files changed

+83
-97
lines changed

README.md

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,31 @@ React-Native text gradient component for iOS & Android.
2222
## Status
2323

2424
- iOS - component works as drop-in replacement for standard `Text` component, e.g. it is possible to have nested gradients;
25-
- Android - WIP, currently only basic 'wrapper'-like behavior without nesting is supported.
26-
- React-Native - supported versions 0.50 - 0.52 , component is not usable with 0.53.0 because of this rn [bug](https://github.com/facebook/react-native/issues/17933)
25+
- Android - WIP, currently only basic 'wrapper'-like behavior without nesting is supported;
26+
- React-Native - supported version >0.50, except of 0.53.0.
2727

2828
## Usage
2929

3030
### LinearTextGradient
31-
Interface is similar to https://github.com/react-native-community/react-native-linear-gradient#examples
31+
Interface is similar to `Text` & [LinearGradient](https://github.com/react-native-community/react-native-linear-gradient)
32+
33+
#### colors
34+
An array of at least two color values that represent gradient colors. Example: `['red', 'blue']` sets gradient from red to blue.
35+
36+
#### start
37+
An optional object of the following type: `{ x: number, y: number }`. Coordinates declare the position that the gradient starts at, as a fraction of the overall size of the gradient, starting from the top left corner. Example: `{ x: 0.1, y: 0.1 }` means that the gradient will start 10% from the top and 10% from the left.
38+
39+
#### end
40+
Same as start, but for the end of the gradient.
41+
42+
#### locations
43+
An optional array of numbers defining the location of each gradient color stop, mapping to the color with the same index in `colors` prop. Example: `[0.1, 0.75, 1]` means that first color will take 0% - 10%, second color will take 10% - 75% and finally third color will occupy 75% - 100%.
44+
45+
#### useViewFrame
46+
Optional. If true gradient will be calculated for text view background frame rather than text frame.
47+
48+
<img src="img/useViewFrame.png" width="300">
49+
3250
```javascript
3351
import { LinearTextGradient } from 'react-native-text-gradient';
3452

@@ -45,7 +63,7 @@ import { LinearTextGradient } from 'react-native-text-gradient';
4563

4664
iOS | Android
4765
:---------------------------------------------:|:---------------------------------------------:
48-
<img src="ios.png" align="left" height="275"> | <img src="android.jpg" align="right" height="275">
66+
<img src="img/ios.png" align="left" height="275"> | <img src="img/android.jpg" align="right" height="275">
4967

5068

5169
## Caveats

android/src/main/java/iyegoroff/RNTextGradient/Linear/RNLinearTextGradientSpan.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ public class RNLinearTextGradientSpan extends CharacterStyle implements UpdateAp
2222
private float[] mLocations;
2323
private float[] mStart;
2424
private float[] mEnd;
25+
private boolean mUseViewFrame;
2526
private int mMaxWidth;
27+
private int mMaxHeight;
2628
private int mTextStart;
2729
private int mTextEnd;
2830
private String mText;
@@ -32,7 +34,9 @@ public RNLinearTextGradientSpan(
3234
int[] colors,
3335
float[] start,
3436
float[] end,
37+
boolean useViewFrame,
3538
float maxWidth,
39+
float maxHeight,
3640
int textStart,
3741
int textEnd,
3842
String text
@@ -41,7 +45,9 @@ public RNLinearTextGradientSpan(
4145
mColors = colors;
4246
mStart = start;
4347
mEnd = end;
48+
mUseViewFrame = useViewFrame;
4449
mMaxWidth = (int)maxWidth;
50+
mMaxHeight = (int)maxHeight;
4551
mTextStart = textStart;
4652
mTextEnd = textEnd;
4753
mText = text;
@@ -73,16 +79,22 @@ public void updateDrawState(TextPaint paint) {
7379

7480
Rect rect = isMultiline(paint) ? multiLineTextBounds(paint) : singleLineTextBounds(paint);
7581

76-
Log.d(ReactConstants.TAG, mText.substring(mTextStart, mTextEnd) + ": "
77-
+ String.valueOf(rect) + " "
78-
+ String.valueOf(rect.width()) + " "
79-
+ String.valueOf(rect.height()));
82+
// Log.d(ReactConstants.TAG, mText.substring(mTextStart, mTextEnd) + ": "
83+
// + String.valueOf(rect) + " "
84+
// + String.valueOf(rect.width()) + " "
85+
// + String.valueOf(rect.height()));
86+
87+
// Log.d(ReactConstants.TAG, "MaxW " + String.valueOf(mMaxWidth) + " width " + String.valueOf(rect.width()));
88+
// Log.d(ReactConstants.TAG, "MaxH " + String.valueOf(mMaxHeight) + " height " + String.valueOf(rect.height()));
89+
90+
int width = mUseViewFrame ? mMaxWidth : rect.width();
91+
int height = mUseViewFrame ? mMaxHeight : rect.height();
8092

8193
LinearGradient gradient = new LinearGradient(
82-
rect.left + mStart[0] * rect.width(),
83-
rect.top + mStart[1] * rect.height(),
84-
rect.left + mEnd[0] * rect.width(),
85-
rect.top + mEnd[1] * rect.height(),
94+
rect.left + mStart[0] * width,
95+
rect.top + mStart[1] * height,
96+
rect.left + mEnd[0] * width,
97+
rect.top + mEnd[1] * height,
8698
mColors,
8799
mLocations,
88100
Shader.TileMode.CLAMP

android/src/main/java/iyegoroff/RNTextGradient/Linear/RNShadowLinearTextGradient.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,17 @@ protected RNSetGradientSpanOperation createSpan(
4848
SpannableStringBuilder builder,
4949
int start,
5050
int end,
51-
float maxWidth
51+
float maxWidth,
52+
float maxHeight
5253
) {
5354
RNLinearTextGradientSpan span = new RNLinearTextGradientSpan(
5455
mLocations,
5556
mColors,
5657
mStart,
5758
mEnd,
59+
mUseViewFrame,
5860
maxWidth,
61+
maxHeight,
5962
start,
6063
end,
6164
builder.toString()

android/src/main/java/iyegoroff/RNTextGradient/RNShadowTextGradient.java

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public abstract class RNShadowTextGradient extends ReactTextShadowNode {
2424

2525
protected float[] mLocations;
2626
protected int[] mColors;
27+
protected boolean mUseViewFrame;
2728

2829
@ReactProp(name = "locations")
2930
public void setLocations(ReadableArray locations) {
@@ -41,7 +42,6 @@ public void setLocations(ReadableArray locations) {
4142

4243
@ReactProp(name = "colors")
4344
public void setColors(ReadableArray colors) {
44-
Log.d(ReactConstants.TAG, String.valueOf(colors));
4545
if (colors != null) {
4646
int[] _colors = new int[colors.size()];
4747

@@ -54,6 +54,13 @@ public void setColors(ReadableArray colors) {
5454
}
5555
}
5656

57+
@ReactProp(name = "useViewFrame")
58+
public void setUseViewFrame(boolean useViewFrame) {
59+
mUseViewFrame = useViewFrame;
60+
61+
markUpdated();
62+
}
63+
5764
@Override
5865
public boolean dispatchUpdates(
5966
float absoluteX,
@@ -92,7 +99,8 @@ private void updateGradient() {
9299
spannableWithGradient(
93100
(Spannable) getParentFieldValue(this, fieldName),
94101
this,
95-
getLayoutWidth()
102+
getLayoutWidth(),
103+
getLayoutHeight()
96104
)
97105
);
98106
}
@@ -102,17 +110,19 @@ protected abstract RNSetGradientSpanOperation createSpan(
102110
SpannableStringBuilder builder,
103111
int start,
104112
int end,
105-
float maxWidth
113+
float maxWidth,
114+
float maxHeight
106115
);
107116

108117
protected static Spannable spannableWithGradient(
109118
Spannable spannable,
110119
RNShadowTextGradient textCSSNode,
111-
float maxWidth
120+
float maxWidth,
121+
float maxHeight
112122
) {
113123
List<RNSetGradientSpanOperation> ops = new ArrayList<>();
114124
SpannableStringBuilder gradientBuilder = new SpannableStringBuilder();
115-
buildSpannedGradientFromTextCSSNode(textCSSNode, gradientBuilder, ops, maxWidth);
125+
buildSpannedGradientFromTextCSSNode(textCSSNode, gradientBuilder, ops, maxWidth, maxHeight);
116126

117127
for (int i = ops.size() - 1; i >= 0; i--) {
118128
//for (int i = 0; i < ops.size(); i++) {
@@ -126,7 +136,8 @@ protected static void buildSpannedGradientFromTextCSSNode(
126136
ReactTextShadowNode textGradientShadowNode,
127137
SpannableStringBuilder builder,
128138
List<RNSetGradientSpanOperation> ops,
129-
float maxWidth
139+
float maxWidth,
140+
float maxHeight
130141
) {
131142
int start = builder.length();
132143

@@ -137,7 +148,13 @@ protected static void buildSpannedGradientFromTextCSSNode(
137148
builder.append(((ReactRawTextShadowNode) child).getText());
138149

139150
} else if (child instanceof ReactTextShadowNode) {
140-
buildSpannedGradientFromTextCSSNode((ReactTextShadowNode) child, builder, ops, maxWidth);
151+
buildSpannedGradientFromTextCSSNode(
152+
(ReactTextShadowNode) child,
153+
builder,
154+
ops,
155+
maxWidth,
156+
maxHeight
157+
);
141158

142159
} else if (child instanceof ReactTextInlineImageShadowNode) {
143160
builder.append(
@@ -151,9 +168,10 @@ protected static void buildSpannedGradientFromTextCSSNode(
151168
int end = builder.length();
152169

153170
if (end >= start && textGradientShadowNode instanceof RNShadowTextGradient) {
154-
ops.add(
155-
((RNShadowTextGradient) textGradientShadowNode).createSpan(builder, start, end, maxWidth)
156-
);
171+
RNSetGradientSpanOperation spanOp = ((RNShadowTextGradient) textGradientShadowNode)
172+
.createSpan(builder, start, end, maxWidth, maxHeight);
173+
174+
ops.add(spanOp);
157175
}
158176
}
159177

android/src/main/java/iyegoroff/RNTextGradient/Radial/RNShadowRadialTextGradient.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ protected RNSetGradientSpanOperation createSpan(
3636
SpannableStringBuilder builder,
3737
int start,
3838
int end,
39-
float maxWidth
39+
float maxWidth,
40+
float maxHeight
4041
) {
4142
return null;
4243
}
File renamed without changes.
File renamed without changes.

img/useViewFrame.png

309 KB
Loading

src/create-text-gradient-class.js

Lines changed: 7 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ const createTextGradientClass = (
3333
const defaultPropAttributes = Object.keys(defaultProps)
3434
.reduce((acc, key) => { acc[key] = true; return acc; }, {});
3535

36-
const defaultStyle = { color: 'gray' };
37-
3836
const viewConfig = {
3937
validAttributes: mergeFast(ReactNativeViewAttributes.UIView, {
4038
isHighlighted: true,
@@ -56,58 +54,6 @@ const createTextGradientClass = (
5654
uiViewClassName,
5755
};
5856

59-
/**
60-
* A React component for displaying text.
61-
*
62-
* `Text` supports nesting, styling, and touch handling.
63-
*
64-
* In the following example, the nested title and body text will inherit the `fontFamily` from
65-
*`styles.baseText`, but the title provides its own additional styles. The title and body will
66-
* stack on top of each other on account of the literal newlines:
67-
*
68-
* ```ReactNativeWebPlayer
69-
* import React, { Component } from 'react';
70-
* import { AppRegistry, Text, StyleSheet } from 'react-native';
71-
*
72-
* export default class TextInANest extends Component {
73-
* constructor(props) {
74-
* super(props);
75-
* this.state = {
76-
* titleText: "Bird's Nest",
77-
* bodyText: 'This is not really a bird nest.'
78-
* };
79-
* }
80-
*
81-
* render() {
82-
* return (
83-
* <Text style={styles.baseText}>
84-
* <Text style={styles.titleText} onPress={this.onPressTitle}>
85-
* {this.state.titleText}{'\n'}{'\n'}
86-
* </Text>
87-
* <Text numberOfLines={5}>
88-
* {this.state.bodyText}
89-
* </Text>
90-
* </Text>
91-
* );
92-
* }
93-
* }
94-
*
95-
* const styles = StyleSheet.create({
96-
* baseText: {
97-
* fontFamily: 'Cochin',
98-
* },
99-
* titleText: {
100-
* fontSize: 20,
101-
* fontWeight: 'bold',
102-
* },
103-
* });
104-
*
105-
* // skip this line if using Create React Native App
106-
* AppRegistry.registerComponent('TextInANest', () => TextInANest);
107-
* ```
108-
*/
109-
110-
// $FlowFixMe(>=0.41.0)
11157
const TextGradient = createReactClass({
11258
displayName: 'TextGradient',
11359
propTypes: {
@@ -192,7 +138,6 @@ const createTextGradientClass = (
192138
testID: PropTypes.string,
193139
/**
194140
* Used to locate this view from native code.
195-
* @platform android
196141
*/
197142
nativeID: PropTypes.string,
198143
/**
@@ -231,7 +176,6 @@ const createTextGradientClass = (
231176
accessible: true,
232177
allowFontScaling: true,
233178
ellipsizeMode: 'tail',
234-
disabled: false,
235179
};
236180
},
237181
getInitialState: function () {
@@ -242,9 +186,7 @@ const createTextGradientClass = (
242186
mixins: [NativeMethodsMixin],
243187
viewConfig: viewConfig,
244188
getChildContext() {
245-
return {
246-
isInAParentText: true
247-
};
189+
return { isInAParentText: true };
248190
},
249191
childContextTypes: {
250192
isInAParentText: PropTypes.bool
@@ -319,44 +261,33 @@ const createTextGradientClass = (
319261
return this.props.pressRetentionOffset || PRESS_RECT_OFFSET;
320262
};
321263
}
322-
// $FlowFixMe(>=0.41.0)
323264
return setResponder;
324265
},
325266
onResponderGrant: function (e, dispatchID) {
326-
// $FlowFixMe(>=0.41.0)
327267
this.touchableHandleResponderGrant(e, dispatchID);
328268
this.props.onResponderGrant &&
329-
// $FlowFixMe(>=0.41.0)
330269
this.props.onResponderGrant.apply(this, arguments);
331270
}.bind(this),
332271
onResponderMove: function (e) {
333-
// $FlowFixMe(>=0.41.0)
334272
this.touchableHandleResponderMove(e);
335273
this.props.onResponderMove &&
336-
// $FlowFixMe(>=0.41.0)
337274
this.props.onResponderMove.apply(this, arguments);
338275
}.bind(this),
339276
onResponderRelease: function (e) {
340-
// $FlowFixMe(>=0.41.0)
341277
this.touchableHandleResponderRelease(e);
342278
this.props.onResponderRelease &&
343-
// $FlowFixMe(>=0.41.0)
344279
this.props.onResponderRelease.apply(this, arguments);
345280
}.bind(this),
346281
onResponderTerminate: function (e) {
347-
// $FlowFixMe(>=0.41.0)
348282
this.touchableHandleResponderTerminate(e);
349283
this.props.onResponderTerminate &&
350-
// $FlowFixMe(>=0.41.0)
351284
this.props.onResponderTerminate.apply(this, arguments);
352285
}.bind(this),
353286
onResponderTerminationRequest: function () {
354287
// Allow touchable or props.onResponderTerminationRequest to deny
355288
// the request
356-
// $FlowFixMe(>=0.41.0)
357289
var allowTermination = this.touchableHandleResponderTerminationRequest();
358290
if (allowTermination && this.props.onResponderTerminationRequest) {
359-
// $FlowFixMe(>=0.41.0)
360291
allowTermination = this.props.onResponderTerminationRequest.apply(this, arguments);
361292
}
362293
return allowTermination;
@@ -370,6 +301,11 @@ const createTextGradientClass = (
370301
};
371302
}
372303

304+
newProps = {
305+
...newProps,
306+
style: [{ color: 'gray' }, newProps.style],
307+
};
308+
373309
newProps.style = [
374310
{ color: 'gray' },
375311
newProps.style
@@ -390,9 +326,7 @@ const createTextGradientClass = (
390326
if (Touchable.TOUCH_TARGET_DEBUG && newProps.onPress) {
391327
newProps = {
392328
...newProps,
393-
style: [this.props.style, {
394-
color: 'magenta'
395-
}],
329+
style: [this.props.style, { color: 'magenta' }],
396330
};
397331
}
398332
if (this.context.isInAParentText) {

0 commit comments

Comments
 (0)