You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native实现带区号选择器的手机号输入UI及自定义键盘需求

解决方案

一、调整react-native-phone-number-input的UI样式

默认组件支持通过多维度样式属性自定义各部分外观,你可以针对国家选择按钮、区号文本、输入容器分别设置样式,匹配目标UI:

import PhoneInput from 'react-native-phone-number-input';
import { useState } from 'react';
import { StyleSheet, View, TouchableOpacity } from 'react-native';

// 组件内部状态
const [phoneNumber, setPhoneNumber] = useState('');
const [countryCode, setCountryCode] = useState('AE');
const [isKeyboardVisible, setIsKeyboardVisible] = useState(false);

// 渲染输入框
<PhoneInput
  defaultValue={phoneNumber}
  defaultCode={countryCode}
  onChangeFormattedText={(text) => setPhoneNumber(text)}
  onChangeCountry={(country) => setCountryCode(country.cca2)}
  containerStyle={styles.phoneContainer}
  textContainerStyle={styles.textContainer}
  codeTextStyle={styles.codeText}
  flagButtonStyle={styles.flagButton}
  textInputProps={{
    editable: false, // 禁用系统输入,避免弹出默认键盘
    showSoftInputOnFocus: false,
  }}
  onPress={() => setIsKeyboardVisible(true)} // 点击触发自定义键盘显示
/>

对应的样式定义:

const styles = StyleSheet.create({
  phoneContainer: {
    width: '80%',
    height: 65,
    backgroundColor: '#fff', // 按目标UI调整背景色
    borderColor: '#ccc',
    borderWidth: 1,
    borderRadius: 8,
    flexDirection: 'row',
    alignItems: 'center',
    paddingHorizontal: 10,
  },
  textContainer: {
    flex: 1,
    marginLeft: 10,
    borderWidth: 0, // 移除默认输入框边框
  },
  codeText: {
    fontSize: 16,
    fontWeight: '500',
    color: '#333',
  },
  flagButton: {
    padding: 0,
  },
});

二、实现自定义数字键盘

封装一个独立的数字键盘组件,通过状态控制显示/隐藏,点击按键时更新手机号并保持格式化:

const CustomNumberKeyboard = ({ onNumberPress, onDeletePress, onClose }) => {
  const numbers = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '', '0', '⌫'];

  return (
    <View style={styles.keyboardContainer}>
      <TouchableOpacity onPress={onClose} style={styles.closeButton}>
        <Text>完成</Text>
      </TouchableOpacity>
      <View style={styles.keyboardGrid}>
        {numbers.map((num, index) => (
          <TouchableOpacity
            key={index}
            style={styles.keyButton}
            onPress={() => {
              if (num === '⌫') {
                onDeletePress();
              } else if (num) {
                onNumberPress(num);
              }
            }}
          >
            <Text style={styles.keyText}>{num}</Text>
          </TouchableOpacity>
        ))}
      </View>
    </View>
  );
};

// 键盘样式
const styles = StyleSheet.create({
  keyboardContainer: {
    position: 'absolute',
    bottom: 0,
    left: 0,
    right: 0,
    backgroundColor: '#fff',
    borderTopWidth: 1,
    borderTopColor: '#eee',
    paddingVertical: 20,
  },
  closeButton: {
    alignSelf: 'flex-end',
    paddingRight: 20,
    paddingBottom: 10,
  },
  keyboardGrid: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    justifyContent: 'center',
  },
  keyButton: {
    width: '30%',
    height: 60,
    alignItems: 'center',
    justifyContent: 'center',
    marginVertical: 5,
  },
  keyText: {
    fontSize: 20,
    fontWeight: 'bold',
    color: '#333',
  },
});

三、整合组件并处理手机号格式化

使用react-native-phone-number-input提供的parsePhoneNumber工具,确保输入的手机号符合对应国家的格式规范:

import { parsePhoneNumber } from 'react-native-phone-number-input';

// 处理数字按键点击
const handleNumberPress = (num) => {
  const newNumber = phoneNumber + num;
  try {
    const parsed = parsePhoneNumber(newNumber, countryCode);
    setPhoneNumber(parsed?.formattedNumber || newNumber);
  } catch (e) {
    setPhoneNumber(newNumber);
  }
};

// 处理删除按键点击
const handleDeletePress = () => {
  if (phoneNumber.length === 0) return;
  const newNumber = phoneNumber.slice(0, -1);
  try {
    const parsed = parsePhoneNumber(newNumber, countryCode);
    setPhoneNumber(parsed?.formattedNumber || newNumber);
  } catch (e) {
    setPhoneNumber(newNumber);
  }
};

// 在render中整合输入框与键盘
return (
  <View style={styles.container}>
    {/* 手机号输入框 */}
    <PhoneInput
      // 上述配置属性
    />
    {/* 自定义数字键盘 */}
    {isKeyboardVisible && (
      <CustomNumberKeyboard
        onNumberPress={handleNumberPress}
        onDeletePress={handleDeletePress}
        onClose={() => setIsKeyboardVisible(false)}
      />
    )}
  </View>
);

四、替代方案:完全自定义输入组件

如果react-native-phone-number-input的样式限制过多,可以拆分实现:

  • 用react-native-country-picker-modal做国家选择器
  • 自定义文本显示区域替代输入框
  • 搭配上述自定义数字键盘

示例代码:

import CountryPicker from 'react-native-country-picker-modal';

// 组件内部状态
const [country, setCountry] = useState({ cca2: 'AE', callingCode: '971' });

// 渲染自定义输入组件
<View style={styles.customPhoneInput}>
  <CountryPicker
    countryCode={country.cca2}
    onSelect={(selectedCountry) => setCountry(selectedCountry)}
    withCallingCode
    withFlag
    containerButtonStyle={styles.countryPickerButton}
  />
  <TouchableOpacity
    style={styles.phoneDisplay}
    onPress={() => setIsKeyboardVisible(true)}
  >
    <Text style={styles.phoneText}>{phoneNumber || '请输入手机号'}</Text>
  </TouchableOpacity>
</View>

// 对应样式
const styles = StyleSheet.create({
  customPhoneInput: {
    width: '80%',
    height: 65,
    flexDirection: 'row',
    alignItems: 'center',
    borderColor: '#ccc',
    borderWidth: 1,
    borderRadius: 8,
    paddingHorizontal: 10,
  },
  countryPickerButton: {
    padding: 0,
    width: 80,
  },
  phoneDisplay: {
    flex: 1,
    height: '100%',
    justifyContent: 'center',
    marginLeft: 10,
  },
  phoneText: {
    fontSize: 16,
    color: '#333',
  },
});

这种方式可以完全控制UI的每一部分,更灵活匹配目标设计。

内容的提问来源于stack exchange,提问作者Anjali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 16:37:45