如果有更好的书写方式,欢迎提出
废话不多说,直接上代码!!
由于不同手机机型分辨率不同,先写个适配比例不同机型的方法
import { Dimensions, Platform } from 'react-native';
const { height, width } = Dimensions.get('window');
const isWeb = Platform.OS === 'web';
const baseHeight = 667;
const baseWidth = 375;
const HRatio = width / baseWidth;
const VRatio = height / baseHeight;
// 根据手机屏幕的宽度进行比例适配
export const convertX = (width: number) => (isWeb ? width : width * HRatio);
// 根据手机屏幕的高度进行比例适配
export const convertY = (height: number) => (isWeb ? height : height * VRatio);
思路:
1、将8按下图划分
utils.js:
export const numPosition = (val, width, border) => {
const offset = border / 2;
const all = width + border * 2 * 2;
const obj = {
0: { top: offset, left: 0 },
1: { top: 0, left: offset },
2: { top: offset, left: 2 * offset + border * 2 + width },
3: { top: 2 * offset + border * 2 + width, left: offset },
4: { top: all + offset - border, left: 0 },
5: { top: (2 * offset + border * 2 + width) * 2, left: offset },
6: { top: all + offset - border, left: 2 * offset + border * 2 + width },
};
return obj[val];
};
export const numToIndex = val => {
const obj = {
0: [0, 1, 2, 4, 5, 6],
1: [2, 6],
2: [1, 2, 3, 4, 5],
3: [1, 2, 3, 5, 6],
4: [0, 2, 3, 6],
5: [0, 1, 3, 5, 6],
6: [0, 1, 3, 4, 5, 6],
7: [1, 2, 6],
8: [0, 1, 2, 3, 4, 5, 6],
9: [0, 1, 2, 3, 5, 6],
10: [3],
p: [0, 1, 2, 3, 4],
c: [0, 1, 4, 5],
l: [0, 4, 5],
f: [0, 1, 3, 4],
h: [0, 2, 3, 4, 6],
};
return obj[val];
};
export const isOdd = num => {
return num % 2 !== 0;
};
实现代码:
import React, { useState } from 'react';
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
import { convertX, isOdd, numPosition, numToIndex } from '@utils';
interface NumProps {
num: number; // 显示的文案
numWidth: number; // numWidth={cx(10)}
numBorder: number; // 数字一竖杠的边框宽度
style: StyleProp<ViewStyle>; // 最外层的样式设置
color: string; // 数字颜色设置
}
const NumView = (props: NumProps) => {
const { num = 8, numWidth = convertX(20), numBorder = convertX(4), style} = props;
const [numTxt, setNumTxt] = useState(numToIndex(num));
return (
<View
style={[
styles.wrap,
{ width: numWidth + numBorder * 5, height: numWidth * 2 + numBorder * 8 },
style,
]}
>
{numTxt.map(item => (
<View
key={item}
style={[
styles.numAbs,
{
flexDirection: !isOdd(item) ? 'column' : 'row',
},
numPosition(item, numWidth, numBorder),
]}
>
<View
style={[
styles.commonAngle,
{ borderWidth: numBorder },
!isOdd(item) ? styles.bottomChoice : styles.leftChoice,
]}
/>
<View
style={
!isOdd(item)
? [styles.columnLine, { width: numBorder * 2, height: numWidth }]
: [styles.rowLine, { width: numWidth, height: numBorder * 2 }]
}
/>
<View
style={[
styles.commonAngle,
{ borderWidth: numBorder },
!isOdd(item) ? styles.topChoice : styles.rightChoice,
]}
/>
</View>
))}
</View>
);
};
const styles = StyleSheet.create({
wrap: {
position: 'relative',
backgroundColor: 'red'
},
numAbs: {
position: 'absolute',
},
rowLine: {
backgroundColor: '#fff',
},
columnLine: {
backgroundColor: '#fff',
},
commonAngle: {
width: 0,
height: 0,
borderStyle: 'solid',
},
leftChoice: {
borderTopColor: 'transparent',
borderLeftColor: 'transparent',
borderBottomColor: 'transparent',
borderRightColor: '#fff',
},
rightChoice: {
borderTopColor: 'transparent',
borderLeftColor: '#fff',
borderBottomColor: 'transparent',
borderRightColor: 'transparent',
},
topChoice: {
borderTopColor: '#fff',
borderLeftColor: 'transparent',
borderBottomColor: 'transparent',
borderRightColor: 'transparent',
},
bottomChoice: {
borderTopColor: 'transparent',
borderLeftColor: 'transparent',
borderBottomColor: '#fff',
borderRightColor: 'transparent',
},
});
export default NumView;