I am trying to have a repeating-linear-gradient for my view in React Native. However i couldn't find any information or library that would help me use it.
I found a library named react-native-linear-gradient but it seems to be helpful to only have simple linear gradient.
Thanks for your help in advance
CSS
background: repeating-linear-gradient(
-55deg,
#222,
#222 10px,
#333 10px,
#333 20px
);
In React, styles are specified with an object wherein the key is the camelCase version of the style name, and the value is the style’s value. If the value is not explicitly typeof 'number', the entire value must be a single string. Within that string, normal css style names can be used.
Here is an example:
<ExampleComponent
style={{
background: 'repeating-linear-gradient(-55deg, #222, #222 10px,#333 10px, #333 20px)',
backgroundSize: 'cover',
}}
/>
I have used react-native-linear-gradient for my splash screen
fist I have set 4 different colors and make it a gradient with white color.
const gradient1 = [Colors.secondary1Color, Colors.white];
const gradient2 = [Colors.primary1Color, Colors.white];
const gradient3 = [Colors.secondaryColor, Colors.white];
const gradient4 = [Colors.primaryColor, Colors.white];
I first set this.state = {changeGradient: true}
then I have this changeGradient function which changes the const gradient colors ever had a second
changeGradient = async () => {
console.log("changeGradient", await this.state.gradient);
if (this.state.changeGradient) {
setTimeout(async () => {
await this.setState(({ gradient }) => ({ gradient: gradient === gradient1 ? gradient2 : gradient === gradient2 ? gradient3 : gradient === gradient3 ? gradient4 : gradient1 }));
this.changeGradient();
}, 500);
}
};
Then, I render in the Lineargradient component
<LinearGradient colors={this.state.gradient} style={styles.container}>
</LinearGradient >
You're good to go!!!
Hope this helps you!
Related
I am trying to incorporate this WYSIWYG package into my react native project (0.64.3). I built my project with a managed workflow via Expo (~44.0.0).
The problem I am noticing is that the editor will sometimes render with the text from my database and sometimes render without it.
Here is a snippet of the function that retrieves the information from firebase.
const [note, setNote] = useState("");
const getNote = () => {
const myDoc = doc(db,"/users/" + user.uid + "/Destinations/Trip-" + trip.tripID + '/itinerary/' + date);
getDoc(myDoc)
.then(data => {
setNote(data.data()[date]);
}).catch();
}
The above code and the editor component are nested within a large function
export default function ItineraryScreen({route}) {
// functions
return (
<RichEditor
onChange={newText => {
setNote(newText)
}}
scrollEnabled={false}
ref={text}
initialFocus={false}
placeholder={'What are you planning to do this day?'}
initialContentHTML={note}
/>
)
}
Here is what it should look like with the text rendered (screenshot of simulator):
But this is what I get most of the time (screenshot from physical device):
My assumption is that there is a very slight delay between when the data for the text editor is actually available vs. when the editor is being rendered. I believe my simulator renders correctly because it is able to process the getNote() function faster.
what I have tried is using a setTimeOut function to the display of the parent View but it does not address the issue.
What do you recommend?
I believe I have solved the issue. I needed to parse the response better before assigning a value to note and only show the editor and toolbar once a value was established.
Before firebase gets queried, I assigned a null value to note
const [note, setNote] = useState(null);
Below, I will always assign value to note regardless of the outcome.
if(data.data() !== undefined){
setNote(data.data()[date]);
} else {
setNote("");
}
The last step was to only show the editor once note no longer had a null value.
{
note !== null &&
<RichToolbar
style={{backgroundColor:"white", width:"114%", flex:1, position:"absolute", left:0, zIndex:4, bottom: (toolbarVisible) ? keyboardHeight * 1.11 : 0 , marginBottom:-40, display: toolbarVisible ? "flex" : "none"}}
editor={text}
actions={[ actions.undo, actions.setBold, actions.setItalic, actions.setUnderline,actions.insertLink, actions.insertBulletsList, actions.insertOrderedList, actions.keyboard ]}
iconMap={{ [actions.heading1]: ({tintColor}) => (<Text style={[{color: tintColor}]}>H1</Text>), }}
/>
<RichEditor
disabled={disableEditor}
initialFocus={false}
onChange={ descriptionText => { setNote(descriptionText) }}
scrollEnabled={true}
ref={text}
placeholder={'What are you planning to do?'}
initialContentHTML={note}
/>
}
It is working properly.
I'm trying to render an curved vertical list like this iOS component: https://github.com/makotokw/CocoaWZYCircularTableView
That component (written in Obj-c) iterates the visible cells when laying them out, and sets the frame (i.e. indent) using asin.
I know in React Native I can set the leftMargin style in the renderItem callback, but I can't figure out how to get the on-screen index of the item - all I have is the index into the source data. And also, at that point, I don't think I have access to the absolute position.
Any ideas?
The function you are looking for is
onViewableItemsChanged.
You can use it with viewabilityConfig which provides us with
minimumViewTime,viewAreaCoveragePercentThreshold,waitForInteraction
which can be set accordingly
const VIEWABILITY_CONFIG = {
minimumViewTime: 3000,
viewAreaCoveragePercentThreshold: 100,
waitForInteraction: true,
};
_onViewableItemsChanged = (info: {
changed: Array<{
key: string,
isViewable: boolean,
item: any,
index: ?number,
section?: any,
}>
}
){
//here you can have the index which is visible to you
}
<FlatList
renderItem={this.renderItem}
data={this.state.data}
onViewableItemsChanged={this._onViewableItemsChanged}
viewabilityConfig={VIEWABILITY_CONFIG}
/>
Thanks for both answers.
What I have ended up doing is deriving the visible items using the scroll offset of the list. This is simple because the list items all have the same height.
I do this in the onScroll handler, and at that point I calculate the horizontal offset for each item (and I use leftMargin / rightMargin to render this). It's not perfect, but it does give me an elliptical list.
_handleScroll = (event) => {
const topItemIndex = Math.floor(event.nativeEvent.contentOffset.y / LIST_ITEM_HEIGHT);
const topItemSpare = LIST_ITEM_HEIGHT-(event.nativeEvent.contentOffset.y % LIST_ITEM_HEIGHT);
const positionFromEllipseTop = (forIndex-topItemIndex)*LIST_ITEM_HEIGHT+topItemSpare;
const positionFromOrigin = Math.floor(Math.abs(yRadius - positionFromEllipseTop));
const angle = Math.asin(positionFromOrigin / yRadius);
if (orientation === 'Left') {
marginLeft = 0;
marginRight = ((xRadius * Math.cos(angle)))-LIST_ITEM_HEIGHT;
alignSelf = 'flex-end';
}
else if (orientation === 'Right') {
marginLeft = (xRadius * Math.cos(angle))-LIST_ITEM_HEIGHT;
marginRight = 0;
alignSelf = 'flex-start';
}
}
React-native's FlatList component has a prop called onLayout. You can get the position of the component on screen with this prop.
onLayout
Invoked on mount and layout changes with:
{nativeEvent: { layout: {x, y, width, height}}}
This event is fired immediately once the layout has been calculated,
but the new layout may not yet be reflected on the screen at the time
the event is received, especially if a layout animation is in
progress.
I have some Text element with dynamically loaded text. It's an RTL language (Hebrew) text mixed with some English.
When the first char is English, it automatically sets to LTR direction.
When the first char is Hebrew, it automatically sets to RTL direction.
I'm not happy with that behavoir!
I'd like to set the element to be RTL anyway. Always.
In CSS that would be very simple:
text-align: right; direction: rtl;
How can I achieve the same in React Native?
When I had this problem (of individual lines of text in RTL language being incorrectly treated as LTR becuase they start with non-transliterated LTR text or numbers), I dealt with it using Unicode direction marker characters.
Here they are (they're the invisible characters between the quotes):
'' to force text to be treated as RTL
'' to force text to be treated as LTR
These change the behaviour you're seeing, explicitly saying how the text should be treated rather than letting the system assume.
How you apply these is up to you. I mostly did it with regex find-replace insertions in the source content, but you could do something like this (untested), making a swap-in replacement for useTranslation's t function that wraps the text in the appropriate Unicode control character:
import { I18nManager } from 'react-native'
// assuming you're using i18n hooks
import { useTranslation } from 'react-i18next'
const rtlMarkerChar = ''
const ltrMarkerChar = ''
const directionChar = I18nManager.isRTL ? rtlMarkerChar : ltrMarkerChar
// Use instead of `useTranslation` to force text right on RTL and left on LTR
// regardless of the initial character of the particular snippet of text
export const useLocaleAlignedText = () => {
const { t } = useTranslation()
return (key) => `${directionChar}${t(key)}`
}
// For example, this should be consistently RTL or LTR regardless of content
const SomeComponent = ({ contentKey }) => {
const t = useLocaleAlignedText()
return <Text>{t(contentKey)}</Text>
}
Be warned that the above might not work where your content contains newline characters, you might need to inject the control characters at the start of each line. This was one of the reasons I chose to inject the characters into the source material; but be warned also, that's hard work and easy to make mistakes.
To handle RTL for Text, Use style alignSelf: 'flex-start'
Example react-native:
<View>
<Text style={styles.headersText}>{headerTitle}</Text>
</View>
StyleSheet.create({ headersText: {
alignSelf: 'flex-start', // <- Here Handle RTL for Text
paddingHorizontal: 16,
paddingTop: 14,
color: 'black',
fontSize: 13,
},
});
I did this with :
textAlign:'right'
your Text should have this style.
This worked for me:
<Text style={{alignSelf: "flex-start"}}>
{text}
</Text>
BTW, if you wanna force RTL for the entire project you could just write something like this and run it in your main App component:
import { I18nManager } from "react-native";
const App = () => {
. . . . . . . .
const rtl = () => {
if (I18nManager.isRTL === false) {
I18nManager.allowRTL(true);
I18nManager.forceRTL(true);
}
};
. . . . . . . .
}
React Native has documentation for AutoExpandingTextInput: https://facebook.github.io/react-native/docs/textinput.html
The Problem: When the content of the AutoExpandingTextInput is changed programmatically the height never changes.
For example:
componentWillReceiveProps(props) {
this.setState({
richText: this._addHighlights(props.richText)
});
}
//
<AutoExpandingTextInput ref={component => this._text = component}>
{this.state.richText}
</AutoExpandingTextInput>
Say, for example. the user hits a button that adds a link to the text that wraps to the next line; in this case, the AutoExpandingTextInput never expands, because the height only is measured & changed on the onChange event of the TextInput.
I need some work around to get the content height when no onChange is triggered --- or less ideally, a way to programmatically trigger an onChange to the TextInput.
Are there any solutions????
No need to use the AutoExpandingTextInput plugin any more. The functionality you need is supported (sort of) in react-native now and will resize with a programatic update. Try something like this:
_heightChange(event) {
let height = event.nativeEvent.contentSize.height;
if (height < _minHeight) {
height = _minHeight;
} else if (height > _maxHeight) {
height = _maxHeight;
}
if (height !== this.state.height) {
this.setState({height: height});
}
}
render() {
return (
<TextInput
{...this.props}
multiline={true}
onContentSizeChange={this._heightChange.bind(this)}
/>
)
}
I would like to be able to know the actual size of a network-loaded image that has been passed into <Image /> I have tried using onLayout to work out the size (as taken from here https://github.com/facebook/react-native/issues/858) but that seems to return the sanitised size after it's already been pushed through the layout engine.
I tried looking into onLoadStart, onLoad, onLoadEnd, onProgress to see if there was any other information available but cannot seem to get any of these to fire. I have declared them as follows:
onImageLoadStart: function(e){
console.log("onImageLoadStart");
},
onImageLoad: function(e){
console.log("onImageLoad");
},
onImageLoadEnd: function(e){
console.log("onImageLoadEnd");
},
onImageProgress: function(e){
console.log("onImageProgress");
},
onImageError: function(e){
console.log("onImageError");
},
render: function (e) {
return (
<Image
source={{uri: "http://adomain.com/myimageurl.jpg"}}
style={[this.props.style, this.state.style]}
onLayout={this.onImageLayout}
onLoadStart={(e) => {this.onImageLoadStart(e)}}
onLoad={(e) => {this.onImageLoad(e)}}
onLoadEnd={(e) => {this.onImageLoadEnd(e)}}
onProgress={(e) => {this.onImageProgress(e)}}
onError={(e) => {this.onImageError(e)}} />
);
}
Thanks.
Image component now provides a static method to get the size of the image. For example:
Image.getSize(myUri, (width, height) => {this.setState({width, height})});
You can use resolveAssetSource method from the Image component :
import picture from 'pathToYourPicture';
const {width, height} = Image.resolveAssetSource(picture);
This answer is now out of date. See Bill's answer.
Image.getSize(myUri, (width, height) => { this.setState({ width, height }) });
Old Answer (valid for older builds of react native)
Ok, I got it working. Currently this takes some modification of the React-Native installation as it's not natively supported.
I followed the tips in this thread to enabled me to do this.
https://github.com/facebook/react-native/issues/494
Mainly, alter the RCTNetworkImageView.m file: add the following into setImageURL
void (^loadImageEndHandler)(UIImage *image) = ^(UIImage *image) {
NSDictionary *event = #{
#"target": self.reactTag,
#"size": #{
#"height": #(image.size.height),
#"width": #(image.size.width)
}
};
[_eventDispatcher sendInputEventWithName:#"loaded" body:event];
};
Then edit the line that handles the load completion:
[self.layer removeAnimationForKey:#"contents"];
self.layer.contentsScale = image.scale;
self.layer.contents = (__bridge id)image.CGImage;
loadEndHandler();
replace
loadEndHandler();
with
loadImageEndHandler(image);
Then in React-Native you have access to the size via the native events. data from the onLoaded function - note the documentation currently says the function is onLoad but this is incorrect. The correct functions are as follows for v0.8.0:
onLoadStart
onLoadProgress
onLoaded
onLoadError
onLoadAbort
These can be accessed like so:
onImageLoaded: function(data){
try{
console.log("image width:"+data.nativeEvents.size.width);
console.log("image height:"+data.nativeEvents.size.height);
}catch(e){
//error
}
},
...
render: function(){
return (
<View style={{width:1,height:1,overflow='hidden'}}>
<Image source={{uri: yourImageURL}} resizeMode='contain' onLoaded={this.onImageLoaded} style={{width:5000,height:5000}} />
</View>
);
}
Points to note:
I have set a large image window and set it inside a wrapping element of 1x1px this is because the image must fit inside if you are to retrieve meaningful values.
The resize mode must be 'contain' to enable you to get the correct sizes, otherwise the constrained size will be reported.
The image sizes are scaled proportionately to the scale factor of the device, e.g. a 200*200 image on an iPhone6 (not 6 plus) will be reported as 100*100. I assume that this also means it will be reported as 67*67 on an iPhone6 plus but I have not tested this.
I have not yet got this to work for GIF files which traverse a different path on the Obj-C side of the bridge. I will update this answer once I have done that.
I believe there is a PR going through for this at the moment but until it is included in the core then this change will have to be made to the react-native installation every time you update/re-install.
TypeScript example:
import {Image} from 'react-native';
export interface ISize {
width: number;
height: number;
}
function getImageSize(uri: string): Promise<ISize> {
const success = (resolve: (value?: ISize | PromiseLike<ISize>) => void) => (width: number, height: number) => {
resolve({
width,
height
});
};
const error = (reject: (reason?: any) => void) => (failure: Error) => {
reject(failure);
};
return new Promise<ISize>((resolve, reject) => {
Image.getSize(uri, success(resolve), error(reject));
});
}