[ 卡卡 DAY 25 ] - React Native 手机装置 keyboard 问题之 右下角的 next and go 设定

一个表单没有良好的 keyboard 操作,怎麽能说是一个好表单!!!!
接续 Day23 + Day24
到目前为止遇到三个问题 :

  1. 键盘上的 next go 要做什麽用呢?
  2. 刻完画面竟然被键盘挡住了 :(
  3. 人家键盘都可以自己收起来 我为什麽不行?

今天来处理 keyboard 右下角的 next and go 设定

前情提要

前两天的表单页面让我们来前让我们来前情提要一下吧~

还记得 TextInput 中有两个 props returnKeyType and returnKeyLabel?知道这是什麽意思吗?

有几个选项可以放在里面分别为 cross-platform 跟一些符合 OS-specific.像是 email input 里我们写上"next" 这个选项,他的意思是他会将 focus 移动到下一个 input,"go" 这个选项会启动 submit 的 function,而这些事件需要另外来写,所以就是我们今天所要学习的项目唷!

<Input
    label='mail'
    placeholder='Enter your email'
    autoCapitalize='none'
    autoCompleteType='email'
    keyboardType='email-address'
    keyboardAppearance='dark'
    // here
    returnKeyType='next'
    returnKeyLabel='next'
/>

开始配置

  1. 於 screens/ Formik.js 引入 useRef 并且给与 ref 初始值 null
import React, { useRef } from 'react';

const phone = useRef(null);
const email = useRef(null);
// 只有第一个input不需要

  1. 於 returnKeyType and returnKeyLabel 为 next 的部分设定,如下:
<Input
    // ...
    label='Name'
    returnKeyType='next'
    returnKeyLabel='next'
    // 加入
    onSubmitEditing={() => mail.current?.focus()}
/>
<Input
    // 加入
    ref={mail}
    label='Mail'
    // ...
    returnKeyType='next'
    returnKeyLabel='next'
    // 加入
    onSubmitEditing={() => phone.current?.focus()}
/>
<Input
    // 加入
    ref={phone}
    label="Phone"
    // ...
    returnKeyType='next'
    returnKeyLabel='next'
/>

接着你会发现 simulator 为 warning,这是因为我们的 Input 是客制的,所以我们需要做一些处理。

  1. 引入 forwardRef 於 components/ Input.js
    forwardRef 是一个自动将 ref 传给一个 children component 的技术,而我的现在需要的就是将 ref 从 Formik.js 传递到 Input.

    import React, { forwardRef } from 'react';
    

    使用 forwardRef 包起所有的 Input functional component,完整的 code 如下:

     import React, {forwardRef} from 'react';
     import {TextInput as RNTextInput, View, StyleSheet, Text} from 'react-native';
    
     const Input =
      // forwardRef 包起来 start
      forwardRef(
         ({label, error, touched, ...otherProps}, ref) => {
         const validationColor = !touched ? '#223e4b' : error ? '#FF5A5F' : '#223e4b';
             return (
             <View style={[styles.input, {borderColor: validationColor}]}>
                 <View style={{padding: 8}}>
                     <Text>{label}</Text>
                 </View>
                 <View style={{flex: 1}}>
                     <RNTextInput
                         underlineColorAndroid="transparent"
                         placeholderTextColor="#ccc"
                         // 加入 ref
                         ref={ref}
                         {...otherProps}
                     />
                 </View>
             </View>
             );
         }
       );
      // forwardRef 包起来 end
    
    const styles = StyleSheet.create({
     input: {
     flexDirection: 'row',
     alignItems: 'center',
     height: 48,
     borderRadius: 8,
     borderWidth: StyleSheet.hairlineWidth,
     padding: 8,
     marginVertical: 10,
     },
    });
    export default Input;
    

    现在按下 "next" 按钮,他将会 focus 下一个 input!

GIF

上面处理好 "next" 按钮,现在来处理"go"按钮

  1. 於 returnKeyType and returnKeyLabel 为 go 的部分设定,如下:
    在 screens/ Formik.js 中加入
onSubmitEditing={() => handleSubmit()}

最後贴上完整的 screens/ Formik.js

import React, {useRef} from 'react';
import {StyleSheet, View, Text, ScrollView} from 'react-native';

import {fonts} from '@src/constants';
import {useFormik} from 'formik';
import Input from '../components/Input';
import Button from '../components/Button';
import {object as yupObject, string as yupString, ValidationError} from 'yup';

const Formik = () => {
  const phone = useRef(null);
  const email = useRef(null);
  const phoneRegExp =
    /^((\\+[1-9]{1,4}[ \\-]*)|(\\([0-9]{2,3}\\)[ \\-]*)|([0-9]{2,4})[ \\-]*)*?[0-9]{3,4}?[ \\-]*[0-9]{3,4}?$/;

  const Schema = yupObject().shape({
    name: yupString().required('Required'),
    email: yupString().email('Invalid email').required('Required'),
    phone: yupString()
      .matches(phoneRegExp, 'Phone number is not valid')
      .required('Required'),
  });
  const {handleChange, handleSubmit, handleBlur, values, errors, touched} =
    useFormik({
      validationSchema: Schema,
      initialValues: {name: '', email: '', phone: ''},
      onSubmit: values =>
        alert(
          `Name: ${values.name},Email: ${values.email}, phone: ${values.phone}`,
        ),
    });
  return (
    <ScrollView style={styles.container}>
      <View style={styles.textBox}>
        <Text style={[styles.text, fonts.h1]}>欢迎来到卡卡塔罗</Text>
        <Text style={(fonts.p, styles.textContent)}>
          如果您有什麽需要或着回馈欢迎留言也或着想预约算塔罗牌也欢迎留言,谢谢您
        </Text>
      </View>

      <View style={styles.formBox}>
        <Input
          onChangeText={handleChange('name')}
          label="Name"
          placeholder="Enter your name"
          autoCapitalize="none"
          autoCompleteType="email"
          keyboardType="default"
          keyboardAppearance="dark"
          onBlur={handleBlur('name')}
          error={errors.name}
          touched={touched.name}
          returnKeyType="next"
          returnKeyLabel="next"
          onSubmitEditing={() => email.current?.focus()}
        />
        <Input
          ref={email}
          onChangeText={handleChange('email')}
          label="Mail"
          placeholder="Enter your email"
          autoCapitalize="none"
          autoCompleteType="email"
          keyboardType="email-address"
          keyboardAppearance="dark"
          onBlur={handleBlur('email')}
          error={errors.email}
          touched={touched.email}
          returnKeyType="next"
          returnKeyLabel="next"
          onSubmitEditing={() => phone.current?.focus()}
        />
        <Input
          ref={phone}
          onChangeText={handleChange('phone')}
          label="Phone"
          placeholder="Enter your phone"
          autoCompleteType="phone-pad"
          autoCapitalize="none"
          keyboardAppearance="dark"
          onBlur={handleBlur('phone')}
          error={errors.phone}
          touched={touched.phone}
          returnKeyType="go"
          returnKeyLabel="go"
          onSubmitEditing={() => handleSubmit()}
        />
        <Button label="submit" color="maroon" onPress={handleSubmit} />
      </View>
    </ScrollView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'rgb(246,246,246)',
    paddingHorizontal: 20,
  },
  textBox: {
    justifyContent: 'center',
    alignItems: 'center',
    paddingVertical: 50,
  },
  textTitle: {color: '#aaa'},
  textContent: {color: '#aaa', lineHeight: 20, marginTop: 10},
  formBox: {
    width: '100%',
    alignItems: 'center',
    justifyContent: 'center',
  },
  input: {
    width: '100%',
    textAlign: 'center',
    borderWidth: 1,
    borderColor: '#ddd',
    padding: 10,
    fontSize: 18,
    margin: 10,
  },
  errorText: {
    textAlign: 'center',
    color: 'crimson',
    marginBottom: 10,
  },
});

export default Formik;

gif

formik and yup 到一段落,表单来个结论

Formik 搭配 Yup 的验证是一个简单又容易了解的方法,Formik 的不断的更新连 Hook 的方式都有!Yup API 也提供了很多验证给表单元件!以及最後教使用 ref 来控制 keyboard,虽然这个设定并不是必须的,但这样一用,感觉也提高了使用者的体验!

到现在有没有发现
下一章节就继续来解决 keyboard 系列的问题噜!

Day 25 done~~~ 请多多指教


<<:  DAY 28 Image message(图片讯息)

>>:  DAY 28『 使用相机拍照 』 ImagePicker - Part2

Day5: [资料结构] - Map

Map是JavaScript ES6中新增的资料结构 ,类似於object ,不过Map还是跟ob...

Day 30 | ContentProvider

可以使用ContentProvider将资料库分享给其他应用程序共享资讯,或从其他应用程序操作资料 ...

分布式可观测性 Logging 浅谈

小弟我在去年有分享了 Distributed Tracing 分布式链路追踪简介 主要讲到Distr...

[ Day 4 ] - 阵列基本介绍

阵列的基本介绍 简单来说是存放一组资料集 阵列 会使用 [ ] 前後包住资料集 下面的范例意思是 d...

冒险村17 - Configatron

17 - Configatron Rails 内时常会用到共用的连结、字串、数字等 config,除...