首页 > 代码库 > 第十章、epub文件处理 -- 样式处理

第十章、epub文件处理 -- 样式处理

第十章、epub文件处理 -- 样式处理


这一章的内容比较简单,因为第九章中集中了篇幅介绍显示的流程,所以把处理样式的流程单独列一章来介绍。

对样式的处理包含两个部分:第一是创建样式,第二是应用样式。


创建样式

创建样式的过程其实就是对样式文件的解析。1.0的版本中是直接去读取程序内置的资源文件style.xml,这个文件的位置是在assets\default内。

我们曾在第二章中介绍过如果通过解析资源文件来获得要显示在进度条上的文字。style.xml文件也是资源文件,所以两者在解析的过程中是很相似的。

我们先来回下第二章对解析xml文件的三个核心类ZMLZMLProcessorZLXMLParserZLXMLReader互相之间调用顺序的描述:

1ZLXMLReaderAdapter抽象类的子类ResourceTreeReader类)里面的read方法调用ZLXMLProcessor类的read方法

2ZLXMLProcessor类的read方法通过AndroidAssetsFile类(ZLResourceFile类的子类)的getInputStream方法获取一个针对资源文件的字节流类(AssetInputStream类),并以这个字节流类为参数初始化了一个针对资源文件的字符流类。接着,就调用了ZLXMLParser类的doIt方法。

3、 ZLXMLParser类的doIt方法利用字符流类将文件转换成一个char数组。再利用for循环迭代char数组的过程中,doIt方法又反过来调用ZLXMLReaderAdapter抽象类的子类ResourceTreeReader类)startElementHandlerendElementHandler方法对byte数组中元素所代表的不同节点进行操作。

把上述调用顺序中的标红的TextStyleReader类替换成ResourceTreeReader类,就可以适用于对样式文件的解析流程。

关于解析的顺序我们在第二章以及第六章中已经反复介绍过了,这一章中就不再重复。我们只将注意力放在用for循环迭代char数组的过程对于不同节点的操作。而对于节点的操作都是在TextStyleReader类的startElementHandler方法中完成的。

style.xml文件中,主要是两种节点:basestylebase节点代表基本样式,而style节点则代表各种标签对应的标签样式。

.xhtml文件中所有的字都会先应用base标签代表的基本样式,然后不同标签内的文本内容会在基本样式的基础上再应用标签对应的样式,标签样式会覆盖基本样式。

TextStyleReader类的startElementHandler方法主要就是针对这两种节点进行操作。


TextStyleReader类的startElementHandler方法

在这个方法中,代码会判断是否有读取到basestyle标签。

如果读取到base标签,代码会新建一个ZLTextBaseStyle类来代表基本样式;

如果读取到style标签,代码会新建一个ZLTextFullStyleDecoration类代表特定的标签样式。

 

标签内的属性都会被一一赋值给ZLTextFullStyleDecoration类的各个属性,其中比较重要的包括:左缩进LeftIndentOption、右缩进RightIndentOption、首行缩进FirstLineIndentDeltaOption、字体类型FontFamilyOption、字体大小FontSizeDeltaOption、字体加粗BoldOption、字体斜体ItalicOption,当然还包括最终的当前标签的名字myName

新建出来的ZLTextFullStyleDecoration类会以标签的id属性为键名加入ZLTextStyleCollectionmyDecorationMap属性指向的数组

 

当对char数组的for循环完成时,创建样式的流程也就相应完成了。这个流程完成之后,我们会得到一个“代表基本字体样式的ZLTextBaseStyle类”以及“一系列对应代表不同标签样式的ZLTextFullStyleDecoration类”。


应用样式

应用样式的流程会由两个方法组成:ZLTextViewBase类中resetTextStyle方法与applyControl方法。

ZLTextViewBaseresetTextStyle方法

getBaseStyle方法会在ZLTextView类的buildInfos方法中被调用(参考第九章)。

 

getBaseStyle方法将获取解析样式文件生成的ZLTextBaseStyle类。接着,setTextStyle方法会将代表基本样式的ZLTextBaseStyle类赋值给ZLTextViewBase类的myTextStyle属性。与此同时,字体相关的样式会被存储到ZLTextViewBase类的myContext属性中。

 

ZLTextViewBaseapplyControl方法

applyControl方法会在程序读取到代表标签信息的ZLTextControlElement类时被触发。该方法会首先根据当前ZLTextControlElement类的IsStart属性来会判断当前的这个类对应的是标签对的起始部分还是结束部分。

标签对起始部分

如果当前ZLTextControlElement类对应的是标签对的起始部分,此时,代码会去根据ZLTextControlElement类的Kind属性(该属性的赋值请参考第七章)从ZLTextStyleCollectionmyDecorationMap属性指向的数组中获取对应的ZLTextFullStyleDecoration类(102行,参考刚才介绍的创建流程)。

 

然后,代码会调用ZLTextStyleDecorationcreateDecoratedStyle方法(109行),这个方法会根据ZLTextFullStyleDecoration类生成对应的ZLTextFullDecoratedStyle类。

ZLTextStyleDecorationcreateDecoratedStyle方法中,会调用 ZLTextFullDecoratedStyle类的构造函数,在这个函数中,ZLTextFullStyleDecoration类会被存储在ZLTextFullDecoratedStyle类的myFullDecoration属性中(33行)。

        (这里要特别注意,ZLTextStyleDecorationcreateDecoratedStyle方法还会调用到ZLTextStyle的构造函数,这个构造函数会将已有的ZLTextFullDecoratedStyle类(或者ZLTextBaseStyle类,ZLTextBaseStyle类和ZLTextFullDecoratedStyle类都是ZLTextStyle类的子类)存储到新建的ZLTextFullDecoratedStyleBase属性。)

        

最终,在ZLTextViewBase类的setTextStyle方法中,当前的ZLTextBaseStyle类或ZLTextFullDecoratedStyle类被存储在了ZLTextViewBase类的myTextStyle属性,字体相关的样式被存储到ZLTextViewBase类的myContext属性中。


标签对结束部分

如果当前ZLTextControlElement类对应的是标签对的结束部分,此时,代码就会样式还原到ZLTextFullDecoratedStyle类的Base属性指向的旧的ZLTextFullDecoratedStyle类。


applyControl方法在标签对的起始部分与结束部分中分别对ZLTextFullDecoratedStyleBase属性的操作构成了一种层级存储的结构(这种存储结构与第二章中介绍的利用ZLTreeResource类的myChildren属性构成存储结构是很类似的,可以互相参考)。

我们可以用B标签作为例子,来看下这种层级存储结构有着怎样的作用。下图中,我们可以看到“暂名”两个字是B标签内的内容。


当代码读到B标签之前的内容时,一直都在应用基本样式(ZLTextBaseStyle),一旦读到B标签的起始部分,就会开始新建一个B标签的样式(ZLTextFullDecoratedStyle类),并覆盖掉基本样式,于此同时,代码会将基本样式(ZLTextBaseStyle)存储到B标签样式(ZLTextFullDecoratedStyle类)的Base属性中。在代码读取到B标签的结束部分之前,一直会应用B标签的样式。一旦读到B标签的结束部分,就会从B标签样式(ZLTextFullDecoratedStyle类)的Base属性中中取出基本样式(ZLTextBaseStyle)。然后又开始应用基本样式。

类似的例子还有H1标签。在显示流程之前,H1标签会被转化为这样的格式:“代表P标签起始部分的ZLTextControlElement类 代表P标签起始部分的ZLTextControlElement类 + P标签内的文本内容 代表P标签结束部分的ZLTextControlElement类 代表P标签结束部分的ZLTextControlElement类”(请参考第七章中对相关流程的介绍)。

当代码在读取带P标签的起始部分之前,都在应用基本样式。一旦读到P标签的起始部分,代码就会新建一个P标签样式覆盖掉基本样式,并将基本样式存储到P标签样式的Base属性。接着,程序又读取到H1标签的起始部分,此时又会新建一个H1标签样式覆盖掉P标签样式,并将P标签样式存储到H1标签样式的Base属性。当代码读取到H1标签内的文本内容时,会一直应用H1标签的样式。之后,一旦代码读取到H1标签的结束部分,就会从H1标签样式的Base属性中取出P标签样式,之后代码又读到P标签的结束部分,又从P标签样式的Base属性中取出基本样式。至此为止,代码又开始恢复应用基本样式了。




第十章、epub文件处理 -- 样式处理