React Native ios picker is always open
Asked Answered
T

8

46

I have two pickers on my screen. Whenever I navigate to the screen in iOS app I find that the pickers are always open and all options are visible.

enter image description here

It works perfectly fine in Android where the options are visible only after we click on the picker.

Can somebody suggest a solution to fix this in iOS?

Tipsy answered 16/12, 2016 at 9:58 Comment(2)
How can I remove the picker lineMealymouthed
You can, only for iOS, show the selected value as touchable text which when touched make the picker visible. Then hide the picker again after choose an item.Supercool
T
27

Use ActionSheet instead of Picker on iOS. https://facebook.github.io/react-native/docs/actionsheetios

As answered by jevakallio this is the default behaviour on iOS. But this doesn't give a good UX so remove all picker components and replace with ActionSheet.

I did and it works great. The reason I preferred ActionSheet over other components suggested by jevakallio because it is developed by the RN team and has a good native feeling. The last option suggested react-native-modal-picker is also very good.

enter image description here

Tipsy answered 21/12, 2016 at 4:49 Comment(3)
ActionSheet shouldn't be reserved for actions?Jewbaiting
You can use github.com/peacechen/react-native-modal-selector also. It won't give a native picker but would give a consistent feeling on both the platform.Zingaro
Okay, but what about a Picker with dozens of options (like language selection)? This is not a safe drop in replacement. This is a completely different component.Mabellemable
M
13

That's just how the iOS UIPickerView component works - there's no way to customize it.

If you want a different kind of UI element, you'll need to write your own, or use one of the many open source libraries, such as:

Googling with these, and similar keywords, yields many other libraries as well.

Malpighiaceous answered 16/12, 2016 at 15:25 Comment(1)
Useful. but using action sheet for a long list of data cannot be preferred. And in react-native-modal-picker/ react-native-modal-selector there remains an extra padding at the bottom. Could nt find a perfect solution for this yet.Homeless
S
12

I don't know why you'd choose the answer with ActionSheet as accepted answer. However I'll give a workaround for this problem:

Put this values in your state:

this.state= {
    pickerOpacity: 0,
    opacityOfOtherItems: 1 //THIS IS THE OPACITY OF ALL OTHER ITEMS, WHICH COLLIDES WITH YOUR PICKER.
    label: 'Firstvalue'
}

In your render method do following:

{this.checkIfIOS()}
      <Picker
         selectedValue={this.state.selected}
         style={{ height: 50, alignSelf: 'center', opacity: this.state.pickerOpacity, marginBottom:30, width: 250}}
         onValueChange={(itemValue, itemIndex) =>{
            this.setState({
                selected: itemValue,
                label: itemValue
            });
            toggle();
            }
          }>
          <Picker.Item label="Your Label" value="yourValue"/>
      </Picker>

So now we've to check, whether our client is android or ios. Therefore import Platform and put the checkIfIos()-Method in your code:

import {Platform} from 'react-native'

checkIfIOS(){
        if(Platform.OS === 'ios'){ // check if ios
            console.log("IOS!!!");
            //this button will (onpress) set our picker visible
            return (<Button buttonStyle={{backgroundColor:'#D1D1D1', opacity: this.state.opacityOfOtherItems}} onPress={this.toggle()} color="#101010" title={this.state.label} onPress={this.changeOpacity}/>); 
        }else if(Platform.OS === 'android'){ //check if android
            this.setState({
                pickerOpacity: 1 //set picker opacity:1 -> picker is visible.
            });
            console.log("ANDROID!!!");
        }
    }

toggle(){
    if(Platform.OS === 'ios'){

        if(this.state.pickerOpacity == 0){
            this.setState({
                pickerOpacity: 1,
                opacityOfOtherItems: 0 // THIS WILL HIDE YOUR BUTTON!
            });
         }else{
             this.setState({
                 pickerOpacity: 0,
                 opacityOfOtherItems: 1
             });
          }
     }
}

EDIT: Screenshot with iOS (Click here for Video)

Screenshot of DatePicker with iOS

Slog answered 29/8, 2018 at 11:46 Comment(8)
do you maybe have an expo snack of this? I'm having a hard time implementing this and I'm not even sure if it works.Dykes
Unfortunately not. You just have to put the toggle() & checkIfIOS() methods and run the checkIfOs before the rendering your picker and use the toggle() method in your pickers onValueChange event. If you could provide your view, can help you how to implement it.Slog
@SercanSametSavran can you please provide a screen shots of the picker? How does the button looks like in the view? It appears that the implementation of this.changeOpacity() is missingOvercautious
Can you provide us please with a screenshot on IOS ?Mycosis
Sorry for late answer. But I did something better and uploaded a video, where you can see the datepicker in action (ios). There you go: streamable.com/pzaioSlog
Share your code please. How do you actívate the picker?Somatotype
@Somatotype My code is already there, you have to use the toggle()-method to activate/deactivate the picker.Slog
This is by far the best solution and should be the accepted answer.Supercool
L
7

React-native-modal-picker was discontinued. react-native-modal-selector

Luminescence answered 1/3, 2018 at 17:38 Comment(0)
A
7

use

<Picker itemStyle={{height:50}} > </Picker>

it only affect ios picker. change picker itemstyle height to your standard.

Abubekr answered 15/11, 2020 at 15:32 Comment(1)
Actually that was the trick for me so I don't need to use alternatives ! ThanksMorality
T
2

Extending the ActionSheetIOS answer, I created a custom component that is a drop-in replacement for Picker (I'm using Button from https://react-native-elements.github.io/react-native-elements/docs/overview.html):

import React from 'react';
import { ActionSheetIOS, Platform } from 'react-native';
import { Button } from 'react-native-elements';

class PickerDropDown extends React.Component {
  onIOSButton = () => {
    let options = this.props.children.map((item, i) => {
      return item.props.label;
    });
    options.push("Cancel");
    ActionSheetIOS.showActionSheetWithOptions(
      {
        options: options,
        cancelButtonIndex: options.length - 1,
      },
      this.onIOSButtonPick
    );
  }

  onIOSButtonPick = (buttonIndex) => {
    if (buttonIndex < this.props.children.length && buttonIndex != this.props.selectedValue) {
      if (typeof this.props.selectedValue === 'undefined' || (typeof this.props.selectedValue !== 'undefined' && buttonIndex != this.findIndexForValue(this.props.selectedValue))) {
        this.props.onValueChange(this.props.children[buttonIndex].props.value, buttonIndex);
      }
    }
  }

  findLabelForValue = (searchValue) => {
    for (let i = 0; i < this.props.children.length; i++) {
      if (this.props.children[i].props.value == searchValue) {
        return this.props.children[i].props.label;
      }
    }
    return null;
  }

  findIndexForValue = (searchValue) => {
    for (let i = 0; i < this.props.children.length; i++) {
      if (this.props.children[i].props.value == searchValue) {
        return i;
      }
    }
    return -1;
  }

  render() {
    if (Platform.OS === "ios") {
      let title = "";
      if (this.props.children && this.props.children.length > 0) {
        if (typeof this.props.selectedValue !== 'undefined') {
          title = this.findLabelForValue(this.props.selectedValue);
        } else {
          title = this.props.children[0].props.label;
        }
      }
      return (
      <View>
        <Button
          title={title}
          onPress={this.onIOSButton}
          type="clear"
          icon={{
            name: "arrow-drop-down",
            size: 15,
            color: "black"
          }}
          iconRight={true}
        />
     </View>
      );
    } else {
      return (
        <Picker {...this.props} />
      );
    }
  }
}
Towner answered 19/11, 2019 at 6:21 Comment(5)
What does it look like? a video or snapshot pleaseJunji
I used this and worked. Just that it is not using full available width like PickerJunji
I wrapped it in a <View> and set the style prop on it. Styles on react-native-elements button were not applying.Junji
Best answer. This solution uses native picker as much possible with little code. And the dropin replacement is quick to implement.Junji
I used this class to great effect, with some small changes for styling, wrapped it in a <View> as suggested by @IsmailS, and published it to a Gist: gist.github.com/thargenediad/7615e281baab25733ca0e7f5c7cb97d6 I hope it helps someone save time trying to style Kevin's component. Enjoy!Lambertson
K
1

react-native-dropdown has reference bugs If you don't want to use Action Sheets but a 'real' picker, this one I found is way better...

https://github.com/lawnstarter/react-native-picker-select

Kaylil answered 7/11, 2020 at 12:12 Comment(0)
K
-3

import from native-base library instead of react-native

Kura answered 2/1, 2020 at 11:18 Comment(1)
The problem is with react native picker element, and third party libraries like native-base is not we are looking forAreaway

© 2022 - 2024 — McMap. All rights reserved.