【问题标题】:Focus style for TextInput in react-nativereact-native 中 TextInput 的焦点样式
【发布时间】:2016-03-09 08:00:49
【问题描述】:

在 React Native 中,如何在 textInput 获得焦点时更改其样式?说我有类似的东西

class MyInput extends Component {
    render () {
        return <TextInput style={styles.textInput} />;
    }
};

const stylesObj = {
    textInput: {
        height: 50,
        fontSize: 15,
        backgroundColor: 'yellow',
        color: 'black',
    }
};
const styles = StyleSheet.create(stylesObj);

我想将焦点上的背景颜色更改为green

This documentation 让我相信解决方案类似于

class MyInput extends Component {
    constructor (props) {
        super(props);
        this.state = {hasFocus: false};
    }

    render () {
        return (<TextInput
            style={this.state.hasFocus ? styles.focusedTextInput : styles.textInput}
            onFocus={this.setFocus.bind(this, true)}
            onBlur={this.setFocus.bind(this, false)}
        />);
    }

    setFocus (hasFocus) {
        this.setState({hasFocus});
    }
};

const stylesObj = {
    textInput: {
        height: 50,
        fontSize: 15,
        backgroundColor: 'yellow',
        color: 'black',
    }
};
const styles = StyleSheet.create({
    ...stylesObj,
    focusedTextInput: {
        ...stylesObj,
        backgroundColor: 'green',
    }
});

忽略样式结构中的潜在错误,这是否被认为是正确的处理方法?这对我来说似乎很冗长。

【问题讨论】:

    标签: javascript react-native


    【解决方案1】:

    您可以通过传递 onFocus 和 onBlur 事件来设置和取消设置焦点和模糊时的样式:

      onFocus() {
        this.setState({
            backgroundColor: 'green'
        })
      },
    
      onBlur() {
        this.setState({
          backgroundColor: '#ededed'
        })
      },
    

    然后,在 TextInput 中执行以下操作:

    <TextInput 
        onBlur={ () => this.onBlur() }
        onFocus={ () => this.onFocus() }
        style={{ height:60, backgroundColor: this.state.backgroundColor, color: this.state.color }}  />
    

    我已经建立了一个完整的工作项目here。我希望这会有所帮助!

    https://rnplay.org/apps/hYrKmQ

    'use strict';
    
    var React = require('react-native');
    var {
      AppRegistry,
      StyleSheet,
      Text,
      View,
      TextInput
    } = React;
    
    var SampleApp = React.createClass({
    
      getInitialState() {
        return {
            backgroundColor: '#ededed',
          color: 'white'
        }
      },
    
      onFocus() {
            this.setState({
            backgroundColor: 'green'
        })
      },
    
      onBlur() {
        this.setState({
          backgroundColor: '#ededed'
        })
      },
    
      render: function() {
        return (
          <View style={styles.container}>
           <TextInput 
            onBlur={ () => this.onBlur() }
            onFocus={ () => this.onFocus() }
            style={{ height:60, backgroundColor: this.state.backgroundColor, color: this.state.color }}  />
          </View>
        );
      }
    });
    
    var styles = StyleSheet.create({
      container: {
        flex: 1,
        marginTop:60
      }
    });
    
    AppRegistry.registerComponent('SampleApp', () => SampleApp);
    

    【讨论】:

    • 是的。这就说得通了。它本质上是相同的过程,这似乎是通向这些事情的方式
    • 你也可以(而且你应该)写 onBlur={ this.onBlur } 来防止每次调用 render() 时都会创建一个新的匿名函数
    • onBlur={ this.onBlur.bind(this) } 绑定组件,否则在方法调用中可能无法访问“this”
    • 如果视图中有多个 并且只想设置当前焦点的样式怎么办?
    • 这个解决方案似乎是一个临时解决方案,请告诉在一个屏幕上出现多个 TextInput 的情况下会发生什么,我们想为焦点和非焦点设置不同的样式
    【解决方案2】:

    使用 refs、DirectManipulation 和 setNativeProps 来提高性能:https://facebook.github.io/react-native/docs/direct-manipulation

    class MyInput extends Component {
      focusedInput = () => { 
        this.textInput.setNativeProps({
          style: { backgroundColor: 'green' }
        }) 
      }
    
      blurredInput = () => { 
        this.textInput.setNativeProps({
          style: { backgroundColor: 'yellow' }
        }) 
      }
    
      render () {
          return <TextInput 
                    ref={c => { this.textInput = c}} 
                    style={styles.textInput}
                    onFocus={this.focusedInput}
                    onBlur={this.blurredInput} />
      }
    

    }

    常量样式对象 = { 文本输入:{ 身高:50, 字体大小:15, 背景颜色:'黄色', 颜色:黑色', } }

    const 样式 = StyleSheet.create(stylesObj)

    这会直接更新 TextInput 组件,而无需重新渲染组件层次结构。

    【讨论】:

    • 这仅适用于组件中/组件上的一个 TextInput 吗?
    • @ryanwebjackson 您可以为任意数量的输入实现此功能 - 只需为每个输入分配不同的 ref。然后,您可以将 ref 名称传递给您的focusedInput 函数,并从那里调用 this[refName].setNativeProps
    【解决方案3】:

    当元素聚焦/模糊时控制样式的最佳方法是创建自己的 TextInput 包装器

    export const MyAppTextInput = (props) => {
      return (
        <TextInput
          {...props}
        />
      );
    };
    

    请注意,{...props} 将传递您已经设置或可用于 TextInput 的任何属性。

    然后通过添加状态来扩展上面的组件以在焦点/模糊时应用样式

    export const MyAppTextInput = (props) => {
      const [isFocused, setIsFocused] = useState(false);
      return (
        <TextInput
          {...props}
          style={[props.style, isFocused && {borderWidth: 5, borderColor: 'blue'}]}
          onBlur={() => setIsFocused(false)}
          onFocus={() => setIsFocused(true)}
        />
      );
    };
    

    请记住,当您使用组件绑定值时,就像示例中一样(请参阅value={passwordText});否则,随着状态更改后新的渲染开始,该值将在模糊时消失。

    <MyAppTextInput
              style={styles.input}
              value={passwordText}
              textContentType="password"
              autoCompleteType="off"
              secureTextEntry
              onChangeText={text => {
                setPasswordText(text);
              }}
            />
    

    您当然可以避免创建包装器,但如果您有多个输入,则会在您的输入父组件中造成混乱,因为您必须添加重复逻辑。

    【讨论】:

      【解决方案4】:

      您可以创建一个状态来跟踪输入状态并使用该状态来切换样式。这是一个简单的例子

      const App = () => {
        const [isActive, setActive] = useState(false);
      
        return (
          <TextInput style={{ color: isActive ? 'black' : 'grey' }} onFocus={() => setActive(true)} onBlur={() => setActive(false)}/>
        );
      }
      

      【讨论】:

        【解决方案5】:

        Nader Dabit 指示我做一些类似的事情——将状态用于样式——但我认为如果你为重点和非重点样式创建单独的样式并只传递样式 ID,它可以以更简洁的方式完成如下:

        getInitialState() {
          return { style: styles.textinput_unfocused }
        }
        onFocus() {
          this.setState({ style: styles.textinput_focused })
        }
        onBlur() {
          this.setState({ style: styles.textinput_unfocused })
        }
        

        在渲染中——通过this.state.style中的styleID引用,注意不同的样式是如何作为数组传递的:

        <TextInput 
          onBlur={ () => this.onBlur() }
          onFocus={ () => this.onFocus() }
          style={ [styles.textinput, this.state.style] }  />
        

        + 点菜样式表:

        textinput_focused: {
          backgroundColor: 'red',
          color: 'white'
        }
        textinput_unfocused: {
          backgroundColor: 'green'
        }
        

        【讨论】:

        • 如果我有 2 个 TextInputs 而一个焦点集中而另一个没有呢? style={ [styles.textinput, this.state.style] } 似乎适用于所有 TextInputs。
        • 不,动态部分仍由this.setState 设置,因此仅适用于触发事件的文本字段。给出的示例只是让一些可覆盖的基本样式保持不变,这应该是评论混乱。
        【解决方案6】:

        嘿伙计们,我有点用了每个人的想法:p

        @Felix 给了我一个可能更简洁的想法。 (我本来希望在这个静态组件上不包含状态,只是为了改变样式......但我对此很陌生。

        这是我的解决方案:

        import React, { Component } from 'react';
        import { StyleSheet, TextInput } from 'react-native';
        
        class TxtInput extends Component {
          constructor(props) {
            super(props);
            this.state = {
              style: {},
            };
          }
        
          onFocus = () => {
            const state = { ...this.state };
            state.style = {
              borderStyle: 'solid',
              borderColor: '#e74712',
            };
        
            this.setState(state);
          }
        
          onBlur = () => {
            console.log('on ONBLUR')
            const state = { ...this.state };
            state.style = {};
        
            this.setState(state);
          }
        
          render = () => <TextInput style={[styles.input, this.state.style]} onFocus={() => this.onFocus()} onBlur={() => this.onBlur()} />;
        }
        
        const styles = StyleSheet.create({
          input: {
            color: '#000000',
            fontFamily: 'MuseoSans 700 Italic',
            fontSize: 22,
            borderRadius: 34,
            borderStyle: 'solid',
            borderColor: 'transparent',
            borderWidth: 5,
            backgroundColor: '#ffffff',
            textAlign: 'center',
            width: '25%',
         },
        });
        
        export default TxtInput;
        

        我将样式添加到一个数组中,在数组的第一个属性上完成所有实际输入样式,第二个在焦点和蓝色上进行微调。

        希望对你有帮助

        【讨论】:

          【解决方案7】:
           <TextInput
           style={{ backgroundColor: 'white', height: 40, width: 100, alignItems: 'center' 
             }} 
           theme={{ colors: { placeholder: 'white', text: 'white', primary: 'white', 
            underlineColor: 'transparent', background: '#003489' } }}
             />
          

          【讨论】:

          • 您能解释一下“主题”在做什么,以及它如何改变焦点和模糊的输入样式吗?
          【解决方案8】:

          为此,我在功能组件中设计了这个简单的逻辑(它在类组件中的工作原理与相关更改相同),它可以应用于多个&lt;textinputs/&gt;。下面我举个例子:

          // state
               const [isFocused, setIsFocused] = useState({
                 name: false,
                 email: false,
                 phone: false,
               })
          // handlers
               const handleInputFocus = (textinput) => {
                 setIsFocused({
                   [textinput]: true
                 })
               }
               const handleInputBlur = (textinput) => {
                 setIsFocused({
                   [textinput]: false
                 })
               }
          // JSX
          
               <View style={styles.form} >
                  <TextInput
                    style={isFocused.name ? [styles.inputs, { borderColor: 'blue' }] : styles.inputs}
                    placeholder='Name'
                    placeholderTextColor={darkColors.text}
                    textContentType='name'
                    keyboardType='default'
                    onFocus={() => handleInputFocus('name')}
                    onBlur={() => handleInputBlur('name')}
                  />
                  <TextInput
                    style={isFocused.email ? [styles.inputs, { borderColor: 'blue' }] : styles.inputs}
                    placeholder='Email'
                    placeholderTextColor={darkColors.text}
                    textContentType='emailAddress'
                    keyboardType='email-address'
                    onFocus={() => handleInputFocus('email')}
                    onBlur={() => handleInputBlur('email')}
                  />
                  <TextInput
                    style={isFocused.phone ? [styles.inputs, { borderColor: 'blue' }] : styles.inputs}
                    placeholder='Phone'
                    placeholderTextColor={darkColors.text}
                    keyboardType='phone-pad'
                    onFocus={() => handleInputFocus('phone')}
                    onBlur={() => handleInputBlur('phone')}
                  />
                </View>
          

          【讨论】:

            【解决方案9】:

            在函数组件中设置初始值

            const [warnColor, setWrnColor] = useState("grey");

            在文本输入中设置

            style={[styles.brdColor, { borderColor: warnColor }]}

            在样式表中设置

             brdColor: {
                height: 40,
                borderColor: "grey",
                borderBottomWidth: 1,
                marginTop: heightToDp("2%"),
                width: "100%",
              }
            

            【讨论】:

              猜你喜欢
              • 2020-06-06
              • 1970-01-01
              • 1970-01-01
              • 2016-11-08
              • 1970-01-01
              • 2018-08-07
              • 2021-06-30
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多