React

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > React > react-native-calendar-events库

ReactNative项目OpenHarmony三方库集成实战指南:react-native-calendar-events(读取不到日历里新增的事件,待排查)

作者:早點睡390

文章介绍了react-native-calendar-events库,这是一个强大的日历事件库,支持读写系统日历,实现日程管理功能,文章说明了其安装配置、核心功能、API使用方法,并提供了注意事项和完整示例,适用于React Native开发中的日历事件管理,感兴趣的朋友一起看看吧

项目基于 RN 0.72.90 开发

📋 前言

在移动应用开发中,日历事件管理是一项常见需求,特别是在日程管理、会议提醒、活动安排等场景中。react-native-calendar-events 是一个功能强大的日历事件库,提供了读取和写入系统日历的能力,支持创建、查询、更新和删除日历事件,是实现日程管理功能的理想选择。

🎯 库简介

基本信息

为什么需要日历事件库?

特性原生方案react-native-calendar-events
跨平台一致性⚠️ 需分别开发✅ 统一 API
权限管理⚠️ 手动处理✅ 自动处理
事件操作⚠️ 需封装✅ 开箱即用
重复规则⚠️ 复杂实现✅ 内置支持
HarmonyOS 支持⚠️ 需适配✅ 完善适配

核心功能

功能说明HarmonyOS 支持
requestPermissions请求日历权限
checkPermissions检查权限状态
findCalendars获取所有日历
saveCalendar创建日历
removeCalendar删除日历
findEventById根据ID查询事件
fetchAllEvents获取所有事件
saveEvent创建/更新事件
removeEvent删除事件

兼容性验证

在以下环境验证通过:

📦 安装步骤

1. 安装依赖

# RN 0.72 版本
npm install @react-native-ohos/react-native-calendar-events@2.2.1-rc.1
# 或者使用 yarn
yarn add @react-native-ohos/react-native-calendar-events@2.2.1-rc.1

2. 验证安装

安装完成后,检查 package.json 文件:

{
  "dependencies": {
    "@react-native-ohos/react-native-calendar-events": "^2.2.1-rc.1"
  }
}

🔧 HarmonyOS 平台配置 ⭐

1. 引入原生端代码

打开 harmony/entry/oh-package.json5,添加以下依赖:

"dependencies": {
  "@react-native-ohos/react-native-calendar-events": "file:../../node_modules/@react-native-ohos/react-native-calendar-events/harmony/calendar_events.har"
}

点击右上角的 sync 按钮,或者在终端执行:

cd entry
ohpm install

2. 配置 CMakeLists

打开 entry/src/main/cpp/CMakeLists.txt,添加:

+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
# RNOH_BEGIN: manual_package_linking_1
+ add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-calendar-events/src/main/cpp" ./calendar_events)
# RNOH_END: manual_package_linking_1
# RNOH_BEGIN: manual_package_linking_2
+ target_link_libraries(rnoh_app PUBLIC rnoh_calendar_events)
# RNOH_END: manual_package_linking_2

3. 引入 CalendarEventPackage

打开 entry/src/main/cpp/PackageProvider.cpp,添加:

#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
+ #include "CalendarEventsPackage.h"
using namespace rnoh;
std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
      std::make_shared<RNOHGeneratedPackage>(ctx),
      + std::make_shared<CalendarEventsPackage>(ctx)
    };
}

打开 entry/src/main/ets/RNPackagesFactory.ets,添加:

+ import { CalendarEventPackage } from '@react-native-ohos/react-native-calendar-events/ts';
export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    new SamplePackage(ctx),
    + new CalendarEventPackage(ctx)
  ];
}

4. 配置权限

entry/src/main/module.json5 中添加日历权限:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.READ_CALENDAR",
        "reason": "$string:Access_calendar",
        "usedScene": {
          "abilities": [
            "FormAbility"
          ],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.WRITE_CALENDAR",
        "reason": "$string:Access_calendar",
        "usedScene": {
          "abilities": [
            "FormAbility"
          ],
          "when": "inuse"
        }
      }
    ]
  }
}

5. 添加权限说明

打开 entry/src/main/resources/base/element/string.json,添加权限说明:

{
  "string": [
    {
      "name": "Access_calendar",
      "value": "用于访问和管理日历事件"
    }
  ]
}

📖 API 详解

requestPermissions - 请求日历权限

请求日历访问权限,必须在访问日历数据之前调用。

类型(readOnly?: boolean) => Promise<'authorized' | 'denied' | 'restricted' | 'undetermined'>

参数

返回值

使用场景

import RNCalendarEvents from 'react-native-calendar-events';
const requestPermission = async () => {
  const status = await RNCalendarEvents.requestPermissions();
  if (status === 'authorized') {
    console.log('日历权限已授权');
  } else {
    console.log('日历权限被拒绝');
  }
};

checkPermissions - 检查权限状态

检查当前的日历权限状态,不会弹出权限请求对话框。

类型(readOnly?: boolean) => Promise<'authorized' | 'denied' | 'restricted' | 'undetermined'>

参数

使用场景

import RNCalendarEvents from 'react-native-calendar-events';
const checkPermission = async () => {
  const status = await RNCalendarEvents.checkPermissions();
  console.log('当前权限状态:', status);
  return status === 'authorized';
};

findCalendars - 获取所有日历

获取设备上所有可用的日历列表。

类型() => Promise<Calendar[]>

返回值:日历对象数组,包含以下属性:

属性类型说明
idstring日历唯一标识
titlestring日历标题
sourceobject日历来源
colorstring日历颜色
allowsModificationsboolean是否允许修改
typestring日历类型

使用场景

import RNCalendarEvents from 'react-native-calendar-events';
const getCalendars = async () => {
  const calendars = await RNCalendarEvents.findCalendars();
  calendars.forEach((calendar) => {
    console.log('日历:', calendar.title, 'ID:', calendar.id);
  });
  return calendars;
};

saveCalendar - 创建日历

创建一个新的日历。

类型(options: CalendarOptions) => Promise<string>

参数

属性类型必填说明
titlestring日历标题
typestring日历类型
displayNamestring显示名称
colorstring日历颜色

返回值:新创建日历的 ID

import RNCalendarEvents from 'react-native-calendar-events';
const createCalendar = async () => {
  const calendarId = await RNCalendarEvents.saveCalendar({
    title: '我的日历',
    type: 'local',
    displayName: '个人日程',
    color: '#FF5722',
  });
  console.log('创建日历成功, ID:', calendarId);
  return calendarId;
};

removeCalendar - 删除日历

根据 ID 删除指定的日历。

类型(id: string) => Promise<boolean>

参数

返回值:是否删除成功

import RNCalendarEvents from 'react-native-calendar-events';
const deleteCalendar = async (calendarId: string) => {
  const success = await RNCalendarEvents.removeCalendar(calendarId);
  console.log('删除日历:', success ? '成功' : '失败');
  return success;
};

findEventById - 根据 ID 查询事件

根据事件 ID 获取单个事件的详细信息。

类型(id: string) => Promise<Event | null>

参数

返回值:事件对象,如果未找到则返回 null

事件对象属性

属性类型说明
idstring事件唯一标识
titlestring事件标题
locationstring事件地点
startDatestring开始时间
endDatestring结束时间
allDayboolean是否全天事件
descriptionstring事件描述
calendarIdstring所属日历 ID
attendeesarray参与者列表
recurrenceRuleobject重复规则
remindersarray提醒列表
import RNCalendarEvents from 'react-native-calendar-events';
const getEventById = async (eventId: string) => {
  const event = await RNCalendarEvents.findEventById(eventId);
  if (event) {
    console.log('事件标题:', event.title);
    console.log('开始时间:', event.startDate);
  }
  return event;
};

fetchAllEvents - 获取所有事件

获取指定时间范围内的所有事件。

类型(startDate: string, endDate: string, calendars?: string[]) => Promise<Event[]>

参数

参数类型必填说明
startDatestring开始时间(时间戳字符串)
endDatestring结束时间(时间戳字符串)
calendarsstring[]要查询的日历 ID 列表

使用场景

import RNCalendarEvents from 'react-native-calendar-events';
const getEvents = async () => {
  const now = Date.now();
  const startDate = now.toString();
  const endDate = (now + 7 * 24 * 60 * 60 * 1000).toString();
  const events = await RNCalendarEvents.fetchAllEvents(startDate, endDate);
  events.forEach((event) => {
    console.log('事件:', event.title, '开始:', event.startDate);
  });
  return events;
};

saveEvent - 创建/更新事件

创建新事件或更新已有事件。如果 details 中包含 id,则更新该事件;否则创建新事件。

类型(title: string, details?: EventDetails, options?: SaveEventOptions) => Promise<string>

参数

title: 事件标题

details: 事件详情

属性类型必填说明
idstring事件 ID(更新时)
typenumber事件类型
titlestring事件标题
locationobject地点信息
startTimenumber开始时间(毫秒)
endTimenumber结束时间(毫秒)
isAllDayboolean是否全天事件
attendeearray参与者列表
timeZonestring时区
reminderTimenumber[]提醒时间列表
recurrenceRuleobject重复规则
descriptionstring事件描述

location 对象

属性类型说明
locationstring地点名称
longitudenumber经度
latitudenumber纬度

recurrenceRule 对象

属性类型说明
recurrenceFrequencynumber重复频率(1=每日,2=每周等)
expirenumber过期时间(0表示永不过期)

返回值:事件的 ID

import RNCalendarEvents from 'react-native-calendar-events';
const createEvent = async () => {
  const now = Date.now();
  const eventId = await RNCalendarEvents.saveEvent('项目会议', {
    title: '项目会议',
    startTime: now + 60 * 60 * 1000,
    endTime: now + 2 * 60 * 60 * 1000,
    location: {
      location: '会议室A',
      longitude: 116.397,
      latitude: 39.908,
    },
    description: '讨论项目进度',
    isAllDay: false,
    reminderTime: [now + 30 * 60 * 1000],
  });
  console.log('创建事件成功, ID:', eventId);
  return eventId;
};
const updateEvent = async (eventId: string) => {
  const now = Date.now();
  const newEventId = await RNCalendarEvents.saveEvent('项目会议(已更新)', {
    id: eventId,
    title: '项目会议(已更新)',
    startTime: now + 2 * 60 * 60 * 1000,
    endTime: now + 3 * 60 * 60 * 1000,
    description: '会议时间已调整',
  });
  console.log('更新事件成功');
  return newEventId;
};

removeEvent - 删除事件

根据 ID 删除指定的事件。

类型(id: string, options?: { futureEvents?: boolean }) => Promise<boolean>

参数

参数类型必填说明
idstring事件 ID
futureEventsboolean是否删除未来的重复事件

返回值:是否删除成功

import RNCalendarEvents from 'react-native-calendar-events';
const deleteEvent = async (eventId: string) => {
  const success = await RNCalendarEvents.removeEvent(eventId);
  console.log('删除事件:', success ? '成功' : '失败');
  return success;
};

📋 完整示例

import React, { useState, useEffect } from 'react';
import {
  View,
  Text,
  StyleSheet,
  ScrollView,
  TouchableOpacity,
  SafeAreaView,
  StatusBar,
  Alert,
  TextInput,
  Switch,
  TouchableWithoutFeedback,
} from 'react-native';
import RNCalendarEvents from 'react-native-calendar-events';
interface Calendar {
  id: string;
  title: string;
  type?: string;
  displayName?: string;
}
interface Event {
  id: string;
  title: string;
  startDate: string;
  endDate?: string;
  location?: string;
  description?: string;
  allDay?: boolean;
}
const App: React.FC = () => {
  const [calendars, setCalendars] = useState<Calendar[]>([]);
  const [events, setEvents] = useState<Event[]>([]);
  const [isAuthorized, setIsAuthorized] = useState(false);
  const [showForm, setShowForm] = useState(false);
  const [eventTitle, setEventTitle] = useState('');
  const [eventDescription, setEventDescription] = useState('');
  const [eventLocation, setEventLocation] = useState('');
  const [isAllDay, setIsAllDay] = useState(false);
  useEffect(() => {
    checkPermission();
  }, []);
  const checkPermission = async () => {
    const status = await RNCalendarEvents.checkPermissions();
    setIsAuthorized(status === 'authorized');
    if (status === 'authorized') {
      loadCalendars();
      loadEvents();
    }
  };
  const requestPermission = async () => {
    const status = await RNCalendarEvents.requestPermissions();
    setIsAuthorized(status === 'authorized');
    if (status === 'authorized') {
      loadCalendars();
      loadEvents();
    } else {
      Alert.alert('权限被拒绝', '请在设置中允许访问日历');
    }
  };
  const loadCalendars = async () => {
    try {
      const calendarList = await RNCalendarEvents.findCalendars();
      setCalendars(calendarList);
    } catch (error) {
      console.error('获取日历失败:', error);
    }
  };
  const loadEvents = async () => {
    try {
      const now = new Date();
      const startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString();
      const endDate = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000).toISOString();
      const eventList = await RNCalendarEvents.fetchAllEvents(startDate, endDate);
      setEvents(eventList);
    } catch (error) {
      console.error('获取事件失败:', error);
    }
  };
  const createEvent = async () => {
    if (!eventTitle.trim()) {
      Alert.alert('提示', '请输入事件标题');
      return;
    }
    try {
      const now = new Date();
      let startDate: string;
      let endDate: string;
      if (isAllDay) {
        const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
        const tomorrow = new Date(today.getTime() + 24 * 60 * 60 * 1000);
        startDate = today.toISOString();
        endDate = tomorrow.toISOString();
      } else {
        startDate = new Date(now.getTime() + 60 * 60 * 1000).toISOString();
        endDate = new Date(now.getTime() + 2 * 60 * 60 * 1000).toISOString();
      }
      const eventId = await RNCalendarEvents.saveEvent(eventTitle, {
        startDate,
        endDate,
        location: eventLocation || undefined,
        description: eventDescription,
        allDay: isAllDay,
      });
      Alert.alert('成功', '事件创建成功');
      setShowForm(false);
      setEventTitle('');
      setEventDescription('');
      setEventLocation('');
      setIsAllDay(false);
      loadEvents();
    } catch (error) {
      console.error('创建事件失败:', error);
      Alert.alert('错误', '创建事件失败');
    }
  };
  const deleteEvent = async (eventId: string) => {
    Alert.alert('确认删除', '确定要删除这个事件吗?', [
      { text: '取消', style: 'cancel' },
      {
        text: '删除',
        style: 'destructive',
        onPress: async () => {
          try {
            await RNCalendarEvents.removeEvent(eventId);
            Alert.alert('成功', '事件已删除');
            loadEvents();
          } catch (error) {
            console.error('删除事件失败:', error);
            Alert.alert('错误', '删除事件失败');
          }
        },
      },
    ]);
  };
  const formatDate = (dateString: string) => {
    try {
      const date = new Date(dateString);
      if (isNaN(date.getTime())) {
        return dateString;
      }
      const year = date.getUTCFullYear();
      const month = String(date.getUTCMonth() + 1).padStart(2, '0');
      const day = String(date.getUTCDate()).padStart(2, '0');
      const hours = String(date.getUTCHours()).padStart(2, '0');
      const minutes = String(date.getUTCMinutes()).padStart(2, '0');
      return `${year}-${month}-${day} ${hours}:${minutes}`;
    } catch {
      return dateString;
    }
  };
  const getLocationText = (location: Event['location']) => {
    return location || '';
  };
  if (!isAuthorized) {
    return (
      <SafeAreaView style={styles.container}>
        <StatusBar barStyle="dark-content" backgroundColor="#FFFFFF" />
        <View style={styles.permissionContainer}>
          <Text style={styles.permissionTitle}>日历权限</Text>
          <Text style={styles.permissionText}>
            需要日历权限才能管理您的日程事件
          </Text>
          <TouchableOpacity style={styles.permissionButton} onPress={requestPermission}>
            <Text style={styles.permissionButtonText}>授权访问日历</Text>
          </TouchableOpacity>
        </View>
      </SafeAreaView>
    );
  }
  return (
    <SafeAreaView style={styles.container}>
      <StatusBar barStyle="dark-content" backgroundColor="#FFFFFF" />
      <View style={styles.header}>
        <Text style={styles.headerTitle}>日历事件管理</Text>
        <TouchableOpacity
          style={styles.addButton}
          onPress={() => setShowForm(true)}
        >
          <Text style={styles.addButtonText}>+ 新建</Text>
        </TouchableOpacity>
      </View>
      <ScrollView style={styles.content}>
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>日历列表 ({calendars.length})</Text>
          {calendars.length === 0 ? (
            <Text style={styles.emptyText}>暂无日历</Text>
          ) : (
            calendars.map((calendar, index) => (
              <View key={calendar.id || index} style={styles.calendarItem}>
                <View style={styles.calendarColor} />
                <View style={styles.calendarInfo}>
                  <Text style={styles.calendarTitle}>{calendar.title || '未命名日历'}</Text>
                  <Text style={styles.calendarType}>类型: {calendar.type || '本地'}</Text>
                </View>
              </View>
            ))
          )}
        </View>
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>近期事件 ({events.length})</Text>
          {events.length === 0 ? (
            <View style={styles.emptyContainer}>
              <Text style={styles.emptyText}>暂无事件</Text>
              <Text style={styles.emptyHint}>点击右上角"新建"创建事件</Text>
            </View>
          ) : (
            events.map((event) => (
              <View key={event.id} style={styles.eventItem}>
                <View style={styles.eventHeader}>
                  <Text style={styles.eventTitle}>{event.title}</Text>
                  <TouchableOpacity onPress={() => deleteEvent(event.id)}>
                    <Text style={styles.deleteText}>删除</Text>
                  </TouchableOpacity>
                </View>
                <Text style={styles.eventTime}>开始: {formatDate(event.startDate)}</Text>
                {event.endDate && (
                  <Text style={styles.eventTime}>结束: {formatDate(event.endDate)}</Text>
                )}
                {event.location && (
                  <Text style={styles.eventLocation}>📍 {getLocationText(event.location)}</Text>
                )}
                {event.description && (
                  <Text style={styles.eventDescription}>{event.description}</Text>
                )}
              </View>
            ))
          )}
        </View>
      </ScrollView>
      {showForm && (
        <TouchableWithoutFeedback onPress={() => setShowForm(false)}>
          <View style={styles.overlay}>
            <TouchableWithoutFeedback onPress={() => {}}>
              <View style={styles.formContainer}>
                <Text style={styles.formTitle}>新建事件</Text>
                <Text style={styles.inputLabel}>事件标题</Text>
                <TextInput
                  style={styles.input}
                  placeholder="请输入事件标题"
                  value={eventTitle}
                  onChangeText={setEventTitle}
                />
                <Text style={styles.inputLabel}>地点(可选)</Text>
                <TextInput
                  style={styles.input}
                  placeholder="请输入地点"
                  value={eventLocation}
                  onChangeText={setEventLocation}
                />
                <Text style={styles.inputLabel}>描述(可选)</Text>
                <TextInput
                  style={[styles.input, styles.textArea]}
                  placeholder="请输入描述"
                  value={eventDescription}
                  onChangeText={setEventDescription}
                  multiline
                />
                <View style={styles.switchRow}>
                  <Text style={styles.switchLabel}>全天事件</Text>
                  <Switch value={isAllDay} onValueChange={setIsAllDay} />
                </View>
                <View style={styles.formButtons}>
                  <TouchableOpacity
                    style={[styles.formButton, styles.cancelButton]}
                    onPress={() => setShowForm(false)}
                  >
                    <Text style={styles.cancelButtonText}>取消</Text>
                  </TouchableOpacity>
                  <TouchableOpacity
                    style={[styles.formButton, styles.confirmButton]}
                    onPress={createEvent}
                  >
                    <Text style={styles.confirmButtonText}>创建</Text>
                  </TouchableOpacity>
                </View>
              </View>
            </TouchableWithoutFeedback>
          </View>
        </TouchableWithoutFeedback>
      )}
    </SafeAreaView>
  );
};
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#F5F5F5',
  },
  permissionContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  permissionTitle: {
    fontSize: 24,
    fontWeight: '700',
    color: '#333333',
    marginBottom: 12,
  },
  permissionText: {
    fontSize: 16,
    color: '#666666',
    textAlign: 'center',
    marginBottom: 24,
  },
  permissionButton: {
    backgroundColor: '#007AFF',
    paddingHorizontal: 32,
    paddingVertical: 14,
    borderRadius: 8,
  },
  permissionButtonText: {
    color: '#FFFFFF',
    fontSize: 16,
    fontWeight: '600',
  },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    padding: 16,
    backgroundColor: '#FFFFFF',
    borderBottomWidth: 1,
    borderBottomColor: '#E5E5EA',
  },
  headerTitle: {
    fontSize: 20,
    fontWeight: '700',
    color: '#333333',
  },
  addButton: {
    backgroundColor: '#007AFF',
    paddingHorizontal: 16,
    paddingVertical: 8,
    borderRadius: 6,
  },
  addButtonText: {
    color: '#FFFFFF',
    fontSize: 14,
    fontWeight: '600',
  },
  content: {
    flex: 1,
    padding: 16,
  },
  section: {
    backgroundColor: '#FFFFFF',
    borderRadius: 12,
    padding: 16,
    marginBottom: 16,
  },
  sectionTitle: {
    fontSize: 18,
    fontWeight: '600',
    color: '#333333',
    marginBottom: 12,
  },
  calendarItem: {
    flexDirection: 'row',
    alignItems: 'center',
    paddingVertical: 12,
    borderBottomWidth: 1,
    borderBottomColor: '#F0F0F0',
  },
  calendarColor: {
    width: 12,
    height: 12,
    borderRadius: 6,
    backgroundColor: '#007AFF',
    marginRight: 12,
  },
  calendarInfo: {
    flex: 1,
  },
  calendarTitle: {
    fontSize: 16,
    color: '#333333',
    fontWeight: '500',
  },
  calendarType: {
    fontSize: 14,
    color: '#999999',
    marginTop: 2,
  },
  emptyContainer: {
    alignItems: 'center',
    paddingVertical: 32,
  },
  emptyText: {
    fontSize: 16,
    color: '#999999',
  },
  emptyHint: {
    fontSize: 14,
    color: '#CCCCCC',
    marginTop: 8,
  },
  eventItem: {
    paddingVertical: 12,
    borderBottomWidth: 1,
    borderBottomColor: '#F0F0F0',
  },
  eventHeader: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  eventTitle: {
    fontSize: 16,
    fontWeight: '600',
    color: '#333333',
    flex: 1,
  },
  deleteText: {
    fontSize: 14,
    color: '#FF3B30',
    marginLeft: 12,
  },
  eventTime: {
    fontSize: 14,
    color: '#666666',
    marginTop: 4,
  },
  eventLocation: {
    fontSize: 14,
    color: '#666666',
    marginTop: 4,
  },
  eventDescription: {
    fontSize: 14,
    color: '#999999',
    marginTop: 4,
  },
  overlay: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    backgroundColor: 'rgba(0,0,0,0.5)',
    justifyContent: 'center',
    alignItems: 'center',
  },
  formContainer: {
    backgroundColor: '#FFFFFF',
    borderRadius: 12,
    padding: 20,
    width: '90%',
    maxWidth: 400,
  },
  formTitle: {
    fontSize: 20,
    fontWeight: '700',
    color: '#333333',
    marginBottom: 20,
    textAlign: 'center',
  },
  inputLabel: {
    fontSize: 14,
    color: '#666666',
    marginBottom: 4,
  },
  input: {
    borderWidth: 1,
    borderColor: '#E5E5EA',
    borderRadius: 8,
    paddingHorizontal: 16,
    paddingVertical: 12,
    fontSize: 16,
    marginBottom: 12,
  },
  textArea: {
    height: 80,
    textAlignVertical: 'top',
  },
  switchRow: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    paddingVertical: 8,
    marginBottom: 20,
  },
  switchLabel: {
    fontSize: 16,
    color: '#333333',
  },
  formButtons: {
    flexDirection: 'row',
    gap: 12,
  },
  formButton: {
    flex: 1,
    paddingVertical: 14,
    borderRadius: 8,
    alignItems: 'center',
  },
  cancelButton: {
    backgroundColor: '#F0F0F0',
  },
  cancelButtonText: {
    fontSize: 16,
    color: '#666666',
    fontWeight: '600',
  },
  confirmButton: {
    backgroundColor: '#007AFF',
  },
  confirmButtonText: {
    fontSize: 16,
    color: '#FFFFFF',
    fontWeight: '600',
  },
});
export default App;

⚠️ 注意事项

1. 权限配置

2. 时间格式

3. 日历 ID

4. 事件更新

5. 重复事件

6. 错误处理

7. 性能优化

到此这篇关于ReactNative项目OpenHarmony三方库集成实战指南:react-native-calendar-events(读取不到日历里新增的事件,待排查)的文章就介绍到这了,更多相关react-native-calendar-events库内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文