要实现一个可拖拽的温度计,我们可以结合 React Native 的拖拽机制和温度计视觉效果。下面是一个完整的实现方案,使用 PanResponder 处理拖拽逻辑,并通过状态控制温度值:

import React, { useRef, useState } from 'react';
import { View, PanResponder, StyleSheet, Text, Dimensions } from 'react-native';

// 获取屏幕尺寸
const { width } = Dimensions.get('window');

const DraggableThermometer = () => {
  // 温度状态 (范围: 0-100°C)
  const [temperature, setTemperature] = useState(25);
  // 温度计高度
  const thermometerHeight = 300;
  // 滑块位置
  const [sliderPosition, setSliderPosition] = useState({
    y: thermometerHeight - (temperature / 100) * thermometerHeight
  });
  // 偏移量记录
  const offset = useRef({ y: 0 });

  // 创建PanResponder处理拖拽
  const panResponder = PanResponder.create({
    // 允许响应触摸事件
    onStartShouldSetPanResponder: () => true,
    onMoveShouldSetPanResponder: () => true,

    // 触摸开始时记录偏移
    onPanResponderGrant: (e, gesture) => {
      offset.current.y = sliderPosition.y - gesture.dy;
    },

    // 触摸移动时更新位置和温度
    onPanResponderMove: (e, gesture) => {
      // 计算新位置,限制在温度计范围内
      let newY = offset.current.y + gesture.dy;
      newY = Math.max(0, Math.min(newY, thermometerHeight));
      
      // 更新滑块位置
      setSliderPosition({ y: newY });
      
      // 根据位置计算温度 (0-100°C)
      const newTemperature = Math.round(100 - (newY / thermometerHeight) * 100);
      setTemperature(newTemperature);
    }
  });

  // 计算温度柱高度
  const temperatureBarHeight = (temperature / 100) * thermometerHeight;

  return (
    <View style={styles.container}>
      {/* 温度显示 */}
      <Text style={styles.tempText}>{temperature}°C</Text>
      
      {/* 温度计容器 */}
      <View style={[styles.thermometer, { height: thermometerHeight }]}>
        {/* 温度刻度 */}
        <View style={styles.scale}>
          {[0, 20, 40, 60, 80, 100].map((value) => (
            <View 
              key={value}
              style={[
                styles.tick,
                { top: thermometerHeight - (value / 100) * thermometerHeight }
              ]}
            >
              <Text style={styles.tickText}>{value}</Text>
            </View>
          ))}
        </View>
        
        {/* 温度柱 */}
        <View style={styles.tube}>
          <View 
            style={[
              styles.temperatureBar,
              { 
                height: temperatureBarHeight,
                bottom: 0
              }
            ]}
          />
        </View>
        
        {/* 可拖拽滑块 */}
        <View
          style={[
            styles.slider,
            { top: sliderPosition.y }
          ]}
          {...panResponder.panHandlers}
        />
      </View>
      
      {/* 温度范围提示 */}
      <View style={styles.labels}>
        <Text>低温</Text>
        <Text>高温</Text>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    alignItems: 'center',
    paddingVertical: 40
  },
  tempText: {
    fontSize: 40,
    fontWeight: 'bold',
    marginBottom: 20,
    color: '#333'
  },
  thermometer: {
    width: 60,
    position: 'relative',
    alignItems: 'center'
  },
  tube: {
    width: 20,
    height: '100%',
    borderWidth: 2,
    borderColor: '#666',
    borderRadius: 10,
    backgroundColor: 'transparent',
    position: 'relative',
    overflow: 'hidden'
  },
  temperatureBar: {
    width: '100%',
    backgroundColor: '#ff6b6b',
    position: 'absolute',
    transitionProperty: 'height',
    transitionDuration: '200ms'
  },
  slider: {
    width: 40,
    height: 15,
    backgroundColor: '#4a6fff',
    borderRadius: 3,
    position: 'absolute',
    left: (60 - 40) / 2,
    transform: [{ translateY: -7.5 }], // 居中对齐
    borderWidth: 2,
    borderColor: '#333'
  },
  scale: {
    position: 'absolute',
    right: -30,
    height: '100%',
    width: 30
  },
  tick: {
    position: 'absolute',
    width: 10,
    height: 2,
    backgroundColor: '#666',
    right: 0
  },
  tickText: {
    position: 'absolute',
    right: 12,
    fontSize: 12,
    color: '#666',
    transform: [{ translateY: -6 }]
  },
  labels: {
    width: 200,
    flexDirection: 'row',
    justifyContent: 'space-between',
    marginTop: 10
  }
});

export default DraggableThermometer;

这个可拖拽温度计组件的特点:

  1. 核心功能

    • 通过拖拽滑块调节温度(范围 0-100°C)
    • 实时显示当前温度值
    • 带有温度刻度标记,直观展示温度位置
  2. 实现细节

    • 使用 PanResponder 处理拖拽手势
    • 将滑块位置映射为温度值(位置越高,温度越低)
    • 限制滑块在温度计范围内移动,防止超出边界
    • 温度变化平滑且有数值显示
  3. UI 设计

    • 包含温度计主体、温度柱、可拖拽滑块
    • 右侧有温度刻度标记
    • 底部有高低温提示
    • 温度柱颜色使用渐变色效果(红色表示高温)

使用时,只需将该组件导入并添加到你的视图中即可。你可以根据需要调整样式,如温度计高度、颜色、温度范围等。如果需要摄氏度/华氏度切换,可以添加一个切换按钮并修改温度计算逻辑。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐