Hôm nay mình sẽ chia sẻ chủ đề sử dụng sensor cảm biến trong React Native.
Chắc hẳn nhiều bạn khi mới học React Native luôn trăn trở: Liệu nó có thể can thiệp sâu vào phần cứng hệ thống được không?
Đừng lo! Đúng như cái tên của nó: react Native. Nghĩa là nó rất gần với các app native.
Một trong những thế mạnh thú vị nhất của React Native là cho phép bạn kết nối giữa code native với code Javascript.
Nghĩa là, bạn có thể can thiệp rất sâu vào hệ thống thông qua các API native. Ví dụ: bạn có thể code Java/Kotlin và sử dụng API native của Android trong dự án React Native.
💦 Nghỉ chút xíu: Tâm sự của người mới học React Native
Quá tuyệt đúng không!
Nội dung chính của bài viết
Sensor là gì
Sensor hay chính là cảm biến, là các thiết bị cảm nhận sự thay đổi của môi trường tại vị trí cần đo. Trong một chiếc smart phone, nhà sản xuất trang bị hàng tá cảm biến để tăng cường các tính năng cho điện thoại.
Có thể kể tên như cảm biến tiệm cận, gia tốc… Cao cấp hơn thì có cảm biến vân tay, cảm biến gyro (cảm biến con quay hồi chuyển), cảm biến nhịp tim.v.v…
Đôi điều về thư viện React Native Sensor
Như mình đã đề cập, React Native có thể can thiệp sâu vào phần cứng thông qua API native của nền tảng. Tuy nhiên, điều này lại khiến developer cần phải chọn nhiều thư viện để thực hiện cùng một công việc cho các platform khác nhau. Nó làm mất đi tính chất cross-platform (lập trình đa nền tảng- code một lần cho mọi nền tảng).
Một vấn đề khác là API của các native module. Một số module rất tốt, nhưng một số module lại chỉ đơn giản là sử dụng các primitive API do React Native cung cấp, chẳng hạn như NativeEventEmitter. Do vậy, nó cũng không giúp gì nhiều cho bạn.
Khi mình tham gia dự án cần làm việc với các sensor trên thiết bị, mình đã gặp phải cả 2 vấn đề nêu trên.
Thật khó để so sánh cộng đồng React Native với các cộng đồng khác. Theo đúng nghĩa đen, đây là cộng đồng mà thành viên đến từ đủ mọi “tầng lớp xã hội”, có thể điểm danh:
- Những người xuất thân là Web Developer, những người rất giỏi Javascript.
- Hoặc những bạn đã từng làm việc với ReactJS, nay nghe nói đến React Native mà nhảy sang…
Do vậy, React Native luôn được hỗ trợ rất nhiệt tình, chu đáo bởi cộng đồng.
Thế là mình hùng hục tìm kiếm trên mạng xem có giải pháp nào nó tối ưu không? Xem có module nào wraper cho cả 2 nền tảng Android và iOS để không phải code riêng rẽ. Thật là may mắn, mình đã tìm ra thư viện react native sensors.
Sử dụng thư viện React Native Sensors như thế nào?
React-native-sensors cung cấp interface dựa trên RxJS cho cảm biến Accelerometer, Gyroscope và Magnetometer.
React native sensors hỗ trợ nhiều loại sensor trên cả Android và iOS. Tất nhiên, thư viện này rất dễ sử dụng. Bạn tham khảo đoạn code bên dưới đây:
import React, { Component } from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { Accelerometer } from "react-native-sensors"; const Value = ({name, value}) => ( <View style={styles.valueContainer}> <Text style={styles.valueName}>{name}:</Text> <Text style={styles.valueValue}>{new String(value).substr(0, 8)}</Text> </View> ) export default class App extends Component { constructor(props) { super(props); // Dòng 20 new Accelerometer({ updateInterval: 400 // defaults to 100ms }) .then(observable => { observable.subscribe(({x,y,z}) => this.setState({x,y,z})); }) .catch(error => { console.log("The sensor is not available"); }); this.state = {x: 0, y: 0, z: 0}; } // Dòng 33 render() { return ( <View style={styles.container}> <Text style={styles.headline}> Accelerometer values </Text> <Value name="x" value={this.state.x} /> <Value name="y" value={this.state.y} /> <Value name="z" value={this.state.z} /> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, headline: { fontSize: 30, textAlign: 'center', margin: 10, }, valueContainer: { flexDirection: 'row', flexWrap: 'wrap', }, valueValue: { width: 200, fontSize: 20 }, valueName: { width: 50, fontSize: 20, fontWeight: 'bold' }, instructions: { textAlign: 'center', color: '#333333', marginBottom: 5, }, });
Mình giải thích một chút ở 2 dòng comment:
- Dòng 20: Khởi tạo một Accelerometer mới, trả về một promise. Promise sẽ hoàn thành khi sensor đã available, có thể sử dụng. Ok, khi sensor đã ready thì tiến hành đăng kí observable và thiết lập state.
- Dòng 33: Ở hàm render, chúng ta chỉ đơn giản là access vào state để hiển thị dữ liệu thô của sensor. Kiểu như bên dưới này:
Thực hành sử dụng Sensor cảm biến với project
Để minh họa cách sử dụng thư viện này, mình tạo một project đơn giản như sau:
- Mình muốn sử dụng sensor con quay hồi chuyển gyroscopes để người dùng tương tác với một hình ảnh quá lớn để hiển thị trên toàn bộ màn hình.
- Thay vì phải vuốt sang trái hoặc sang phải, chỉ cần xoay điện thoại là sẽ nhìn thấy các phần khác của hình ảnh.
import React, { Component } from "react";
import { StyleSheet, Text, View, Image } from "react-native";
import { Gyroscope } from "react-native-sensors";
const Dimensions = require("Dimensions");
const PixelRatio = require("PixelRatio");
const window = Dimensions.get("window");
const deviceWidth = window.width;
const deviceHeight = window.height;
const imageWidth = 8 * deviceWidth;
const imageHeight = deviceHeight;
const middleOfTheScreenX = (imageWidth - deviceWidth) / 2;
export default class App extends Component {
constructor(props) {
super(props);
new Gyroscope({
updateInterval: 50
})
.then(observable => {
observable.subscribe(({ y }) => {
this.setState(state => ({
y: y + state.y
}));
});
})
.catch(error => {
console.log("The sensor is not available");
});
this.state = {
image: https://placeimg.com/${PixelRatio.getPixelSizeForLayoutSize(
imageWidth
)}/${PixelRatio.getPixelSizeForLayoutSize(imageHeight)}/any
,
y: 0
};
}
render() {
const positionOnScreenX = -imageWidth / 2;
// The y axis of the sensor data resembles what we need for the x axis
// in the image
const movementX = -this.state.y / 10 * imageWidth;
return (
<View style={styles.container}>
<Image
translateX={positionOnScreenX + movementX}
style={styles.image}
source={{ uri: this.state.image }}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#F5FCFF"
},
image: {
position: "absolute",
top: 0,
left: 0,
height: imageHeight,
width: imageWidth
}
});
Để tính toán xem đã di chuyển hình ảnh bao nhiêu, chỉ cần thêm các giá trị cảm biến cho tọa độ y
. Như vậy nếu bạn để điện thoại nghiêng sang trái, bạn sẽ tiếp tục ở bên trái của hình ảnh.
Trong hàm render, mình sử dụng translateX
để định vị hình ảnh ở giữa màn hình.
Bằng cách chia nhỏ giá trị cảm biến cho 10, chúng ta làm cho chuyển động cảm giác mượt hơn. Bạn có thể thử giá trị khác xem nó thay đổi độ mượt như nào nhé.
Và đây là kết quả cuối cùng:
Kết luận
Như vậy, chúng ta đã hoàn thành ứng dụng nho nhỏ sử dụng react-native-sensors, bạn thử build và chạy trên cả Android và iphone xem thế nào nhé.
Toàn bộ source code của project các bạn có thể tải về tại đây:
Dự án của bạn có sử dụng đến react-native-sensors không? Dù có hay không thì cũng để lại bình luận để mình có động lực cho bài viết tiếp theo nha.
💦 Đọc thêm về React Native:
Bình luận. Cùng nhau thảo luận nhé!