代码之家  ›  专栏  ›  技术社区  ›  docker compose

React Native中椭圆或圆角矩形视图周围的进度边界

  •  0
  • docker compose  · 技术社区  · 10 月前

    我正在做一个React Native项目,在那里我需要显示一个概述非圆形视图的进度指示器。

    我尝试使用带有Circle组件的react原生svg来创建循环进度指示器,但它并没有按我想要的那样工作。

    我需要进度指示器适合椭圆形或圆角矩形。

    以下是我目前使用基本React Native组件的方法的简化版本: https://snack.expo.dev/@audn/progress-border

    我想做的是:

    Goal

    到目前为止,我所拥有的:

    Current

    import { TouchableOpacity, Text, View, StyleSheet } from 'react-native';
    import moment from 'moment';
    import Svg, { Circle } from 'react-native-svg';
    
    const DateComponent = () => {
      const date = moment(new Date());
      const dayName = date.format('dd').charAt(0);
      const dayNumber = date.format('D');
      const isFutureDate = date.isAfter(moment(), 'day');
    
      const progress = 0.75;
      const radius = 35;
      const strokeWidth = 2;
      const circumference = 2 * Math.PI * radius;
    
      return (
        <TouchableOpacity  style={styles.container}>
          <View style={styles.wrapper}>
            <Svg height="70" width="70" viewBox="0 0 70 70">
              <Circle
                cx="35" 
                cy="35"
                r={radius}
                stroke="gray"
                strokeWidth={strokeWidth}
                fill="none"
                opacity={0.2}
              />
              <Circle
                cx="35"
                cy="35"
                r={radius}
                stroke="green"
                strokeWidth={strokeWidth}
                fill="none"
                strokeDasharray={`${circumference} ${circumference}`}
                strokeDashoffset={(1 - progress) * circumference}
                strokeLinecap="round"
                transform="rotate(-90, 35, 35)"
              />
            </Svg>
    
            <View style={styles.card}>
              <Text style={styles.dayText}>{dayName}</Text>
              <Text style={[styles.dateText, { color: isFutureDate ? '#757575' : 'black' }]}>
                {dayNumber}
              </Text>
            </View>
          </View>
        </TouchableOpacity>
      );
    };
    
    const styles = StyleSheet.create({
      container: {
        justifyContent: 'center',
        alignItems: 'center',
      },
      wrapper: {
        justifyContent: 'center',
        alignItems: 'center',
      },
      card: {
        position: 'absolute',
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        justifyContent: 'center',
        alignItems: 'center',
        borderRadius: 35,
        height: 70,
        width: 70,
      },
      dayText: {
        fontSize: 14,
        color: '#757575',
      },
      dateText: {
        fontSize: 18,
        fontWeight: 'bold',
      },
    });
    
    export default DateComponent;
    
    1 回复  |  直到 10 月前
        1
  •  0
  •   Łukasz Daniel Mastalerz    10 月前

    我画了一个简单的 SVG 文件和只是 已切换 它符合你的代码。。。这个解决方案对你来说合适吗?

    import React from 'react';
    import { TouchableOpacity, StyleSheet, View } from 'react-native';
    import Svg, { Rect, Text as SvgText } from 'react-native-svg';
    import moment from 'moment';
    
    const DateComponent = () => {
      const date = moment(new Date());
      const dayName = date.format('dd').charAt(0);
      const dayNumber = date.format('D');
      const isFutureDate = date.isAfter(moment(), 'day');
    
      const progress = 0.50;
      const radius = 30;
      const strokeWidth = 3;
      const rectWidth = 60;
      const rectHeight = 80;
      const perimeter = 1.6 * (rectWidth + rectHeight);
      const progressLength = progress * perimeter;
    
      return (
        <View style={styles.screen}>
          <TouchableOpacity style={styles.container}>
            <Svg width="70" height="100" viewBox="0 0 70 100">
              <Rect
                x="5"
                y="10"
                width={rectWidth}
                height={rectHeight}
                rx={radius}
                ry={radius}
                fill="black"
                stroke="gray"
                strokeWidth={strokeWidth}
                opacity={0.2}
              />
              <Rect
                x="5"
                y="10"
                width={rectWidth}
                height={rectHeight}
                rx={radius}
                ry={radius}
                fill="none"
                stroke="green"
                strokeWidth={strokeWidth}
                strokeDasharray={`${progressLength} ${perimeter - progressLength}`}
                strokeLinecap="round"
              />
              <SvgText
                x="35"
                y="40"
                textAnchor="middle"
                fill="#858585"
                fontSize="20"
                fontFamily="Arial"
              >
                {dayName}
              </SvgText>
              <SvgText
                x="35"
                y="75"
                textAnchor="middle"
                fill={isFutureDate ? '#757575' : 'white'}
                fontSize="20"
                fontFamily="Arial"
              >
                {dayNumber}
              </SvgText>
            </Svg>
          </TouchableOpacity>
        </View>
      );
    };
    
    const styles = StyleSheet.create({
      screen: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#f5f5f5',
      },
      container: {
        justifyContent: 'center',
        alignItems: 'center',
        width: 70,
        height: 100,
      },
    });
    
    export default DateComponent;
    

    更新

    pathLength版本

    import React from 'react';
    import { TouchableOpacity, StyleSheet, View } from 'react-native';
    import Svg, { Rect, Text as SvgText } from 'react-native-svg';
    import moment from 'moment';
    
      const DateComponent = () => {
      const date = moment(new Date());
      const dayName = date.format('dd').charAt(0);
      const dayNumber = date.format('D');
      const isFutureDate = date.isAfter(moment(), 'day');
    
      const progress = 0.50;
      const radius = 30;
      const strokeWidth = 3;
      const rectWidth = 60;
      const rectHeight = 80;
    
      return (
        <View style={styles.screen}>
          <TouchableOpacity style={styles.container}>
            <Svg width="70" height="100" viewBox="0 0 70 100">
              <Rect
                x="5"
                y="10"
                width={rectWidth}
                height={rectHeight}
                rx={radius}
                ry={radius}
                fill="black"
                stroke="gray"
                strokeWidth={strokeWidth}
                opacity={0.2}
              />
              <Rect
                x="5"
                y="10"
                width={rectWidth}
                height={rectHeight}
                rx={radius}
                ry={radius}
                fill="none"
                stroke="green"
                strokeWidth={strokeWidth}
                strokeDasharray={`${progress * 100} ${100 - (progress * 100)}`}
                strokeLinecap="round"
                pathLength="100"
              />
              <SvgText
                x="35"
                y="40"
                textAnchor="middle"
                fill="#858585"
                fontSize="20"
                fontFamily="Arial"
              >
                {dayName}
              </SvgText>
              <SvgText
                x="35"
                y="75"
                textAnchor="middle"
                fill={isFutureDate ? '#757575' : 'white'}
                fontSize="20"
                fontFamily="Arial"
              >
                {dayNumber}
              </SvgText>
            </Svg>
          </TouchableOpacity>
        </View>
      );
    };
    
    const styles = StyleSheet.create({
      screen: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#f5f5f5',
      },
      container: {
        justifyContent: 'center',
        alignItems: 'center',
        width: 70,
        height: 100,
      },
    });
    
    export default DateComponent;