- vừa được xem lúc

Phân tích plugin React Native Unsigned Input: Giải pháp nhập liệu không dấu cho bàn phím Vietnamese

0 0 9

Người đăng: DUY TRAN

Theo Viblo Asia

Xin chào các bạn, hôm nay chúng ta sẽ cùng nhau phân tích một plugin rất hữu ích cho các ứng dụng React Native - @tdduydev/react-native-unsigned-input. Plugin này giúp đơn giản hóa việc nhập liệu số không dấu trong các ứng dụng React Native. Hãy cùng tìm hiểu về tính năng, cách sử dụng, ưu điểm và nhược điểm của plugin này nhé!

1. Giới thiệu về @tdduydev/react-native-unsigned-input

  • Trong các ứng dụng di động, việc nhập liệu số không dấu là một yêu cầu phổ biến. Tuy nhiên, việc xử lý nhập liệu này trong React Native có thể gặp một số khó khăn. Để giải quyết vấn đề này, '@tdduydev/react-native-unsigned-input' đã được phát triển.

  • Plugin này cung cấp một thành phần nhập liệu dựa trên TextInput của React Native, giúp giới hạn việc nhập liệu chỉ gồm các ký tự số không dấu. Điều này đồng nghĩa với việc người dùng chỉ có thể nhập các giá trị số dương và không thể nhập các ký tự không phải số.

2. Cách sử dụng plugin

Để bắt đầu sử dụng plugin này, bạn cần cài đặt nó vào dự án React Native của bạn:

npm install @tdduydev/react-native-unsigned-input

Sau khi cài đặt xong, bạn có thể sử dụng thành phần UnsignedInput trong dự án của mình như sau:

import React from 'react';
import { View } from 'react-native';
import UnsignedInput from '@tdduydev/react-native-unsigned-input'; const App = () => { return ( <View> <UnsignedInput /> </View> );
}; export default App;

3. Ưu điểm của plugin

  • Dễ dàng sử dụng: Chỉ cần cài đặt và sử dụng thành phần UnsignedInput trong dự án của bạn.
  • Tích hợp nhanh chóng: Plugin được phát triển dựa trên TextInput của React Native, giúp tích hợp dễ dàng vào các ứng dụng hiện có.
  • Tiết kiệm thời gian: Giảm bớt công việc liên quan đến xử lý nhập liệu số không dấu.

4. Nhược điểm

  • Chưa hỗ trợ đa ngôn ngữ: Nếu ứng dụng của bạn cần hỗ trợ đa ngôn ngữ, bạn cần tự thêm tính năng này.
  • Tùy chỉnh giới hạn: Plugin chỉ hỗ trợ nhập liệu số không dấu, nếu bạn muốn tùy chỉnh giới hạn nhập liệu (ví dụ: chỉ cho phép nhập số lớn hơn 10), bạn sẽ phải thực hiện điều này bằng cách sửa mã nguồn hoặc thêm các xử lý bổ sung.

5. Một số ví dụ về tùy chỉnh plugin

Ví dụ 1: Thêm placeholder và kiểu nhập liệu

import React from 'react';
import { View } from 'react-native';
import UnsignedInput from '@tdduydev/react-native-unsigned-input'; const App = () => { return ( <View> <UnsignedInput placeholder="Nhập số không dấu" keyboardType="number-pad" /> </View> );
}; export default App;

Ví dụ 2: Thêm sự kiện thay đổi giá trị và xử lý nhập liệu

import React, { useState } from 'react';
import { View, Text } from 'react-native';
import UnsignedInput from '@tdduydev/react-native-unsigned-input'; const App = () => { const [value, setValue] = useState(''); const handleChange = (text) => { setValue(text); }; return ( <View> <UnsignedInput onChangeText={handleChange} /> <Text>Giá trị nhập: {value}</Text> </View> );
}; export default App;

6. Phân tích sâu về code của native ios và native android

native ios

//
// ReactNativeUnsignedDelegate.m
// UnsignedInput
//
// Created by DUY TRAN on 27/03/2023.
// Copyright © 2023 Facebook. All rights reserved.
// #import <UIKit/UIKit.h> @protocol InputListener <UITextFieldDelegate>
@end @interface ReactNativeUnsignedDelegate : NSObject <UITextFieldDelegate> @property (nonatomic, weak) id<InputListener> listener;
@property (nonatomic, copy) void (^onChange)(UITextField *textField, NSString *value); - (instancetype)initWithListener:(id<InputListener>)listener onChange:(void (^)(UITextField *textField, NSString *value))onChange; @end @implementation ReactNativeUnsignedDelegate - (instancetype)initWithListener:(id<InputListener>)listener onChange:(void (^)(UITextField *textField, NSString *value))onChange { self = [super init]; if (self) { _listener = listener; _onChange = onChange; } return self;
} - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { // Chuẩn hóa chuỗi nhập vào bằng cách loại bỏ dấu tiếng Việt và khoảng trắng NSString *normalizedString = [[[string decomposedStringWithCanonicalMapping] stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:[NSLocale currentLocale]] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; // Thay thế chuỗi nhập vào bằng chuỗi đã được chuẩn hóa textField.text = [textField.text stringByReplacingCharactersInRange:range withString:normalizedString]; self.onChange(textField,textField.text); return NO;
} // MARK: default RNTextInput handlers
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { return [self.listener respondsToSelector:@selector(textFieldShouldBeginEditing:)] ? [self.listener textFieldShouldBeginEditing:textField] : YES;
} - (void)textFieldDidBeginEditing:(UITextField *)textField { [self.listener textFieldDidBeginEditing:textField];
} - (BOOL)textFieldShouldEndEditing:(UITextField *)textField { return [self.listener respondsToSelector:@selector(textFieldShouldEndEditing:)] ? [self.listener textFieldShouldEndEditing:textField] : YES;
} - (void)textFieldDidEndEditing:(UITextField *)textField { [self.listener textFieldDidEndEditing:textField];
} - (void)textFieldDidEndEditing:(UITextField *)textField reason:(UITextFieldDidEndEditingReason)reason API_AVAILABLE(ios(10.0)) { if ([self.listener respondsToSelector:@selector(textFieldDidEndEditing:reason:)]) { [self.listener textFieldDidEndEditing:textField reason:reason]; } else { [self.listener textFieldDidEndEditing:textField]; }
} @end 
  1. Khai báo và import thư viện:
#import <UIKit/UIKit.h>

Thư viện UIKit được import để sử dụng các thành phần UI của iOS.

  1. Khai báo giao diện InputListener:
@protocol InputListener <UITextFieldDelegate>
@end

Giao diện InputListener kế thừa từ UITextFieldDelegate, cho phép xử lý các sự kiện liên quan đến UITextField.

  1. Khai báo lớp ReactNativeUnsignedDelegate:
@interface ReactNativeUnsignedDelegate : NSObject <UITextFieldDelegate> @property (nonatomic, weak) id<InputListener> listener;
@property (nonatomic, copy) void (^onChange)(UITextField *textField, NSString *value); - (instancetype)initWithListener:(id<InputListener>)listener onChange:(void (^)(UITextField *textField, NSString *value))onChange; @end 

Lớp ReactNativeUnsignedDelegate kế thừa từ NSObject và tuân thủ giao diện UITextFieldDelegate. Lớp này có hai thuộc tính

  • listener: Một đối tượng tuân thủ giao diện InputListener, giúp xử lý các sự kiện của UITextField.
  • onChange: Một block được gọi khi giá trị của UITextField thay đổi.

Lớp này cũng có một phương thức khởi tạo initWithListener:onChange.

  1. Thực thi lớp ReactNativeUnsignedDelegate:
@implementation ReactNativeUnsignedDelegate

Phần này chứa các phương thức được gọi khi xử lý sự kiện của UITextField.

  1. Phương thức khởi tạo initWithListener:onChange:
- (instancetype)initWithListener:(id<InputListener>)listener onChange:(void (^)(UITextField *textField, NSString *value))onChange { self = [super init]; if (self) { _listener = listener; _onChange = onChange; } return self;
}

Phương thức này khởi tạo một đối tượng của lớp ReactNativeUnsignedDelegate với đối số listener và block onChange.

  1. Phương thức textField:shouldChangeCharactersInRange:replacementString:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 

Phương thức này được gọi khi có sự thay đổi ký tự trong UITextField. Nó chuẩn hóa chuỗi nhập vào bằng cách loại bỏ dấu tiếng Việt và khoảng trắng, sau đó thay thế chuỗi nhập vào bằng chuỗi đã được chuẩn hóa.

  1. Các phương thức xử lý sự kiện của UITextField:

Phần này chứa các phương thức xử lý sự kiện của UITextField,như textFieldShouldBeginEditing, textFieldDidBeginEditing, textFieldShouldEndEditing, textFieldDidEndEditingtextFieldDidEndEditing:reason. Các phương thức này được gọi khi có các sự kiện liên quan đến việc bắt đầu và kết thúc nhập liệu của UITextField.

Ví dụ:

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { return [self.listener respondsToSelector:@selector(textFieldShouldBeginEditing:)] ? [self.listener textFieldShouldBeginEditing:textField] : YES;
}

Phương thức textFieldShouldBeginEditing kiểm tra xem listener có thực hiện phương thức textFieldShouldBeginEditing hay không. Nếu có, phương thức này sẽ gọi textFieldShouldBeginEditing của listener, ngược lại trả về YES.

  1. Kết thúc cài đặt lớp ReactNativeUnsignedDelegate:

Tóm lại, đoạn mã trên là một file mã nguồn Objective-C được sử dụng trong ứng dụng React Native để hỗ trợ việc nhập liệu số không dấu. Nó tạo ra một lớp tuân thủ giao diện UITextFieldDelegate để xử lý các sự kiện của UITextField, giúp chuẩn hóa chuỗi nhập vào bằng cách loại bỏ dấu tiếng Việt và khoảng trắng.

native android

  1. Khai báo package và import các thư viện cần thiết:
import android.text.InputType
import android.text.TextWatcher
import android.widget.EditText
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.uimanager.UIManagerModule
  1. Khai báo lớp ReactNativeUnsignedInputModule:
class ReactNativeUnsignedInputModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) 

Lớp ReactNativeUnsignedInputModule kế thừa từ ReactContextBaseJavaModule và nhận một tham số reactContext kiểu ReactApplicationContext.

  1. Override phương thức getName():
override fun getName(): String { return NAME
}

Phương thức này trả về tên của module, trong trường hợp này là ReactNativeUnsignedInput.

  1. Khởi tạo và quản lý listeners:
private val listeners = hashMapOf<String, TextWatcher?>()

listeners là một HashMap chứa các TextWatcher dùng để lắng nghe sự kiện thay đổi của EditText.

  1. Phương thức applyUnsigned(reactNode: Int):
@ReactMethod
fun applyUnsigned(reactNode: Int) { ...
}

Phương thức này được đánh dấu là @ReactMethod, cho phép gọi từ mã JavaScript của React Native. Phương thức này nhận vào reactNode là ID của EditText cần áp dụng nhập liệu số không dấu.

  1. Thêm UnsignedTextWatcher vào EditText:
val editText = viewRegistry.resolveView(reactNode) as EditText
val listener = UnsignedTextWatcher(editText)
listeners.set(getKey(reactNode), listener)
editText.addTextChangedListener(listener)

Phần mã này lấy ra đối tượng EditText từ viewRegistry, khởi tạo một UnsignedTextWatcher, lưu vào listeners, và thêm vào EditText để lắng nghe sự kiện thay đổi.

  1. Phương thức getKey(reactNode: Int):
private fun getKey(reactNode: Int): String { return reactNode.toString()
}

Phương thức này chuyển đổi reactNode (kiểu Int) thành chuỗi và trả về để sử dụng làm key cho listeners.

Full-code

package com.unsignedinput import android.text.InputType
import android.text.TextWatcher
import android.widget.EditText
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.uimanager.UIManagerModule class ReactNativeUnsignedInputModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { override fun getName(): String { return NAME } private val listeners = hashMapOf<String, TextWatcher?>() @ReactMethod fun applyUnsigned(reactNode: Int) { val uiManager = reactContext.getNativeModule(UIManagerModule::class.java)!! uiManager.addUIBlock { viewRegistry -> val editText = viewRegistry.resolveView(reactNode) as EditText val listener = UnsignedTextWatcher(editText) listeners.set(getKey(reactNode), listener) editText.addTextChangedListener(listener) // Add this line to set the input type to password editText.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD) } } private fun safeResolveString(map: ReadableMap, key: String): String? { return try { map.getString(key) } catch (e: Exception) { null } } private fun safeResolveString(map: ReadableMap, key: String, defaultValue: String): String { return safeResolveString(map, key) ?: defaultValue } private fun safeResolveInt(map: ReadableMap, key: String): Int? { return try { map.getInt(key) } catch (e: Exception) { null } } private fun safeResolveInt(map: ReadableMap, key: String, defaultValue: Int): Int { return safeResolveInt(map, key) ?: defaultValue } companion object { const val NAME = "ReactNativeUnsignedInput" }
}

Tóm lại, Nó tạo ra một lớp ReactNativeUnsignedInputModule kế thừa từ ReactContextBaseJavaModule và tuân thủ giao diện TextWatcher để xử lý các sự kiện của EditText, giúp chuẩn hóa chuỗi nhập vào bằng cách loại bỏ dấu tiếng Việt và khoảng trắng.

Demo

Như vậy, @tdduydev/react-native-unsigned-input là một plugin hữu ích, giúp bạn dễ dàng nhập liệu số không dấu trong các ứng dụng React Native. Tuy nhiên, để tận dụng tối đa plugin này, bạn cần phải tùy chỉnh và thêm các xử lý bổ sung phù hợp với yêu cầu của ứng dụng. Chúc các bạn thành công với việc sử dụng và tùy biến plugin này!

Bình luận

Bài viết tương tự

- vừa được xem lúc

Some useful javascript functions (P2)

Như Phần trước mình đã đề cập đến 4 functions mình cho là khá hữu dụng trong javascript. Trong bài này mình sẽ tiếp tục đưa ra một số functions nữa.

0 0 25

- vừa được xem lúc

Cưỡi React Native xem Appium (Phần 1 - Cùng tìm hiểu cách hoạt động của Appium)

1. Mở đầu.

0 0 26

- vừa được xem lúc

[React Native] Dựng base App React Native - Navigation Sample - Modal Navigation

Introduction. Hi All. Trước khi vào chủ đề chính thì mình xin đưa ra 2 bài toán sau:. .

0 0 32

- vừa được xem lúc

[React Native] Dựng base App React Native - Mobx - Áp dụng thực tế

Chào mọi người. Và hôm nay chúng ta sẽ đi vào bài toán thực tế mà chúng ta có thể sử dụng với Mobx.

0 0 132

- vừa được xem lúc

React Router v6

React Router v6 đang được dần hoàn thiện và sẽ trình làng trong thời gian sắp tới. 1.

0 0 22

- vừa được xem lúc

"Một chút" về kiến trúc mới của React Native

Bài viết gốc: https://vir.vn/mot-chut-ve-kien-truc-moi-cua-react-native/.

0 0 102