Is there a Cross platform clearButtonMode for Android with React Native - react-native

How should one implement the "X" to clear button in react native so that it works with Android as well as iOS. iOS has the text input option of "clearButtonMode" enum('never', 'while-editing', 'unless-editing', 'always').
To make it cross platform, do we need to just add an android conditional rendering of the clear button? Something like:
{Platform.OS === 'android' && <ClearTextButton />}
Seems a bit hacky so I am wondering if there is a cleaner method for this.

For your problem, you just need to create a simple button to handle the clear function of your input field and place it right next to your TextInput component to have the effect of clearButtonMode.
A naive implementation could be something like this:
Create these states in your main component constructor :
A state for the status of your TextInput (is it touched?, does it have text yet?)
A state for the actual value of your TextInput, set your TextInput's value to this state.
For example:
this.state = {
textInput1Status: 'untouched',
textInput1Value: '',
};
Create callback functions to set your states:
Create a callback function to set both your TextInput's value state and status state and assign it to the onChange prop of you TextInput.
For example:
<TextInput
onChangeText={(text) => this.onTextInput1Change(text)}
value={this.state.textInput1Value}
/>
...
onTextInput1Change(text) {
this.setState({
textInput1Status: 'touched',
textInput1Value: text
});
}
Create your own button using TouchableOpacity and handle the clear function.
For example:
<TouchableOpacity onPress={this.clearText}>
<Image
style={styles.button}
source={require('./myButton.png')}
/>
</TouchableOpacity>
...
clearText() {
this.setState({
textInput1Status: 'untouched',
textInput1Value: '',
});
}
Handle the rendering of your "X" button:
For example:
renderClearButotn() {
if (this.state.textInput1Status == 'touched') {
return (
<TouchableOpacity onPress={this.clearText}>
<Image
style={styles.button}
source={require('./myButton.png')}
/>
</TouchableOpacity>
);
} else {
return '';
}
}
...
render() {
return (
<TextInput
onChangeText={(text) => this.onTextInput1Change(text)}
value={this.state.textInput1Value}
/>
{this.renderClearButton()}
);
}
In this way your code will be independent from both iOS and Android. I hope this could help you!

There is another simple solution I found from this article. It works perfect for me in Android, and it is expected to give the same view and behavior in iOS also.
I had to modify the styles slightly to match with my UI
closeButtonParent: {
justifyContent: 'center',
alignItems: 'center',
borderTopRightRadius: 5,
borderBottomRightRadius: 5,
backgroundColor: "#cdcdcd",
width: 30,
},
Code credit goes to https://www.codevscolor.com/react-native-text-input-clear-button/ auther

This solution works ok but it's not the exact same effect than the clearButtonMode in iOS. The clearButtonMode won't dismiss the keyboard when clicked, and this solution for android will dispatch the Keyboard.dismiss event natively and there's no way to catch it, so the user needs to tap again on the input to get the keyboard back.

Related

How avoid to press button on scroll React native

I have two scrollviews with Pressable inside but when I scroll inside the scrollview it triggers the pressable button.
I'd like to avoid trigger that pressable on scroll but only on press as it should be.
Here you can see what I mean :
https://imgur.com/zh6Jch8
Sorry we can't see the mouse, I don't know how to show it with Android studio.
I've implemented onLongPress with Pressable but it's not really great as it results in worse user experience.
No code provided here : I just use Pressable with on onLongPress for now inside scrollview or Flatlist
The press is visible(button gets a bit transparent), however the onPress function is not called. Also try and use TouchableOpacity instead of Pressable and see if it works.
render() {
const time = [{id: 0}, {id: 0}, {id: 0}, {id: 0}, {id: 0}];
return (
<ScrollView style={{flex: 1, backgroundColor: 'red', marginTop: 50}}>
{time.map((data, index) => {
return (
<TouchableOpacity
style={{
paddingVertical: 100,
marginBottom: 20,
backgroundColor: 'green',
}}
onPress={() => alert(`HEllo ${index}`)}>
<Text>HEllo ${data.id}</Text>
</TouchableOpacity>
);
})}
</ScrollView>
);
}
I tried the above and the alert(HEllo ${index}) was never called.
Also if you want to prevent the user from seeing any interaction of buttonPress, try using <TouchableWithutFeedback /> from react-native
Here's what I did.
use onPressIn and onPressOut to modify the style of my pressable through a "pressed" state.
use onPress for my action, use onLongPress to do absolutely nothing so I can scroll without activating my action.
<Pressable
onPressIn={() => {
setPressed(true)
}}
onPressOut={() => {
setPressed(false)
}}
onPress={() => {
whateverYouWantYourPressableToDo()
}}
onLongPress={() => {}}
>
I just tested it on my own app, and it seems to be working as expected. When I tap a button my action triggers. when I press and hold for scrolling, I scroll and my pressable does nothing. Hope this is useful for you, or someone in the future :)
I spent my whole day on this problem but finally I found a solution for this problem.
import it from gesture handler either TouchableWithoutFeedback or touchableOpacity.
import { TouchableWithoutFeedback } from "react-native-gesture-handler";
it will definitely work and your problem will solve.

How to make possible to deselect text in a Text component in React Native?

I'm trying to make an app with React Native which shows a lot of information to the end user.
It's vital that the user can select/copy/paste the info from and to the app.
The selectable property of Text is quite useful since it uses the native android UI for selecting text.
My only problem is that if you select a part of the text (intentionally or accidentally), you can only deselect if you tap inside the Text component again.
That is, if I touch the screen anywhere else (where any other component would be, even its father), the text keeps being selected.
Take, for example, the "Hello World" in React Native Documentation, and just add the selectable property:
import React from 'react';
import { Text, View } from 'react-native';
export default function YourApp() {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text selectable>
Try editing me! 🎉
</Text>
</View>
);
}
If you run it on android, you'll notice that you can indeed select and copy when you double tap (or long tap) as expected. But you won't be able to cancel the selection unless you tap on some part of the text again. If you touch any other part of the screen the selection UI won't go away.
Is there a way to achieve that? There are too many Text components in my app, with varying length and size. When users accidentally select something, a lot feel frustrated tapping away and nothing happening.
In this case I would use a TouchableWithoutFeedback component.
TouchableWithoutFeedback
Example from RN, where alert('Pressed!') is your function to remove selection.
function MyComponent(props) {
return (
<View {...props} style={{ flex: 1, backgroundColor: '#fff' }}>
<Text>My Component</Text>
</View>
);
}
<TouchableWithoutFeedback onPress={() => alert('Pressed!')}>
<MyComponent />
</TouchableWithoutFeedback>;

Is that possible to force keyboard gone immediately in React Native? [duplicate]

If I tap onto a textinput, I want to be able to tap somewhere else in order to dismiss the keyboard again (not the return key though). I haven't found the slightest piece of information concerning this in all the tutorials and blog posts that I read.
This basic example is still not working for me with react-native 0.4.2 in the Simulator. Couldn't try it on my iPhone yet.
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.ios.js
</Text>
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+D or shake for dev menu
</Text>
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onEndEditing={this.clearFocus}
/>
</View>
The problem with keyboard not dismissing gets more severe if you have keyboardType='numeric', as there is no way to dismiss it.
Replacing View with ScrollView is not a correct solution, as if you have multiple textInputs or buttons, tapping on them while the keyboard is up will only dismiss the keyboard.
Correct way is to encapsulate View with TouchableWithoutFeedback and calling Keyboard.dismiss()
EDIT: You can now use ScrollView with keyboardShouldPersistTaps='handled' to only dismiss the keyboard when the tap is not handled by the children (ie. tapping on other textInputs or buttons)
If you have
<View style={{flex: 1}}>
<TextInput keyboardType='numeric'/>
</View>
Change it to
<ScrollView contentContainerStyle={{flexGrow: 1}}
keyboardShouldPersistTaps='handled'
>
<TextInput keyboardType='numeric'/>
</ScrollView>
or
import {Keyboard} from 'react-native'
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
<View style={{flex: 1}}>
<TextInput keyboardType='numeric'/>
</View>
</TouchableWithoutFeedback>
EDIT: You can also create a Higher Order Component to dismiss the keyboard.
import React from 'react';
import { TouchableWithoutFeedback, Keyboard, View } from 'react-native';
const DismissKeyboardHOC = (Comp) => {
return ({ children, ...props }) => (
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
<Comp {...props}>
{children}
</Comp>
</TouchableWithoutFeedback>
);
};
const DismissKeyboardView = DismissKeyboardHOC(View)
Simply use it like this
...
render() {
<DismissKeyboardView>
<TextInput keyboardType='numeric'/>
</DismissKeyboardView>
}
NOTE: the accessible={false} is required to make the input form continue to be accessible through VoiceOver. Visually impaired people will thank you!
This just got updated and documented! No more hidden tricks.
import { Keyboard } from 'react-native'
// Hide that keyboard!
Keyboard.dismiss()
Github link
Use React Native's Keyboard.dismiss()
Updated Answer
React Native exposed the static dismiss() method on the Keyboard, so the updated method is:
import { Keyboard } from 'react-native';
Keyboard.dismiss()
Original Answer
Use React Native's dismissKeyboard Library.
I had a very similar problem and felt like I was the only one that didn't get it.
ScrollViews
If you have a ScrollView, or anything that inherits from it like a ListView, you can add a prop that will automatically dismiss the keyboard based on press or dragging events.
The prop is keyboardDismissMode and can have a value of none, interactive or on-drag. You can read more on that here.
Regular Views
If you have something other than a ScrollView and you'd like any presses to dismiss the keyboard, you can use a simple TouchableWithoutFeedback and have the onPress use React Native's utility library dismissKeyboard to dismiss the keyboard for you.
In your example, you could do something like this:
var DismissKeyboard = require('dismissKeyboard'); // Require React Native's utility library.
// Wrap your view with a TouchableWithoutFeedback component like so.
<View style={styles.container}>
<TouchableWithoutFeedback onPress={ () => { DismissKeyboard() } }>
<View>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.ios.js
</Text>
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+D or shake for dev menu
</Text>
<TextInput style={{height: 40, borderColor: 'gray', borderWidth: 1}} />
</View>
</TouchableWithoutFeedback>
</View>
Note: TouchableWithoutFeedback can only have a single child so you need to wrap everything below it in a single View as shown above.
use this for custom dismissal
var dismissKeyboard = require('dismissKeyboard');
var TestView = React.createClass({
render: function(){
return (
<TouchableWithoutFeedback
onPress={dismissKeyboard}>
<View />
</TouchableWithoutFeedback>
)
}
})
The simple answer is to use a ScrollView instead of View and set the scrollable property to false (might need to adjust some styling though).
This way, the keyboard gets dismissed the moment I tap somewhere else. This might be an issue with react-native, but tap events only seem to be handled with ScrollViews which leads to the described behaviour.
Edit: Thanks to jllodra. Please note that if you tap directly into another Textinput and then outside, the keyboard still won't hide.
You can import keyboard from react-native like below:
import { Keyboard } from 'react-native';
and in your code could be something like this:
render() {
return (
<TextInput
onSubmit={Keyboard.dismiss}
/>
);
}
static dismiss()
Dismisses the active keyboard and removes focus.
I'm brand new to React, and ran into the exact same issue while making a demo app. If you use the onStartShouldSetResponder prop (described here), you can grab touches on a plain old React.View. Curious to hear more experienced React-ers' thoughts on this strategy / if there's a better one, but this is what worked for me:
containerTouched(event) {
this.refs.textInput.blur();
return false;
}
render() {
<View onStartShouldSetResponder={this.containerTouched.bind(this)}>
<TextInput ref='textInput' />
</View>
}
2 things to note here. First, as discussed here, there's not yet a way to end editing of all subviews, so we have to refer to the TextInput directly to blur it. Second, the onStartShouldSetResponder is intercepted by other touchable controls on top of it. So clicking on a TouchableHighlight etc (including another TextInput) within the container view will not trigger the event. However, clicking on an Image within the container view will still dismiss the keyboard.
Use ScrollView instead of View and set the keyboardShouldPersistTaps attribute to false.
<ScrollView style={styles.container} keyboardShouldPersistTaps={false}>
<TextInput
placeholder="Post Title"
onChange={(event) => this.updateTitle(event.nativeEvent.text)}
style={styles.default}/>
</ScrollView>
Wrapping your components in a TouchableWithoutFeedback can cause some weird scroll behavior and other issues. I prefer to wrap my topmost app in a View with the onStartShouldSetResponder property filled in. This will allow me to handle all unhandled touches and then dismiss the keyboard. Importantly, since the handler function returns false the touch event is propagated up like normal.
handleUnhandledTouches(){
Keyboard.dismiss
return false;
}
render(){
<View style={{ flex: 1 }} onStartShouldSetResponder={this.handleUnhandledTouches}>
<MyApp>
</View>
}
The simplest way to do this
import {Keyboard} from 'react-native'
and then use the function Keyboard.dismiss()
That's all.
Here is a screenshot of my code so you can understand faster.
Now wrap the entire view with TouchableWithoutFeedback and onPress function is keyboard.dismiss()
Here is the example
In this way if user tap on anywhere of the screen excluding textInput field, keyboard will be dismissed.
There are a few ways,
if you control of event like onPress you can use:
import { Keyboard } from 'react-native'
onClickFunction = () => {
Keyboard.dismiss()
}
if you want to close the keyboard when the use scrolling:
<ScrollView keyboardDismissMode={'on-drag'}>
//content
</ScrollView>
More option is when the user clicks outside the keyboard:
<KeyboardAvoidingView behavior='padding' style={{ flex: 1}}>
//inputs and other content
</KeyboardAvoidingView>
If any one needs a working example of how to dismiss a multiline text input here ya go! Hope this helps some folks out there, the docs do not describe a way to dismiss a multiline input at all, at least there was no specific reference on how to do it. Still a noob to actually posting here on the stack, if anyone thinks this should be a reference to the actual post this snippet was written for let me know.
import React, { Component } from 'react'
import {
Keyboard,
TextInput,
TouchableOpacity,
View,
KeyboardAvoidingView,
} from 'react-native'
class App extends Component {
constructor(props) {
super(props)
this.state = {
behavior: 'position',
}
this._keyboardDismiss = this._keyboardDismiss.bind(this)
}
componentWillMount() {
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
}
componentWillUnmount() {
this.keyboardDidHideListener.remove()
}
_keyboardDidHide() {
Keyboard.dismiss()
}
render() {
return (
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={this.state.behavior}
>
<TouchableOpacity onPress={this._keyboardDidHide}>
<View>
<TextInput
style={{
color: '#000000',
paddingLeft: 15,
paddingTop: 10,
fontSize: 18,
}}
multiline={true}
textStyle={{ fontSize: '20', fontFamily: 'Montserrat-Medium' }}
placeholder="Share your Success..."
value={this.state.text}
underlineColorAndroid="transparent"
returnKeyType={'default'}
/>
</View>
</TouchableOpacity>
</KeyboardAvoidingView>
)
}
}
Updated usage of ScrollView for React Native 0.39
<ScrollView scrollEnabled={false} contentContainerStyle={{flex: 1}} />
Although, there is still a problem with two TextInput boxes. eg. A username and password form would now dismiss the keyboard when switching between inputs. Would love to get some suggestions to keep keyboard alive when switching between TextInputs while using a ScrollView.
const dismissKeyboard = require('dismissKeyboard');
dismissKeyboard(); //dismisses it
Approach No# 2;
Thanks to user #ricardo-stuven for pointing this out, there is another better way to dismiss the keyboard which you can see in the example in the react native docs.
Simple import Keyboard and call it's method dismiss()
I just tested this using the latest React Native version (0.4.2), and the keyboard is dismissed when you tap elsewhere.
And FYI: you can set a callback function to be executed when you dismiss the keyboard by assigning it to the "onEndEditing" prop.
If i'm not mistaken the latest version of React Native has solved this issue of being able to dismiss the keyboard by tapping out.
How about placing a touchable component around/beside the TextInput?
var INPUTREF = 'MyTextInput';
class TestKb extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View style={{ flex: 1, flexDirection: 'column', backgroundColor: 'blue' }}>
<View>
<TextInput ref={'MyTextInput'}
style={{
height: 40,
borderWidth: 1,
backgroundColor: 'grey'
}} ></TextInput>
</View>
<TouchableWithoutFeedback onPress={() => this.refs[INPUTREF].blur()}>
<View
style={{
flex: 1,
flexDirection: 'column',
backgroundColor: 'green'
}}
/>
</TouchableWithoutFeedback>
</View>
)
}
}
Wrap your whole component with:
import { TouchableWithoutFeedback, Keyboard } from 'react-native'
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
...
</TouchableWithoutFeedback>
Worked for me
Using KeyBoard API from react-native does the trick.
import { Keyboard } from 'react-native'
// Hide the keyboard whenever you want using !
Keyboard.dismiss()
Keyboard module is used to control keyboard events.
import { Keyboard } from 'react-native'
Add below code in render method.
render() {
return <TextInput onSubmitEditing={Keyboard.dismiss} />;
}
You can use -
Keyboard.dismiss()
static dismiss() Dismisses the active keyboard and removes focus as per react native documents.
https://facebook.github.io/react-native/docs/keyboard.html
Use
Keyboard.dismiss(0);
to hide the keyboard.
Using keyboardShouldPersistTaps in the ScrollView you can pass in "handled", which deals with the issues that people are saying comes with using the ScrollView. This is what the documentation says about using 'handled': the keyboard will not dismiss automatically when the tap was handled by a children, (or captured by an ancestor). Here is where it's referenced.
First import Keyboard
import { Keyboard } from 'react-native'
Then inside your TextInput you add Keyboard.dismiss to the onSubmitEditing prop. You should have something that looks like this:
render(){
return(
<View>
<TextInput
onSubmitEditing={Keyboard.dismiss}
/>
</View>
)
}
We can use keyboard and tochablewithoutfeedback from react-native
const DismissKeyboard = ({ children }) => (
<TouchableWithoutFeedback
onPress={() => Keyboard.dismiss()}
>
{children}
</TouchableWithoutFeedback>
);
And use it in this way:
const App = () => (
<DismissKeyboard>
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="username"
keyboardType="numeric"
/>
<TextInput
style={styles.input}
placeholder="password"
/>
</View>
</DismissKeyboard>
);
I also explained here with source code.
Use Keyboard.dismiss() to dismiss keyboard at any time.
Wrap the View component that is the parent of the TextInput in a Pressable component and then pass Keyboard. dismiss to the onPress prop. So, if the user taps anywhere outside the TextInput field, it will trigger Keyboard. dismiss, resulting in the TextInput field losing focus and the keyboard being hidden.
<Pressable onPress={Keyboard.dismiss}>
<View>
<TextInput
multiline={true}
onChangeText={onChangeText}
value={text}
placeholder={...}
/>
</View>
</Pressable>
in ScrollView use
keyboardShouldPersistTaps="handled"
This will do your job.
There are many ways you could handle this, the answers above don't include returnType as it was not included in react-native that time.
1: You can solve it by wrapping your components inside ScrollView, by default ScrollView closes the keyboard if we press somewhere. But incase you want to use ScrollView but disable this effect. you can use pointerEvent prop to scrollView
pointerEvents = 'none'.
2: If you want to close the keyboard on a button press, You can just use Keyboard from react-native
import { Keyboard } from 'react-native'
and inside onPress of that button, you can useKeyboard.dismiss()'.
3: You can also close the keyboard when you click the return key on the keyboard,
NOTE: if your keyboard type is numeric, you won't have a return key.
So, you can enable it by giving it a prop, returnKeyType to done.
or you could use onSubmitEditing={Keyboard.dismiss},It gets called whenever we press the return key. And if you want to dismiss the keyboard when losing focus, you can use onBlur prop, onBlur = {Keyboard.dismiss}
Keyboard.dismiss() will do it. But sometimes it may lose the focus and Keyboard will be unable to find the ref. The most consistent way to do is put a ref=_ref to the textInput, and do _ref.blur() when you need to dismiss, and _ref.focus() when you need to bring back the keyboard.
Here is my solution for Keyboard dismissing and scrolling to tapped TextInput (I am using ScrollView with keyboardDismissMode prop):
import React from 'react';
import {
Platform,
KeyboardAvoidingView,
ScrollView
} from 'react-native';
const DismissKeyboard = ({ children }) => {
const isAndroid = Platform.OS === 'android';
const behavior = isAndroid ? false : 'padding';
return (
<KeyboardAvoidingView
enabled
behavior={ behavior }
style={{ flex: 1}}
>
<ScrollView
keyboardShouldPersistTaps={'always'}
keyboardDismissMode={'on-drag'}
>
{ children }
</ScrollView>
</KeyboardAvoidingView>
);
};
export default DismissKeyboard;
usage:
render(){
return(
<DismissKeyboard>
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({text})}
value={this.state.text}
/>
</DismissKeyboard>
);
}

Component does not get updated after calling `this.forceUpdate();`

I am using direct manipulation to change the color of a view, every time a specific event occurs.
My render function:
render() {
return (
<View>
<View
ref={component => this._view = component}
style={{width: 50, height: 50}} />
</View>
);
My update function that is called every time a specific event occurs:
onSlideChangeHandle(index) {
this._view.backgroundColor = 'red'
this._view.forceUpdate()
}
Do I need to do something more to force the component to change the color? The method is called, and the property is updated. Unfortunately, the UI is not updated calling the force update. Do I miss something? I know I should use the state to update the components, but for this specific case I really need direct manipulation.
I found the issue. I need to update the background color using the setNativeProps.
onSlideChangeHandle(index) {
this._view.setNativeProps({ style: {
backgroundColor: 'red'
} });
}

React Native <ScrollView> persistent scrollbar

After perusing the React Native Documentation I couldn't seem to find out how to make a <ScrollView> have a persistent scrollbar that doesn't fade out. How would I achieve that?
iOS
The underlying iOS native component, UIScrollView (technically, RCTEnhancedScrollView), doesn't support keeping the scroll indicators visible. For this reason, the React Native wrapper around it won't either.
There is a hack to get this working with the native component (see this answer for one approach). To accomplish this in React Native, you'd need to implement this hack on the native side, and then either create your own Native Module or fork React Native and modify their ScrollView component.
That said, the iOS Scroll View interface guidelines discourage this, so you may want to leave the indicators' behavior alone.
Android
A few approaches:
set <item name="android:overScrollMode">always</item>,
set android:fadeScrollbars="false" in XML, or
set ScrollView.setScrollbarFadingEnabled(false) in Java (e.g. in your custom native bridge code)
This is similarly discouraged as nonstandard UI unless you have a strong reason for it.
Adding answer since none of the above worked for me.
Android now has the persistentScrollbar props.
iOS does not support this. So I created a JS solution that can be used as follows:
<SBScrollView persistentScrollbar={true}>...</SBScrollView>
Basically, this functional component will use persistentScrollbar when on Android, while add a bar when we are on iOS. It is not smooth for now, but it is functional.
// #flow
import React, {useState} from 'react';
import {Platform, View, ScrollView} from 'react-native';
type Props = {|
persistentScrollbar?: boolean,
children?: React$Node,
|} & View.propTypes;
export default function SBScrollView({
persistentScrollbar = false,
children,
...other
}: Props) {
const [nativeEvent, setNativeEvent] = useState();
if (Platform.OS === 'android' || !persistentScrollbar) {
// Abdroid supports the persistentScrollbar
return (
<ScrollView persistentScrollbar={persistentScrollbar} {...other}>
{children}
</ScrollView>
);
}
const top = nativeEvent
? nativeEvent.contentOffset.y +
(nativeEvent.contentOffset.y / nativeEvent.contentSize.height) *
nativeEvent.layoutMeasurement.height
: 0;
// iOS does not support persistentScrollbar, so
// lets simulate it with a view.
return (
<ScrollView
scrollEventThrottle={5}
showsVerticalScrollIndicator={false}
onScroll={event => setNativeEvent(event.nativeEvent)}
{...other}>
{children}
<View
style={{
position: 'absolute',
top,
right: 4,
height: 200,
width: 4,
borderRadius: 20,
backgroundColor: 'gray',
}}
/>
</ScrollView>
);
}
I hope this can help others.
I was looking for a solution but I didn't find nothing, then I created a solution, I hope can help you with it.
I created a view View with height and width and put it over my scrollview, after that I used the Props of scrollview like onMomentumScrollBegin, onMomentumScrollEnd, onContentSizeChange and onScroll
after that I make a condition with a boolean variable, if this variable is false, the View is visible, if is false the View is hide, How do I active this variable? with the Prop onMomentumScrollBegin that detect when you use the scrollView and the same way to set the variable in false with onMomentumScrollEnd that detects when the scroll ends.
The Prop onContentSizeChange allows me to get the height and width of my scrollview, this values I used to calculate where would be set the scrollbar/scrollIndicator
and finally with the Prop onScroll I get the position.
the example:
<ScrollView
onMomentumScrollBegin={() => {this.setvarScrollState()}}
onMomentumScrollEnd={() => {this.setvarScrollStateRev()}}
scrollEventThrottle={5}
onContentSizeChange={(w, h) => this.state.hScroll = h}
showsVerticalScrollIndicator={false}
onScroll={event => { this.state.wScroll = event.nativeEvent.contentOffset.y }}
style={{ marginVertical: 15, marginHorizontal:15, width: this.state.measurements3.width}}>
{
Mydata.map((value, index) => {
return <TouchableOpacity>
<Text>{ value.MyDataItem }</Text>
</TouchableOpacity>
})
}
the functions:
setvarScrollState() {
this.setState({VarScroll: true});
}
setvarScrollStateRev() {
this.setState({VarScroll: false});
}
and the variable
this.state = {VarScroll: false}
Then my condition is
!this.state.VarScroll ?
<View
style = {{
marginTop: 200*(this.state.wScroll / this.state.hScroll),
marginLeft:338.5,
height: 35,
width: 2,
backgroundColor: 'grey',
position:'absolute'
}}
/>
: null
Why 200? because is the maximum value that my marginTop can set
Check the picture
Final note:
the scrollView have to be inside a View with the another View (scrollbar)
something like this
<View>
{/*---- ScrollBar and conditions----*/}
<View>
<View>
<ScrollView>
</ScrollView>
</View>