Мета полягає в розробці кастомного списку з можливістю масштабування, використовуючи react-native-gesture-handler та react-native-reanimated (або Animated з React Native) без використання додаткових зовнішніх пакетів. Функціональність масштабування повинна бути реалізована за допомогою жесту зжаття з react-native-gesture-handler або подібного кастомного підходу.
Вимоги:
- Список повинен бути розміщений у ScrollView і не повинен виходити за його межі під час або після масштабування. Очікувана поведінка повинна максимально відповідати функціональності масштабування в Apple та Google Calendar на мобільних пристроях.
- Реалізація повинна забезпечити плавну роботу як на iOS, так і на Android.
- Після масштабування вміст повинен залишатися на правильній позиції і бути готовим до подальшого масштабування з останнього стану.
- Висота окремих елементів списку повинна залишатися незмінною — лише висота батьківського контейнера повинна масштабуватися.
- Методи прокрутки не повинні використовуватися під час масштабування, щоб уникнути непередбачуваної поведінки та зайвої складності.
Нижче наведено приклад запуску:
import React from "react";
import { View, ScrollView, Text, StyleSheet, Dimensions } from "react-native";
import {
GestureHandlerRootView,
GestureDetector,
Gesture,
} from "react-native-gesture-handler";
const elementHeight = 50;
const list = Array.from({length: 50});
export default function PinchToZoomList() {
const pinchRef = useRef(Gesture.Pinch())
const pinchGesture = Gesture.Pinch()
.onBegin(() => {
//... деякі зміни
})
.onUpdate((e) => {
//... деякі зміни
})
.onFinalize(() => {
//... деякі зміни
})
.runOnJS(true)
.withRef(pinchRef);
return (
<GestureHandlerRootView>
<GestureDetector gesture={pinchGesture}>
<ScrollView simultaneousHandlers={pinchRef}>
{list.map((_, index) => (
<View key={index} style={styles.item}>
<Text>{index}</Text>
</View>
))}
</ScrollView>
</GestureDetector>
</GestureHandlerRootView>
);
}
const styles = StyleSheet.create({
item: {
height: elementHeight,
justifyContent: "center",
alignItems: "center",
borderBottomWidth: 1,
borderColor: "#ccc",
},
});