CKEditor 是当前最为知名的 HTML 编辑器,它具有所有主流 HTML 编辑器所应当具备的特点:所见即所得、简单易用、开源并支持各种主流的浏览器(IE、Oper、FireFox、Chrome、Safari)。最重要的是,CKEditor 经过 10 年的不断完善和更新,其稳定性和兼容性已经不容质疑。
一、下载
CKEditor 最新版本当前为 4.3。进入 CKEditor 的下载页面(http://ckeditor.com/download),你会看到 4.3 版本又分为3个版本:基本版、标准版、完全版。
在这里我们仅使用标准版。选择标准版(Standard Package)进行下载。
下载后得到一个压缩文件ckeditor_4.3_basic.zip。
二、安装
将压缩文件解压缩到一个指定的文件夹,例如 ckeditor4.3 文件夹。然后将 ckeditor 文件夹整个地拖到你的项目中(选择“Copy Items...”和“Create folder”选项)。
这样,ckeditor4.3 目录会以“文件夹”而不是“group”的形式存在于项目中。
注意,文件夹是蓝色图标,而 group 是黄色图标。
现在可以在项目中使用 CKEditor 了。三、使用 CKEditor
现在使用“New File...->iOS->Other->Empty”在项目中新建一个 test.html文件。注意它和 ckeditor4.3的相对位置:
编辑 test.html 如下:
<!DOCTYPE html>
<html>
<head>
<title>CKEditor Sample</title>
<scriptsrc="ckeditor4.3/ckeditor.js"></script>
</head>
<body>
<textareaname="editor1">#{*CKEditorcontent text*}#</textarea>
<script>
CKEDITOR.replace( 'editor1' );
</script>
</body>
</html>
主要注意以下3个地方:
<scriptsrc="ckeditor4.3/ckeditor.js"></script>
这句脚本将导入 cheditor.js 脚本(即CKEditor引擎)。注意 src 属性并不以斜杠“/”开头,表明这是一个相对路径(相对于文件 test.html 本身)。如果 src 写错了,CKEditor 将无法启动。
<textareaname="editor1">#{*CKEditorcontent text*}#</textarea>
<textarea/>在这里其实只是起到了“占位符”的作用,我们给它一个名字 editor1,方便在脚本中调用这个控件,利用脚本将它替换成真正的 CKEditor 控件。#{*CKEditor content text*}# 也是占位符,以后我们可以通过这个特征字符串将其用某些内容替换,这样 CKEditor 控件会在文本框中显示指定的 HTML 内容。
CKEDITOR.replace('editor1' );
这句脚本将名为 editor1 的 <textarea/> 控件替换成 CKEditor 对象。
有了 test.html,我们需要在 ViewController 中加载它,以便使用 CKEditor。
在故事板编辑器中,在 ViewController 拖一个按钮和一个WebView。
打开 AssistantEditor,将 WebView 连接至 IBOutlet webView,将按钮的 TouchUpInside 事件连接至 IBAction send: 方法。
在 viewDidLoad 方法中,在 WebView 中加载 test.html 文件:
NSString*filePath = nil;
filePath= [[NSBundle mainBundle] pathForResource:@"test" ofType:@"html"];
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:filePath]]];
实现 send: 方法,通过 js 脚本获取当前 CKEditor 控件中的 HTML 内容:
- (IBAction)send:(id)sender {
NSString*html=[self.webView stringByEvaluatingJavaScriptFromString:@"CKEDITOR.instances.editor1.getData()"];
showMessage(html);
}
运行程序,如果一切正确,你将在 iPhone(请在设备上测试,不要在模拟器中测试)看到一个默认的 HTML 编辑器,编辑器中支持的所有工具栏按钮都显示出来了。编辑一些内容,点击按钮,将弹出一个消息框,显示正在编辑的 HTML 源码内容:
三、定制编辑器界面
1、定制工具栏
绝大部分情况下,你不需要显示全部的工具栏按钮,你可以在CKEDITOR.replace语句中定制自己的工具栏:
CKEDITOR.replace( 'editor1',
{
removePlugins:'elementspath',
toolbar : [ ['Source', '-', 'FontSize', '-', 'TextColor', 'Bold', 'Italic', 'Underline'],'/',['Subscript','Superscript', '-','JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock','Link', 'Unlink' ]]
});
其中,removePlugins: 'elementspath' 将编辑器下边的元素标签工具移除。
toolbar: 中的内容则制定了我们将要使用的按钮。可以看到我们定义了许多标签,分为两个组(用“[]”分隔组,“-”为分隔条,“/”为换行),但由于标准版只实现了有限的功能,所以并不是所有标签都能被显示为工具栏按钮,比如 FontSize、TextColor、Subscript、Superscript、JustifyLeft、JustifyCenter、JustifyRight、JustifyBlock 都是 4.3 或者标准版中没有实现的,并不能在工具栏中显示。完整的按钮列表请在 ckeditor.js 中搜索“ui.addButton(”字样。
2、指定编辑器中的内容
由于我们使用了特征字符串,我们可以在 viewDidLoad 方法中将特征字符串替换为指定内容,以便显示在编辑器中:
NSMutableString *templateString = [NSMutableString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
[templateString replaceOccurrencesOfString:@"#{*CKEditorcontent text*}#"
withString:@"<h3>Hello</h3>"
options: NSLiteralSearch range:NSMakeRange(0, [templateString length] - 1)];
NSData*htmlData = [templateString dataUsingEncoding: NSUTF8StringEncoding];
if(htmlData){
NSURL* baseURL =[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
[self.webView loadData:htmlDataMIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:baseURL];
}
除此之外,我们也可以用脚本方式进行:
-(void)webViewDidFinishLoad:(UIWebView *)webView{
[_webView stringByEvaluatingJavaScriptFromString:@"document.getElementById('editor1').innerHTML='<em>Hello</em><i>World</i>!';"];
}
3、旋屏支持
在竖屏的情况下,CKEditor 的大小总是适应 iPhone 屏幕的。但当你旋转屏幕时,情况发生了改变,它显得略微太高了一些,屏幕似乎不能刚好显示下。
我们需要在横屏时修改它的尺寸:
-(BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)toInterfaceOrientation{
if(toInterfaceOrientation==UIInterfaceOrientationLandscapeLeft ||
toInterfaceOrientation==UIInterfaceOrientationLandscapeRight) {
[self autosizeCKEditor];
}
return YES;
}
-(void)autosizeCKEditor{
CGRect r=_webView.frame;
NSString*script = [NSString stringWithFormat:@"CKEDITOR.instances.editor1.resize(\'100%%\', \'%.0f\' );",r.size.height];
[self.webView stringByEvaluatingJavaScriptFromString:script];
}
这样当横屏时,它自动和 webView 的高度适配。
而 webView 的 autosizing 属性则被我修改为如下所示:
4、定制 inputAccessoryView
UIWebView 的 inputAccessoryView 上有两个按钮 previous 和 next。这两个按钮通常都不会有任何用处。这非常烦人,但我们可以去掉它。我们可以使用这篇博客中的技巧:
http://ios-blog.co.uk/tutorials/rich-text-editing-a-simple-start-part-1/
首先在 viewDidLoad 方法中监听键盘事件:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
实现 keyboardWillShow 方法:
UIWindow*keyboardWindow = nil;
for (UIWindow*testWindow in [[UIApplication sharedApplication] windows]) {
if(![[testWindow class] isEqual:[UIWindow class]]) {
keyboardWindow = testWindow;
break;
}
}
for (UIView*possibleFormView in [keyboardWindow subviews]) {
if([[possibleFormView description] rangeOfString:@"UIPeripheralHostView"].location != NSNotFound) {
for (UIView*subviewWhichIsPossibleFormView in [possibleFormView subviews]) {
if ([[subviewWhichIsPossibleFormView description] rangeOfString:@"UIWebFormAccessory"].location != NSNotFound) {
[subviewWhichIsPossibleFormView removeFromSuperview];
}
}
}
}
这段代码中使用的仍然是无敌的“class dump”大法,首先找出键盘所在的UIWindow,然后再从中找出 WebView 的 Accessory 并删除它。
除此之外,我们也有简单一点的方法。在http://bjhomer.blogspot.com/2012/03/how-to-hide-inputaccessoryview-of.html这篇博客中,提供了一个 UIWebView 的新类别( HideInputAccessoryView),你可以用它来实现同样的目的。
在 webViewDidFinishLoad: 方法里,加入如下代码:
[self autosizeCKEditor];
if (![self.htmlEditorView isHidesInputAccessoryView])
{
[self.htmlEditorViewhidesInputAccessoryView:YES];
}
OK,这是运行的最终效果,键盘上方的 inputAccessoryView 已然被移除。
最后,我们列出所需的 UIWebView 类别完整定义:
/** UIWebView+AccessoryHiding.h **/
@interface UIWebView (HideInputAccessoryView)
-(BOOL)isHidesInputAccessoryView;
-(void)hidesInputAccessoryView:(BOOL)value;
@end
/** UIWebView+AccessoryHiding.m **/
#import"UIWebView+AccessoryHiding.h"
#import<objc/runtime.h>
@implementation UIWebView (HideInputAccessoryView)
static const char * consthackishFixClassName = "UIWebBrowserViewMinusAccessoryView";
static Class hackishFixClass = Nil;
- (UIView *) hackishlyFoundBrowserView {
UIScrollView *scrollView = self.scrollView;
UIView *browserView = nil;
for (UIView*subview in scrollView.subviews) {
if ([NSStringFromClass([subviewclass]) hasPrefix:@"UIWebBrowserView"]) {
browserView = subview;
break;
}
}
return browserView;
}
- (id)methodReturningNil {
return nil;
}
- (void)ensureHackishSubclassExistsOfBrowserViewClass:(Class)browserViewClass {
if (!hackishFixClass){
id newClass = objc_allocateClassPair(browserViewClass,hackishFixClassName, 0);
IMP nilImp = [selfmethodForSelector:@selector(methodReturningNil)];
class_addMethod(newClass, @selector(inputAccessoryView), nilImp, "@@:");
objc_registerClassPair(newClass);
hackishFixClass = newClass;
}
}
- (BOOL) isHidesInputAccessoryView {
UIView *browserView = [selfhackishlyFoundBrowserView];
return [browserView class]== hackishFixClass;
}
- (void) hidesInputAccessoryView:(BOOL)value {
UIView *browserView = [selfhackishlyFoundBrowserView];
if (browserView == nil){
return;
}
[self ensureHackishSubclassExistsOfBrowserViewClass:[browserViewclass]];
if (value) {
object_setClass(browserView, hackishFixClass);
}
else {
Class normalClass = objc_getClass("UIWebBrowserView");
object_setClass(browserView, normalClass);
}
[browserView reloadInputViews];
}
@end
注:目前 CKEditor 对 iOS 的支持仍然有一些问题,如果 ViewController 中存在其他可编辑控件(TextField、TextView 或 TITokenField ),则 CKEditor 将会出现异常,比如键盘不会弹出或者弹出后无法隐藏等等。