背景
Ant Design是一套不错的UI组件库,功能强大。但是依赖了很多其他的组件,在RN6.3以后要自己安装以下组件才能正常使用。
yarn add @react-native-community/cameraroll @react-native-community/picker @react-native-community/segmented-control @react-native-community/slider @react-native-community/viewpager @react-native-community/async-storage
随着RN版本的不断更新,这里有一些组件渐渐已经过时。或者有更好的替代了。
我以前也写过相关的文章:
- 《2020年React Native使用Ant Design Mobile RN组件》
https://blog.csdn.net/lxyoucan/article/details/108334465 - 《ReactNative AsyncLocalStorageUtil is defined multiple times》
https://blog.csdn.net/lxyoucan/article/details/121015173
虽然Ant Design
非常火,但是不得不承认Ant Design for RN
在RN开发者中并不火。而且更新的频率不太高。因为有很多更好的选择。在我看来Ant Design for RN
还是有些臃肿了,依赖太多会导致APP体积增加。对于极简主义的我还是不能接受的。
随着编码能力的提升,有很多组件可以自己设计出来了。Ant Design for RN
在我的项目中渐渐的可有可无,但是为了照顾以前开发的老组件,我就萌生了自己实现一些我们项目中常用的Ant 组件的想法。
grid组件
这个是我用的最多的组件,没有之一。用起来比较方便。如果不用Ant Design for RN
怎么来自己实现呢?我自己在实现的过程中,发现Ant Design for RN
本身就是开源的。所以就直接把源码拿过来简单修改就可以使用了。
源码地址:
https://github.com/ant-design/ant-design-mobile-rn/blob/master/components/grid/index.tsx
主要代码如下,其他的依赖的内容可以原封不动从Ant Design for RN
源码中复制,这里我就不浪费版面了。
import React from 'react';
import {
Dimensions,
Image,
StyleProp,
StyleSheet,
Text,
ViewStyle,
} from 'react-native';
import Flex from '../flex/index';
import {
DataItem, GridPropsType} from './PropsType';
//import GridStyles from './style/index';
//定义接口
export interface GridProps extends GridPropsType {
itemStyle?: StyleProp<ViewStyle>;
}
//定义Grid的属性
export default class Grid extends React.Component<GridProps, any> {
static defaultProps: GridProps = {
data: [],
hasLine: true,
isCarousel: false,
columnNum: 4,
carouselMaxRow: 2,
itemStyle: {
},
};
//获取每个表格的样式,高度根据屏幕宽度计算得出
getFlexItemStyle(columnNum: number) {
return {
height: Dimensions.get('window').width / columnNum,
borderRightWidth: this.props.hasLine ? StyleSheet.hairlineWidth : 0,
};
}
render() {
//获取相关属性参数
const {
data, hasLine, onPress = () => {
}} = this.props;
//获取列数
const columnNum = this.props.columnNum;
//获取用户自定义的样式
const customItemStyle = this.props.itemStyle;
//设置最大的行数
//获取数据的长度
const dataLength = (data && data.length) || 0;
//计算行数
const rowCount = Math.ceil(dataLength / columnNum);
//如果用户传递属性了,则使用用户传递的方法,否则使用默认的方法
const renderItem =
this.props.renderItem ||
((dataItem: DataItem, index: number) => (
<Flex
direction="column"
justify="center"
style={
{
flex: 1}}
onPress={
() => onPress(dataItem, index)}>
{
React.isValidElement(dataItem.icon) ? (
dataItem.icon
) : (
// 如果不是react组件,则显示图片
<Image source={
{
uri: dataItem.icon}} style={
styles.icon} />
)}
<Text style={
styles.text}>{
dataItem.text}</Text>
</Flex>
));
//获取每一个item的样式
const flexItemStyle = this.getFlexItemStyle(columnNum);
const rowsArr: any[] = []; //用于存储所有的item
//处理每一行的数据
for (let i = 0; i < rowCount; i++) {
//存储单行的内容
const rowArr: any[] = [];
//处理一行中,第一列的数据
for (let j = 0; j < columnNum; j++) {
//计算总index的值
const dataIndex = i * columnNum + j;
if (dataIndex < dataLength) {
//如果数据存在,则取出来待用
const el = data && data[dataIndex];
//把这一行的内容push进来
rowArr.push(
<Flex.Item
key={
j}
style={
[
styles.grayBorderBox,
flexItemStyle,
{
borderLeftWidth:
hasLine && j === 0 ? StyleSheet.hairlineWidth : 0,
},
customItemStyle,
]}
onPress={
() => onPress(el, dataIndex)}>
{
el && renderItem(el, dataIndex)}
</Flex.Item>,
);
} else {
//如果数据为空,则渲染一个空的格子
rowArr.push(
<Flex.Item
key={
j}
style={
[styles.grayBorderBox, flexItemStyle, customItemStyle]}
/>,
);
}
}
//盒子的边框样式
const boxBorderStyle = {
borderTopWidth: hasLine && i === 0 ? StyleSheet.hairlineWidth : 0,
borderBottomWidth: hasLine ? StyleSheet.hairlineWidth : 0,
};
//把每一行的item塞进来
rowsArr.push(
<Flex key={
i} style={
[styles.grayBorderBox, boxBorderStyle]}>
{
rowArr}
</Flex>,
);
}
//根据不同的情况,输入不同的内容
return <Flex direction="column">{
rowsArr}</Flex>;
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
grayBorderBox: {
borderColor: '#dddddd',
},
icon: {
width: 22,
height: 22,
},
text: {
fontSize: 12,
color: '#000000',
marginTop: 8,
},
});
icon组件
这个组件是我使用第2多的组件。移植起来相对上面的容易一些,因为依赖没有上面的多。
详细使用方法见:
https://github.com/ant-design/ant-design-icons/tree/master/packages/icons-react-native
简单介绍:
yarn add @ant-design/icons-react-native
然后把字体文件手动复制到项目中。实现方法不是本文重点,请参考:
《2020年React Native使用Ant Design Mobile RN组件》
https://blog.csdn.net/lxyoucan/article/details/108334465
安卓为例:
项目目录中复制以下字体(node_modules/@ant-design/icons-react-native/fonts
),
android/app/src/main/assets/fonts
- antfill.ttf
- antoutline.ttf
核心 代码:
import {
IconOutline, OutlineGlyphMapType} from '@ant-design/icons-react-native';
import React from 'react';
import {
TextProps} from 'react-native';
export type IconNames = OutlineGlyphMapType;
export interface IconProps extends TextProps {
size?: 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | number;
color?: string;
name: IconNames;
}
export default class Icon extends React.Component<IconProps, any> {
static defaultProps = {
size: 'md',
};
static displayName = 'Icon';
render() {
const {
size, color, name, ...rest} = this.props;
const sizeMap: {
[key: string]: number} = {
xxs: 15,
xs: 18,
sm: 21,
md: 22,
lg: 36,
};
const fontSize = typeof size === 'string' ? sizeMap[size] : size;
return (
<IconOutline
size={
fontSize}
color={
color || '#cccccc'}
name={
name}
{
...rest}
/>
);
}
}
运行测试
至此我没有使用Ant Design for React Native
组件的情况下,也可以把我的常用的组件用起来了。
总结
经过这一翻的折腾,舒服了多了。本文只是提供一个思路。因为我比较常用的是icon组件和grid组件,其他的组件也可以根据这个思路来提取。只引用最需要的组件,就不会那么臃肿了。
示例代码下载
https://download.csdn.net/download/lxyoucan/59367460
特别说明,这个项目代码仅在安卓下测试了,iOS上跑的话,需要手动配置一下字体。