《音量键翻页》三、readerCore阅读核心能力使用指南
HarmonyOS readerCore(阅读核心能力)使用指南
效果
一、概述
readerCore 是 HarmonyOS Reader Kit 的核心模块,提供了阅读页面数据基础类、页面状态管理、内容分页信息、页面排版属性、组件控制器等完整能力。它是阅读类应用实现排版控制、翻页交互、进度管理的核心依赖。
1.1 模块定位
Reader Kit
├── bookParser ← 书籍解析(输入层)
├── readerCore ← 阅读核心(控制层)← 本文重点
└── ReadPageComponent ← 阅读页组件(展示层)
readerCore 处于中间控制层,向下调度书籍解析能力,向上驱动阅读页组件渲染。开发者通过 readerCore 提供的控制器接口,实现对阅读行为的全面控制。
1.2 导入方式
import { readerCore } from '@kit.ReaderKit';
二、核心类型详解
2.1 ReaderComponentController(组件控制器)
ReaderComponentController 是 readerCore 的核心类,提供了对 ReadPageComponent 的完整控制能力。
创建实例
private controller: readerCore.ReaderComponentController =
new readerCore.ReaderComponentController();
完整方法列表
| 方法 | 返回值 | 说明 |
|---|---|---|
init(context) |
Promise<void> |
初始化控制器,传入 UIAbilityContext |
setPageConfig(config) |
void |
设置/更新页面排版属性 |
registerBookParser(handler) |
void |
注册书籍解析器 |
startPlay(spineIndex, domPos) |
Promise<void> |
以指定进度打开书籍 |
flipPage(isNext) |
void |
控制翻页(true=下一页,false=上一页) |
releaseBook() |
void |
释放书籍资源 |
on(event, callback) |
void |
监听阅读事件 |
off(event) |
void |
取消事件监听 |
2.2 ReaderSetting(排版配置)
ReaderSetting 定义了阅读页面的所有排版和视觉属性。
interface ReaderSetting {
fontName: string; // 字体名称
fontPath: string; // 自定义字体文件路径
fontSize: number; // 字体大小
fontColor: string; // 字体颜色(十六进制或rgba)
fontWeight: number; // 字体粗细(1-9)
lineHeight: number; // 行高倍数
nightMode: boolean; // 夜间模式开关
themeColor: string; // 主题背景色
themeBgImg: string; // 主题背景图路径
flipMode: string; // 翻页模式
scaledDensity: number; // 屏幕像素密度
viewPortWidth: number; // 视口宽度(像素)
viewPortHeight: number;// 视口高度(像素)
}
各属性详解
字体相关
| 属性 | 默认值 | 说明 |
|---|---|---|
fontName |
'' |
字体名称,空字符串使用系统默认字体 |
fontPath |
'' |
自定义字体的文件路径,空字符串不加载自定义字体 |
fontSize |
18 |
字体大小,单位由系统排版引擎处理 |
fontColor |
'#000000' |
字体颜色,支持 #RRGGBB 或 rgba() 格式 |
fontWeight |
4 |
字体粗细,范围 1-9(4 为正常,7 为粗体) |
lineHeight |
1.8 |
行高倍数,推荐 1.5-2.0 |
主题相关
| 属性 | 默认值 | 说明 |
|---|---|---|
nightMode |
false |
夜间模式,开启后字体颜色自动适配深色背景 |
themeColor |
'#FAFAFA' |
背景色,常见选项:白色 #FFFFFF、护眼黄 #EAE2CF、羊皮纸 #F5E7C8 |
themeBgImg |
'' |
背景图片路径,空字符串不使用背景图 |
翻页模式
| 属性 | 值 | 说明 |
|---|---|---|
flipMode |
'0' |
仿真翻页(模拟纸张翻转效果) |
flipMode |
'1' |
横滑翻页(左右滑动切换) |
设备参数
| 属性 | 获取方式 | 说明 |
|---|---|---|
scaledDensity |
display.getDefaultDisplaySync().scaledDensity |
屏幕像素密度比,必须 > 0 |
viewPortWidth |
display.getDefaultDisplaySync().width |
视口宽度(物理像素) |
viewPortHeight |
display.getDefaultDisplaySync().height |
视口高度(物理像素) |
2.3 PageDataInfo(页面数据信息)
页面事件回调中返回的页面状态信息:
interface PageDataInfo {
state: PageState; // 页面状态
// 其他页面信息...
}
2.4 PageState(页面状态枚举)
| 枚举值 | 说明 |
|---|---|
PageState.PAGE_ON_SHOW |
页面显示完成 |
PageState.PAGE_ON_HIDE |
页面隐藏 |
三、控制器方法详解
3.1 init(context)
初始化组件控制器。必须在所有其他控制器方法之前调用。
import { common } from '@kit.AbilityKit';
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
await this.controller.init(context);
- 参数:
UIAbilityContext应用上下文 - 返回:
Promise<void> - 注意:初始化是异步操作,需要
await等待完成
3.2 setPageConfig(config)
设置或更新页面排版属性。可以在阅读过程中动态调用以更新排版。
// 初始化时设置
this.controller.setPageConfig({
fontSize: 18,
fontColor: '#333333',
themeColor: '#FAFAFA',
lineHeight: 1.8,
flipMode: '0',
// ...其他配置
});
// 动态更新(如用户调整字号)
let newConfig = { ...this.pageConfig, fontSize: 22 };
this.controller.setPageConfig(newConfig);
3.3 registerBookParser(handler)
注册书籍解析器。必须在 startPlay 之前调用。
import { bookParser } from '@kit.ReaderKit';
let handler = await bookParser.getDefaultHandler(filePath);
this.controller.registerBookParser(handler);
3.4 startPlay(spineIndex, domPos)
以指定的阅读进度打开书籍,使用 Promise 异步回调。
// spineIndex: 章节索引(从 getSpineList 获取)
// domPos: DOM 位置定位(空字符串表示章节开头)
await this.controller.startPlay(0, '');
- spineIndex:章节索引号,通过
BookParserHandler.getSpineList()获取 - domPos:章节内的位置标识,用于精确定位阅读进度
3.5 flipPage(isNext)
控制翻页方向。
// 翻到下一页
this.controller.flipPage(true);
// 翻到上一页
this.controller.flipPage(false);
这是实现音量键翻页、手势翻页等自定义翻页交互的核心方法。
3.6 releaseBook()
释放书籍资源。必须在组件销毁时调用。
aboutToDisappear(): void {
this.controller.releaseBook();
}
3.7 on(event, callback) / off(event)
监听和取消阅读事件。
// 监听页面显示事件
this.controller.on('pageShow', (data: readerCore.PageDataInfo) => {
if (data.state === readerCore.PageState.PAGE_ON_SHOW) {
console.info('Page is now visible');
}
});
// 取消监听
this.controller.off('pageShow');
四、完整实现示例
4.1 基础阅读器实现
import { bookParser, ReadPageComponent, readerCore } from '@kit.ReaderKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { display } from '@kit.ArkUI';
import { common } from '@kit.AbilityKit';
import files from '@ohos.file.fs';
@ComponentV2
struct BasicReader {
@Local isLoading: boolean = true;
@Local currentPage: string = '';
private controller: readerCore.ReaderComponentController =
new readerCore.ReaderComponentController();
private parserHandler: bookParser.BookParserHandler | null = null;
private createPageConfig(): readerCore.ReaderSetting {
let d = display.getDefaultDisplaySync();
return {
fontName: '',
fontPath: '',
fontSize: 18,
fontColor: '#333333',
fontWeight: 4,
lineHeight: 1.8,
nightMode: false,
themeColor: '#FAFAFA',
themeBgImg: '',
flipMode: '0',
scaledDensity: d.scaledDensity > 0 ? d.scaledDensity : 1,
viewPortWidth: d.width,
viewPortHeight: d.height
};
}
private async loadBook(filePath: string): Promise<void> {
try {
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
// 1. 初始化控制器(异步)
let initPromise = this.controller.init(context);
// 2. 创建解析器(异步)
let parserPromise = bookParser.getDefaultHandler(filePath);
// 3. 并行等待
let results = await Promise.all([parserPromise, initPromise]);
this.parserHandler = results[0];
// 4. 获取章节信息
let spineList = this.parserHandler.getSpineList();
let startIndex = spineList[0].index;
// 5. 配置排版
this.controller.setPageConfig(this.createPageConfig());
// 6. 注册解析器
this.controller.registerBookParser(this.parserHandler);
// 7. 监听页面事件
this.controller.on('pageShow', (data: readerCore.PageDataInfo) => {
if (data.state === readerCore.PageState.PAGE_ON_SHOW) {
this.isLoading = false;
}
});
// 8. 开始阅读
await this.controller.startPlay(startIndex || 0, '');
} catch (err) {
console.error('loadBook failed:', JSON.stringify(err));
}
}
aboutToAppear(): void {
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let bookPath = context.filesDir + '/sample.txt';
this.loadBook(bookPath);
}
aboutToDisappear(): void {
this.controller.off('pageShow');
this.controller.releaseBook();
}
build() {
Stack() {
ReadPageComponent({
controller: this.controller,
readerCallback: (err: BusinessError, data: readerCore.ReaderComponentController) => {
if (err) {
console.error('ReadPageComponent error:', err.message);
}
this.controller = data;
}
})
if (this.isLoading) {
Column() {
LoadingProgress().width(48).height(48)
Text('加载中...').fontSize(14).margin({ top: 8 })
}
.width('100%').height('100%')
.justifyContent(FlexAlign.Center)
.backgroundColor('#FAFAFA')
}
}
.width('100%').height('100%')
}
}
4.2 动态调整排版
展示如何在阅读过程中动态更新排版属性(如字号、主题色):
@ComponentV2
struct ReaderWithSettings {
@Local currentFontSize: number = 18;
@Local isNightMode: boolean = false;
private controller: readerCore.ReaderComponentController =
new readerCore.ReaderComponentController();
private baseConfig: readerCore.ReaderSetting = { /* ... */ };
// 调整字号
changeFontSize(delta: number): void {
this.currentFontSize = Math.max(12, Math.min(32, this.currentFontSize + delta));
this.baseConfig.fontSize = this.currentFontSize;
this.controller.setPageConfig(this.baseConfig);
}
// 切换夜间模式
toggleNightMode(): void {
this.isNightMode = !this.isNightMode;
this.baseConfig.nightMode = this.isNightMode;
this.baseConfig.themeColor = this.isNightMode ? '#1A1A1A' : '#FAFAFA';
this.baseConfig.fontColor = this.isNightMode ? '#CCCCCC' : '#333333';
this.controller.setPageConfig(this.baseConfig);
}
build() {
Column() {
ReadPageComponent({
controller: this.controller,
readerCallback: (err, data) => { this.controller = data; }
})
.layoutWeight(1)
Row() {
Button('A-').onClick(() => this.changeFontSize(-2))
Text(`${this.currentFontSize}`).fontSize(14).margin({ left: 12, right: 12 })
Button('A+').onClick(() => this.changeFontSize(2))
Blank()
Button(this.isNightMode ? '☀' : '🌙').onClick(() => this.toggleNightMode())
}
.width('100%')
.padding(16)
.justifyContent(FlexAlign.Center)
}
}
}
4.3 音量键翻页集成
将 readerCore 的 flipPage 方法与 inputConsumer 结合:
import { inputConsumer, KeyCode } from '@kit.InputKit';
@ComponentV2
struct VolumeKeyReader {
@Param enableVolumeKey: boolean = false;
private controller: readerCore.ReaderComponentController =
new readerCore.ReaderComponentController();
@Monitor('enableVolumeKey')
onVolumeKeyChanged(): void {
if (this.enableVolumeKey) {
// 音量+ → 上一页
inputConsumer.on('keyPressed', {
key: KeyCode.KEYCODE_VOLUME_UP,
action: 1,
isRepeat: false
}, () => {
this.controller.flipPage(false);
});
// 音量- → 下一页
inputConsumer.on('keyPressed', {
key: KeyCode.KEYCODE_VOLUME_DOWN,
action: 1,
isRepeat: false
}, () => {
this.controller.flipPage(true);
});
} else {
inputConsumer.off('keyPressed');
}
}
aboutToDisappear(): void {
if (this.enableVolumeKey) {
inputConsumer.off('keyPressed');
}
this.controller.releaseBook();
}
build() {
ReadPageComponent({
controller: this.controller,
readerCallback: (err, data) => { this.controller = data; }
})
}
}
五、API 调用顺序
以下是各 API 的正确调用顺序,顺序错误可能导致功能异常:
┌──────────────────────────────────────────────┐
│ 1. new ReaderComponentController() │ 创建实例
│ 2. controller.init(context) │ 初始化(异步)
│ 3. bookParser.getDefaultHandler(path) │ 获取解析器(异步)
│ ↑ 步骤2和3可并行执行 │
│ 4. controller.setPageConfig(config) │ 设置排版
│ 5. controller.registerBookParser(handler) │ 注册解析器
│ 6. controller.on('pageShow', callback) │ 监听事件(可选)
│ 7. controller.startPlay(index, pos) │ 开始阅读
│ ─────── 阅读过程中 ─────── │
│ 8. controller.flipPage(true/false) │ 翻页操作
│ 9. controller.setPageConfig(newConfig) │ 更新排版(可选)
│ ─────── 页面销毁时 ─────── │
│ 10. controller.off('pageShow') │ 取消事件监听
│ 11. controller.releaseBook() │ 释放资源
└──────────────────────────────────────────────┘
六、常见问题与解决方案
6.1 页面排版异常(文字溢出/空白过多)
原因:viewPortWidth 或 viewPortHeight 未使用实际设备像素值。
解决方案:
let d = display.getDefaultDisplaySync();
// 确保使用真实值
viewPortWidth: d.width,
viewPortHeight: d.height,
scaledDensity: d.scaledDensity > 0 ? d.scaledDensity : 1,
6.2 初始化失败
原因:未传入正确的 UIAbilityContext。
解决方案:
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
await this.controller.init(context);
6.3 startPlay 报错
原因:在 registerBookParser 之前调用了 startPlay。
解决方案:严格按照 registerBookParser → startPlay 的顺序调用。
6.4 翻页无响应
原因:书籍尚未完成加载或控制器未正确初始化。
解决方案:确保 startPlay 返回的 Promise 已 resolve,且控制器已正确初始化。
6.5 页面销毁后报错
原因:未在 aboutToDisappear 中释放资源。
解决方案:
aboutToDisappear(): void {
this.controller.off('pageShow');
this.controller.releaseBook();
}
七、最佳实践
- 并行初始化:使用
Promise.all并行执行init和getDefaultHandler,减少启动时间 - Loading 状态:监听
pageShow事件,在页面显示完成后关闭 Loading - 设备适配:始终使用
display.getDefaultDisplaySync()获取真实设备参数 - 资源管理:在
aboutToDisappear中确保releaseBook()被调用 - 错误处理:所有异步操作使用 try-catch 包裹,记录详细错误信息
- 状态管理 V2:使用
@ComponentV2+@Param+@Monitor实现响应式的阅读控制
八、总结
readerCore 模块是 HarmonyOS 阅读类应用的核心引擎,通过 ReaderComponentController 提供了从初始化、排版、翻页到资源释放的完整生命周期管理。
核心要点:
ReaderComponentController是唯一的控制器入口ReaderSetting控制所有排版和视觉属性- API 调用顺序严格:
init→setPageConfig→registerBookParser→startPlay flipPage()是实现自定义翻页交互的关键方法- 页面销毁时务必调用
releaseBook()释放资源
参考文档
更多推荐



所有评论(0)