网络开发中,当公司已经使用 HTML5 技术实现同时适应 Android 和 iOS 等多个平台的网页时,这时往往需要我们 iOS 平台能够嵌入网页并进行各种交互,那我们应该怎么做来实现这种需求呢?

这里我们考虑的方案就是:使用 UIWebView 网页控件

然而考虑使用 UIWebView 进行混合编程的场景特点有:

(1)排版复杂:通常包括图片和文字的混排,还有可能包括链接需要支持点击操作。如果自己用原生控件拼装实现,由于界面元素过多,做起来会很困难。就算是使用 CoreText 来实现,也需要自己实现相当多的复杂排版逻辑。

(2)界面的变动需求频繁:例如淘宝 App 的彩票页面,可能常常需要更新界面以推出不同的活动。采用 UIWebView 嵌套页面实现后,这类页面不需要向 App Store 提交新的版本就可以动态地更新,而原生控件实现的界面很难达到如此高的灵活性。

(3)界面对用户的交互需求不复杂:因为 UIWebView 实现的交互效果与原生效果相比还是会大打折扣,所以这类界面通常都没有复杂的交互效果。这也是主流 App 大多采用混合 UIWebView 来实现界面而不是使用纯 UIWebView 来实现界面的原因之一,另外的原因是纯 UIWebView 实现的性能也没原生的好,而且纯 UIWebView 实现的话根本无法通过 App Store 的审核,他会建议您搞 Web App。

本随笔简单介绍如何使用 UIWebView 网页控件:

(1)简单浏览器

(2)页面交互;可以考虑使用模版引擎库 GRMustache:https://github.com/groue/GRMustache,方便阅读和更改渲染内容

(3)页面调用 OC 方法;可以考虑使用 JS 与 OC 交互库「WebViewJavascriptBridge」:https://github.com/marcuswestin/WebViewJavascriptBridge,方便 JS 与 OC 之间发送消息进行交互

效果如下:

ViewController.h

 #import <UIKit/UIKit.h>

 @interface ViewController : UITableViewController
@property (copy, nonatomic) NSArray *arrSampleName; - (instancetype)initWithSampleNameArray:(NSArray *)arrSampleName; @end 

ViewController.m

 #import "ViewController.h"
#import "SimpleBrowserViewController.h"
#import "PageInteractionViewController.h"
#import "PageCallOCFunctionViewController.h" @interface ViewController ()
- (void)layoutUI;
@end @implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad]; [self layoutUI];
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} - (instancetype)initWithSampleNameArray:(NSArray *)arrSampleName {
if (self = [super initWithStyle:UITableViewStyleGrouped]) {
self.navigationItem.title = @"UIWebView 操作";
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:nil action:nil]; _arrSampleName = arrSampleName;
}
return self;
} - (void)layoutUI { } #pragma mark - UITableViewController相关方法重写
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 0.1;
} - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return ;
} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [_arrSampleName count];
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = _arrSampleName[indexPath.row];
return cell;
} - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
switch (indexPath.row) {
case : {
SimpleBrowserViewController *simpleBrowserVC = [SimpleBrowserViewController new];
[self.navigationController pushViewController:simpleBrowserVC animated:YES];
break;
}
case : {
PageInteractionViewController *pageInteractionVC = [PageInteractionViewController new];
[self.navigationController pushViewController:pageInteractionVC animated:YES];
break;
}
case : {
PageCallOCFunctionViewController *pageCallOCFunctionVC = [PageCallOCFunctionViewController new];
[self.navigationController pushViewController:pageCallOCFunctionVC animated:YES];
break;
}
default:
break;
}
} @end 

PrefixHeader.pch

 #define kTitleOfSimpleBrowser @"简单浏览器"
#define kTitleOfPageInteraction @"页面交互"
#define kTitleOfPageCallOCFunction @"页面调用 OC 方法" #define kApplication [UIApplication sharedApplication] 

SimpleBrowserViewController.h

 #import <UIKit/UIKit.h>

 @interface SimpleBrowserViewController : UIViewController <UISearchBarDelegate, UIWebViewDelegate>
@property (strong, nonatomic) UISearchBar *searchBar;
@property (strong, nonatomic) UIWebView *webView;
@property (strong, nonatomic) UIToolbar *toolbar;
@property (strong, nonatomic) UIBarButtonItem *barBtnBack;
@property (strong, nonatomic) UIBarButtonItem *barBtnForward; @end 

SimpleBrowserViewController.m

 #import "SimpleBrowserViewController.h"

 @interface SimpleBrowserViewController ()
- (void)webViewBack;
- (void)webViewForward;
- (void)layoutUI;
- (void)sendRequest:(NSString *)requestURLStr;
- (void)changeBarButtonStatus;
@end @implementation SimpleBrowserViewController - (void)viewDidLoad {
[super viewDidLoad]; [self layoutUI];
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} - (void)webViewBack {
[_webView goBack];
} - (void)webViewForward {
[_webView goForward];
} - (void)layoutUI {
self.navigationItem.title = kTitleOfSimpleBrowser;
self.automaticallyAdjustsScrollViewInsets = NO; //是否自动适应滚动视图的内嵌入;默认为YES,这里设置为NO,避免网页控件中_UIWebViewScrollView的UIWebBrowserView位置偏移 CGRect rect = [[UIScreen mainScreen] bounds];
static const CGFloat heightOfStatusBarAndNavigationBar = 64.0;
CGFloat widthOfScreen = rect.size.width;
CGFloat heightOfScreen = rect.size.height; //添加搜索栏
_searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0, heightOfStatusBarAndNavigationBar, widthOfScreen, 44.0)];
_searchBar.delegate = self;
_searchBar.placeholder = @"请输入以file://或http开头的地址";
[self.view addSubview:_searchBar]; //添加工具栏和左右按钮(回退和前进)
_toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, heightOfScreen - 44.0,
widthOfScreen, 44.0)];
rect = CGRectMake(0.0, 0.0, 32.0, 32.0);
UIButton *btnBack = [UIButton buttonWithType:UIButtonTypeCustom];
btnBack.frame = rect;
[btnBack setImage:[UIImage imageNamed:@"LastPageNormal"] forState:UIControlStateNormal];
[btnBack setImage:[UIImage imageNamed:@"LastPageDisabled"] forState:UIControlStateDisabled];
[btnBack addTarget:self
action:@selector(webViewBack)
forControlEvents:UIControlEventTouchUpInside];
_barBtnBack = [[UIBarButtonItem alloc] initWithCustomView:btnBack];
_barBtnBack.enabled = NO; UIBarButtonItem *barBtnSpacing=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; UIButton *btnForward = [UIButton buttonWithType:UIButtonTypeCustom];
btnForward.frame = rect;
[btnForward setImage:[UIImage imageNamed:@"NextPageNormal"] forState:UIControlStateNormal];
[btnForward setImage:[UIImage imageNamed:@"NextPageDisabled"] forState:UIControlStateDisabled];
[btnForward addTarget:self
action:@selector(webViewForward)
forControlEvents:UIControlEventTouchUpInside];
_barBtnForward = [[UIBarButtonItem alloc] initWithCustomView:btnForward];
_barBtnForward.enabled = NO; _toolbar.items = @[ _barBtnBack, barBtnSpacing, _barBtnForward ];
[self.view addSubview:_toolbar]; //添加网页控件
CGFloat heightOfWebView = heightOfScreen - _searchBar.frame.origin.y - _searchBar.frame.size.height - _toolbar.frame.size.height;
_webView = [[UIWebView alloc] initWithFrame:CGRectMake(0.0, heightOfStatusBarAndNavigationBar + _searchBar.frame.size.height,
widthOfScreen, heightOfWebView)];
_webView.dataDetectorTypes = UIDataDetectorTypeAll;
_webView.delegate = self;
[self.view addSubview:_webView];
} - (void)sendRequest:(NSString *)requestURLStr {
if (requestURLStr.length > ) {
NSURL *requestURL; //加载bundle中的文件;网页控件打开本地pdf、word文件依靠的并不是他自身解析,而是依靠MIME Type识别文件类型并调用对应应用打开
if ([requestURLStr hasPrefix:@"file://"]) {
NSRange range = [requestURLStr rangeOfString:@"file://"];
NSString *fileName = [requestURLStr substringFromIndex:range.length];
requestURL = [[NSBundle mainBundle] URLForResource:fileName
withExtension:nil];
} else {
//加载百度搜索网站的内容
if (![requestURLStr hasPrefix:@"http"]) {
requestURLStr = [NSString stringWithFormat:@"https://www.baidu.com/s?wd=%@", requestURLStr];
}
//最终加载的还是HTTP或者HTTPS协议的网站内容,进行编码操作
requestURLStr = [requestURLStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
requestURL = [NSURL URLWithString:requestURLStr];
} //加载请求地址内容
[_webView loadRequest:[NSURLRequest requestWithURL:requestURL]];
}
} - (void)changeBarButtonStatus {
_barBtnBack.enabled = _webView.canGoBack;
_barBtnForward.enabled = _webView.canGoForward;
} #pragma mark - UIWebViewDelegate
- (void)webViewDidStartLoad:(UIWebView *)webView {
kApplication.networkActivityIndicatorVisible = YES;
} - (void)webViewDidFinishLoad:(UIWebView *)webView {
kApplication.networkActivityIndicatorVisible = NO;
[self changeBarButtonStatus];
} - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
NSLog(@"Error: %@", error);
kApplication.networkActivityIndicatorVisible = NO;
UIAlertView *alertVCustom = [[UIAlertView alloc] initWithTitle:@"提示信息"
message:@"网络连接错误"
delegate:nil
cancelButtonTitle:@"确定"
otherButtonTitles:nil, nil];
[alertVCustom show];
} #pragma mark - UISearchBarDelegate
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[self sendRequest:searchBar.text];
[_searchBar resignFirstResponder];
} @end 

PageInteractionViewController.h

 #import <UIKit/UIKit.h>

 @interface PageInteractionViewController : UIViewController<UIWebViewDelegate>
@property (strong, nonatomic) UIWebView *webView; @end 

PageInteractionViewController.m

 #import "PageInteractionViewController.h"

 @interface PageInteractionViewController ()
- (void)layoutUI;
- (void)sendRequest;
@end @implementation PageInteractionViewController - (void)viewDidLoad {
[super viewDidLoad]; [self layoutUI]; [self sendRequest];
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} - (void)layoutUI {
self.navigationItem.title = kTitleOfPageInteraction;
self.automaticallyAdjustsScrollViewInsets = NO; //是否自动适应滚动视图的内嵌入;默认为YES,这里设置为NO,避免网页控件中_UIWebViewScrollView的UIWebBrowserView位置偏移 CGRect rect = [[UIScreen mainScreen] bounds];
static const CGFloat heightOfStatusBarAndNavigationBar = 64.0;
//添加网页控件
_webView = [[UIWebView alloc] initWithFrame:CGRectMake(0.0, heightOfStatusBarAndNavigationBar,
rect.size.width, rect.size.height - heightOfStatusBarAndNavigationBar)];
_webView.dataDetectorTypes = UIDataDetectorTypeAll;
_webView.delegate = self;
self.automaticallyAdjustsScrollViewInsets = NO;
[self.view addSubview:_webView];
} - (void)sendRequest {
NSString *htmlStr=@"<html>\
<head><title>KenmuHuang's Blog</title></head>\
<body style=\"color:#0044AA;\">\
<h3 id=\"header\">I'm KenmuHuang</h3>\
<p>More coding, more thinking. Stay hungry, stay foolish.</p>\
<span>http://www.cnblogs.com/huangjianwu/</span>\
</body>\
</html>";
[_webView loadHTMLString:htmlStr baseURL:nil];
} #pragma mark - UIWebViewDelegate
- (void)webViewDidStartLoad:(UIWebView *)webView {
kApplication.networkActivityIndicatorVisible = YES;
} - (void)webViewDidFinishLoad:(UIWebView *)webView {
kApplication.networkActivityIndicatorVisible = NO;
NSLog(@"%@",[_webView stringByEvaluatingJavaScriptFromString:@"document.title"]); //打印内容为html的title标签内容:KenmuHuang's Blog
NSLog(@"%@",[_webView stringByEvaluatingJavaScriptFromString:@"document.getElementById('header').innerHTML='KenmuHuang\\'s Blog';"]); //必须使用双反斜杆来转译单引号
} - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
NSLog(@"Error: %@", error);
kApplication.networkActivityIndicatorVisible = NO;
UIAlertView *alertVCustom = [[UIAlertView alloc] initWithTitle:@"提示信息"
message:@"网络连接错误"
delegate:nil
cancelButtonTitle:@"确定"
otherButtonTitles:nil, nil];
[alertVCustom show];
} @end 

RedirectURL.js

 function showSheet(title, cancelButtonTitle, destructiveButtonTitle, otherButtonTitle) {
var url = 'KMActionSheet://?';
var paramas = title + '&' + cancelButtonTitle + '&' + destructiveButtonTitle;
if(otherButtonTitle) {
paramas += '&' + otherButtonTitle;
}
window.location.href = url + encodeURIComponent(paramas);
} var header = document.getElementById('header');
if(header) {
header.onclick = function(){
showSheet('系统提示', '取消', '确定', null);
};

PageCallOCFunctionViewController.h

 #import <UIKit/UIKit.h>

 @interface PageCallOCFunctionViewController : UIViewController<UIWebViewDelegate>
@property (strong, nonatomic) UIWebView *webView; @end 

PageCallOCFunctionViewController.m

 #import "PageCallOCFunctionViewController.h"

 @interface PageCallOCFunctionViewController ()
- (void)layoutUI;
- (void)sendRequest;
- (void)showActionSheetWithTitle:(NSString *)title cancelButtonTitle:(NSString *)cancelButtonTitle destructiveButtonTitle:(NSString *)destructiveButtonTitle otherButtonTitle:(NSString *)otherButtonTitle;
@end @implementation PageCallOCFunctionViewController - (void)viewDidLoad {
[super viewDidLoad]; [self layoutUI]; [self sendRequest];
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} - (void)layoutUI {
self.navigationItem.title = kTitleOfPageCallOCFunction;
self.automaticallyAdjustsScrollViewInsets = NO; //是否自动适应滚动视图的内嵌入;默认为YES,这里设置为NO,避免网页控件中_UIWebViewScrollView的UIWebBrowserView位置偏移 CGRect rect = [[UIScreen mainScreen] bounds];
static const CGFloat heightOfStatusBarAndNavigationBar = 64.0;
//添加网页控件
_webView = [[UIWebView alloc] initWithFrame:CGRectMake(0.0, heightOfStatusBarAndNavigationBar,
rect.size.width, rect.size.height - heightOfStatusBarAndNavigationBar)];
_webView.dataDetectorTypes = UIDataDetectorTypeAll;
_webView.delegate = self;
self.automaticallyAdjustsScrollViewInsets = NO;
[self.view addSubview:_webView];
} - (void)sendRequest {
NSString *htmlStr=@"<html>\
<head><title>KenmuHuang's Blog</title></head>\
<body style=\"color:#0044AA;\">\
<h3 id=\"header\">I'm KenmuHuang, click me to show action sheet.</h3>\
<p>More coding, more thinking. Stay hungry, stay foolish.</p>\
<span>http://www.cnblogs.com/huangjianwu/</span>\
</body>\
</html>";
[_webView loadHTMLString:htmlStr baseURL:nil];
} - (void)showActionSheetWithTitle:(NSString *)title cancelButtonTitle:(NSString *)cancelButtonTitle destructiveButtonTitle:(NSString *)destructiveButtonTitle otherButtonTitle:(NSString *)otherButtonTitle{
UIActionSheet *actionSheet=[[UIActionSheet alloc] initWithTitle:title
delegate:nil
cancelButtonTitle:cancelButtonTitle
destructiveButtonTitle:destructiveButtonTitle
otherButtonTitles:otherButtonTitle, nil];
[actionSheet showInView:self.view];
} #pragma mark - UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
BOOL isStartLoad = YES;
if ([request.URL.scheme isEqualToString:@"kmactionsheet"]) { //request.URL.scheme 返回全小写的内容
NSString *paramContent = request.URL.query;
NSArray *arrParam = [[paramContent stringByRemovingPercentEncoding] componentsSeparatedByString:@"&"];
NSString *otherButtonTitle = nil;
if (arrParam.count > ) {
otherButtonTitle = arrParam[];
} [self showActionSheetWithTitle:arrParam[]
cancelButtonTitle:arrParam[]
destructiveButtonTitle:arrParam[]
otherButtonTitle:otherButtonTitle];
isStartLoad = NO;
}
return isStartLoad;
} - (void)webViewDidStartLoad:(UIWebView *)webView {
kApplication.networkActivityIndicatorVisible = YES;
} - (void)webViewDidFinishLoad:(UIWebView *)webView {
kApplication.networkActivityIndicatorVisible = NO; //加载用于重定向地址的JavaScript内容
NSString *jsPath = [[NSBundle mainBundle] pathForResource:@"RedirectURL.js" ofType:nil];
NSString *jsContent = [NSString stringWithContentsOfFile:jsPath
encoding:NSUTF8StringEncoding
error:nil];
[_webView stringByEvaluatingJavaScriptFromString:jsContent];
} - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
NSLog(@"Error: %@", error);
kApplication.networkActivityIndicatorVisible = NO;
UIAlertView *alertVCustom = [[UIAlertView alloc] initWithTitle:@"提示信息"
message:@"网络连接错误"
delegate:nil
cancelButtonTitle:@"确定"
otherButtonTitles:nil, nil];
[alertVCustom show];
} @end 

AppDelegate.h

 #import <UIKit/UIKit.h>

 @interface AppDelegate : UIResponder <UIApplicationDelegate>

 @property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UINavigationController *navigationController; @end 

AppDelegate.m

 #import "AppDelegate.h"
#import "ViewController.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController *viewController = [[ViewController alloc]
initWithSampleNameArray:@[ kTitleOfSimpleBrowser,
kTitleOfPageInteraction,
kTitleOfPageCallOCFunction ]];
_navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
_window.rootViewController = _navigationController;
//[_window addSubview:_navigationController.view]; //当_window.rootViewController关联时,这一句可有可无
[_window makeKeyAndVisible];
return YES;
} - (void)applicationWillResignActive:(UIApplication *)application {
} - (void)applicationDidEnterBackground:(UIApplication *)application {
} - (void)applicationWillEnterForeground:(UIApplication *)application {
} - (void)applicationDidBecomeActive:(UIApplication *)application {
} - (void)applicationWillTerminate:(UIApplication *)application {
} @end

UIWebView 操作的更多相关文章

  1. 【IOS 开发】基本 UI 控件详解 (UIDatePicker | UIPickerView | UIStepper | UIWebView | UIToolBar )

    转载注明出处 : http://blog.csdn.net/shulianghan/article/details/50348982 一. 日期选择器 (UIDatePicker) UIDatePic ...

  2. [Xcode 实际操作]四、常用控件-(13)使用UIWebView控件加载网页

    目录:[Swift]Xcode实际操作 本文将演示网页视图的使用. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit class ViewC ...

  3. [Xcode 实际操作]四、常用控件-(14)使用UIWebView控件加载本地HTML

    目录:[Swift]Xcode实际操作 本文将演示使用网页视图,加载并渲染网页代码. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit im ...

  4. iOS网络3—UIWebView与WKWebView使用详解

    一.整体介绍 UIWebView自iOS2就有,WKWebView从iOS8才有,毫无疑问WKWebView将逐步取代笨重的UIWebView.通过简单的测试即可发现UIWebView占用过多内存,且 ...

  5. UIwebView 和 H5交互详情

    背景: 最近公司准备上一个只有原生登录界面 + H5网页 ,并且支持ios7.0 以上系统的混合app;这可把我难住了,原生的UI界面我可以正写反写各种style把界面搭建起来.而要这个app的难点在 ...

  6. IOS 错误 [UIWebView cut:]: unrecognized selector sent to instance

    那在什么场景中会出现这种情况呢? 如果一个包含文字的输入元素有焦点,然后按钮的点击会导致输入失去焦点,然后接下来在输入时双按会重新得到焦点并从弹出bar中选择剪切复制粘贴,就会导致此error. 也就 ...

  7. UIWebView的使用

    iOS中UIWebView的使用详解 一.初始化与三种加载方式 UIWebView继承与UIView,因此,其初始化方法和一般的view一样,通过alloc和init进行初始化,其加载数据的方式有三种 ...

  8. (转)UIWebView全部API学习

    网上找的收藏一下 http://www.myexception.cn/web/1888974.html 最生僻的API做了下划线以及粗体的标注.百度上查了全是拷贝的同一份代码,而且只有代码没有解释,很 ...

  9. cell嵌套UIWebView遇到的几个问题

    一.防止死循环问题 方法一:使用动画块  [self.myTableView beginUpdates];[self.myTableView endUpdates];            在下面的代 ...

随机推荐

  1. C#像运行一个exe 程序一样运行一个dll文件

    [DllImport("kernel32.dll")] public static extern int WinExec(string exeName, int operType) ...

  2. Android---组件篇---Handler的使用(1)[转]

    在android中,有很多功能是不能放在onCreate或者onStart方法里面,因为这些功能相对 来说费时比较长,比如说下载一个文件,下载的过程比较长,但是如果写在Activity中, 那么这段时 ...

  3. html5之canvas画图

    导航 前言 基本知识 绘制矩形 清除矩形区域 圆弧 路径 绘制线段 绘制贝塞尔曲线 线性渐变 径向渐变(发散) 图形变形(平移.旋转.缩放) 矩阵变换(图形变形的机制) 图形组合 给图形绘制阴影 绘制 ...

  4. cookie and session

    Session is used to save the message for the hole period of user dialogue in web service.Such as the ...

  5. PAIP.并发编程 多核编程 线程池 ExecutorService的判断线程结束

    PAIP.并发编程 多核编程 线程池 ExecutorService的判断线程结束 ExecutorService并没有提供什么 isDone()或者isComplete()之类的方法. 作者Atti ...

  6. Maven学习总结(五)——聚合与继承

    一.聚合 如果我们想一次构建多个项目模块,那我们就需要对多个项目模块进行聚合 1.1.聚合配置代码 <modules> <module>模块一</module> & ...

  7. [推荐]Hadoop+HBase+Zookeeper集群的配置

    [推荐]Hadoop+HBase+Zookeeper集群的配置 Hadoop+HBase+Zookeeper集群的配置  http://wenku.baidu.com/view/991258e881c ...

  8. Android平台免Root无侵入AOP框架Dexposed使用详解

    Dexposed是基于久负盛名的开源Xposed框架实现的一个Android平台上功能强大的无侵入式运行时AOP框架. Dexposed的AOP实现是完全非侵入式的,没有使用任何注解处理器,编织器或者 ...

  9. Python 3 数值计算

    Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:43:06) [MSC v.1600 32 bit (Intel)] on win32Type & ...

  10. 动态变化的OO设计

    今天看到个题目:对象会动态的变化. 游戏精灵,有人和神仙,但是随着人的不断积分,会升级为神仙:神仙也可能会因为积分的减少而降级为人.这种情况怎么画出个类图来. 这是第一版的设计,正常思维.人和神仙都是 ...