ResizableSplitView Component
A React Native component that creates a resizable split-screen interface with smooth gesture-based resizing. The component allows users to drag a handle to resize the top and bottom sections dynamically. It is a new ui approach for mobile apps.
Core Concept
The component uses a shared value (topSectionHeight) to control the height of the top section, which automatically adjusts the bottom section height. The resizing is handled through pan gestures on a drag handle positioned between the sections.
Basic Structure
<GestureHandlerRootView style={{ flex: 1 }}>
<SafeAreaView style={styles.container}>
{/* Top Section - Resizable */}
<Animated.View style={[styles.topSection, topSectionAnimatedStyle]}>
{/* Your top content */}
</Animated.View>
{/* Drag Handle */}
<GestureDetector gesture={panGesture}>
<Animated.View style={styles.dragHandleContainer}>
<Animated.View style={styles.dragHandle} />
</Animated.View>
</GestureDetector>
{/* Bottom Section - Auto-adjusting */}
<Animated.View style={[styles.bottomSection, bottomSectionAnimatedStyle]}>
{/* Your bottom content */}
</Animated.View>
</SafeAreaView>
</GestureHandlerRootView>Key Constants
const { height: SCREEN_HEIGHT } = Dimensions.get('window');
const HEADER_HEIGHT = 60;
const MIN_SECTION_HEIGHT = 100;
const MAX_TOP_SECTION_HEIGHT = SCREEN_HEIGHT * 0.7;
const DEFAULT_TOP_SECTION_HEIGHT = SCREEN_HEIGHT * 0.45;Shared Values
const topSectionHeight = useSharedValue(DEFAULT_TOP_SECTION_HEIGHT);
const isDragging = useSharedValue(false);
const startY = useSharedValue(0);Pan Gesture Logic
The pan gesture handles three phases:
Start: Records the initial height and sets dragging state to true Update: Calculates new height based on finger movement, constrained between min and max values End: Determines snap position based on velocity and current height, then animates to target
Snap Logic:
- High velocity (>800px/s): Snaps to next/previous position
- Low velocity: Snaps to whichever position is closest (minimized, default, or maximized)
Animated Styles Explained
1. Top Section Height Animation (topSectionAnimatedStyle)
What it does: Controls the height of the top section in real-time
How it works: Directly maps the topSectionHeight shared value to the height style
When it updates: Every time the user drags the handle or when snapping occurs
const topSectionAnimatedStyle = useAnimatedStyle(() => ({
height: topSectionHeight.value, // Direct height control
}));2. Bottom Section Height Animation (bottomSectionAnimatedStyle)
What it does: Automatically adjusts the bottom section height to fill remaining space How it works: Calculates remaining height by subtracting top section height from total screen height When it updates: Automatically when top section height changes
const bottomSectionAnimatedStyle = useAnimatedStyle(() => ({
height: SCREEN_HEIGHT - HEADER_HEIGHT - topSectionHeight.value - 100,
// This ensures bottom section always fills remaining space
}));Content Transition Animations (Optional)
If you want content to change based on section size, you can add these animations:
Compact Cards Animation
What it does: Shows/hides compact content when section is minimized How it works: Fades out and scales down as section expands
Expanded Cards Animation
What it does: Shows/hides expanded content when section is expanded How it works: Fades in and scales up as section expands
Three Snap Positions
- Minimized:
MIN_SECTION_HEIGHT(100px) - Default:
DEFAULT_TOP_SECTION_HEIGHT(45% of screen) - Maximized:
MAX_TOP_SECTION_HEIGHT(70% of screen)
Velocity-Based Snapping
- High velocity swipe (> 800px/s): Snaps to next/previous position
- Low velocity: Snaps to nearest position based on current height
Height Thresholds
- VELOCITY_THRESHOLD: 800px/s
- HEIGHT_THRESHOLD: 50px
Animation Configuration
const ANIMATION_CONFIG = {
damping: 25, // Controls bounce (lower = more bouncy)
stiffness: 300, // Controls speed (higher = faster)
mass: 0.8, // Controls inertia (higher = more inertia)
overshootClamping: false,
restDisplacementThreshold: 0.01,
restSpeedThreshold: 0.01,
};Change Snap Positions
const MIN_SECTION_HEIGHT = 80;
const DEFAULT_TOP_SECTION_HEIGHT = SCREEN_HEIGHT * 0.5;
const MAX_TOP_SECTION_HEIGHT = SCREEN_HEIGHT * 0.8;Adjust Animation Feel
const ANIMATION_CONFIG = {
damping: 20, // More bouncy
stiffness: 400, // Faster
mass: 1.0, // More inertia
};Modify Velocity Thresholds
const VELOCITY_THRESHOLD = 600; // Lower threshold
const HEIGHT_THRESHOLD = 30; // Smaller thresholdKey Dependencies
react-native-reanimated: For shared values and animationsreact-native-gesture-handler: For pan gesture handlingreact-native-safe-area-context: For safe area handling