今天开始学IOS咯!其实是因为我OC的书忘在家里了,Macbook还没到,再不到的话我可能还没学完整个人都先疯掉了QAQ
我得找个时间签一下转租合同什么的,马上就要到月底了嗝
晚上回去再说吧
Let’s start!
Inspire Creativity, Enrich Life
UIView
是最基础的类,UIKit中的一个部分用于布局和管理所有的子View
布局的时候设置大小和位置(frame)位置用的是左上角的坐标
frame使用CGRect类实现
管理子View的时候是用的栈结构,位置重叠的话会优先展示栈顶的元素
1 2 3 4 |
UIView *view = [[UIView alloc] init]; view.backgroundColor = [UIColor redColor]; view.frame = CGRectMake[100, 100, 100, 100]; [self.view addSubView: view]; |
类似这样的方法可以创建一个UIView
背景颜色设置:
1 |
self.view.backgroundColor = [UIColor whiteColor]; |
这样的方法可以将背景色变成白色
我们可以创建一个UIView的子类并重写部分方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
@interface TestView : UIView @end @implementation TestView - (instancetype) init{ self = [super init]; if(self){ } return self; - (void)willMoveToSuperview:(nullable UIView *)newSuperview{ [super willMoveToSuperview]; } - (void) didMoveToSuperview{ [super didMoveToSuperview]; } - (void) willMoveToWindow:(nullable UIView *) newWindow{ [super willMoveToWindow:newWindow]; } - (void)didMoveToWindow{ [super didMoveToWindow]; } |
通过单步调试我们发现UIView生命周期
- willMoveToSuperview
- didMoveToSuperview
- willMoveToWindow
- didMoveToWindow
我们可以通过自定义函数来实现一部分的功能
UIViewController
视图控制器,自身包含View(UIViewController Default View),是一个包含多个View的容器
在我们创建一个UIView的时候,会将其粘贴到UIViewController中的View中,所以可以实现对全部视图的管理
- 可以管理View视图的生命周期
- 响应用户操作
- 和App整体交互,视图的切换
- 作为一个container管理多个Controller和动画
例如滚动的相应就是UIViewController响应的,点击一个页面向左拉出一个页面也是UIViewController的功能
UIViewController生命周期
- init
- viewDidLoad 用于View的初始化
- viewWillAppear
- viewDidAppear 展示View的函数
- viewWillDisappear
- viewDidDisappear
- dealloc
利用UIView和UIViewController搭建App
- UIView负责页面内内容呈现
- 基础的UIViewController可以管理多个UIView
- 高级的UIViewController可以管理多个UIViewController
- UIViewController在管理UIView的同时,可以负责不同页面的切换
单页面展示
- 采用列表滚动展示
- 通过较长滚动页面展示内容
多页面管理
- 4到5个底部按钮
- 通过Push的方式进行页面切换
UITabBar
视图加入UITabbarController
UITabBarButton用于交互
tabBarItem.image表示图片
tabBarItem.title表示下面的文字
UITabBarContoller
管理多个UIViewController来切换页面
setViewControllers
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
UITabBarController *tabbarController = [[UITabBarController alloc]init]; UIViewController *controller1 = [[UIViewController alloc] init]; controller1.view.backgroundColor = [UIColor redColor]; controller1.tabBarItem.title = @"新闻"; controller1.tarBarItem.image = [UIImage imagenamed: @"..."]; controller1.tarBarItem,selectedImage = [UIImage imagenamed: @"..."]; UIViewController *controller2 = [[UIViewController alloc] init]; controller2.view.backgroundColor = [UIColor yellowColor]; controller2.tabBarItem.title = @"视频"; UIViewController *controller3 = [[UIViewController alloc] init]; controller3.view.backgroundColor = [UIColor greenColor]; controller3.tabBarItem.title = @"推荐"; UIViewController *controller4 = [[UIViewController alloc] init]; controller4.view.backgroundColor = [UIColor lightGreyColor]; controller4.tabBarItem.title = @"我的"; [tabbarController setViewControllers:@[controller1, controller2, controller3, controller4]; self.window.rootViewController = tabbarController; |
💡是否可以用NSArray结合controller的重写来实现呢?
setViewControllers可以用于控制先后顺序
UINavigationController
同样也是栈结构,管理页面间的跳转
可以通过UINavigationBar操作来实现切换
本身并没有逻辑和视图,因而需要使用initWithRootViewController来进行初始化,例如:
1 2 |
ViewController *viewController = [[ViewController alloc]init]; UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController: viewController]; |
UINavigationBar
在屏幕顶部,backBarButtonItem backIndicatorImage字面意思,就是返回按钮和箭头。默认是上一个页面的title和返回按钮,rightBarButtonItem是右边的一个按钮
在最上面的例子中我们只需要用NavigationController替换上面的Controller即可
我们可以通过添加相应方法来推进一个新的UINavigatrionController
1 2 3 4 5 6 7 8 9 |
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget: self action:@selector(pushController)];//建立一个手势,可以访问一定的方法 [view2 addGestureRecognizer: tapGesture]; - (void)pushController{ UIViewController *viewController = [[UIViewController alloc]init]; viewController.view.backgroundColor = [UIColor whiteColor]; viewController.navigationItem.title = @"内容"; viewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: @"右侧标题" style: UIBarButtonItemStylePlain target: self action: nil]; [self.navigationController pushViewController: [[UIViewController alloc]init] animated: (BOOL)] }//这个是一个具体的方法,用来进入一个NavigationController控制的页面 |
navigationItem的titleView可以将顶上的title换成别的
小结
MVC结构
M(Model)
|
V(View)
|
C(Controller)
|
UIBarButtonItem
|
UITabBar
|
UITabBarController
|
UITabBarItem
|
UINavigationBar
|
UINavigationController
|
UIWindow
一个特殊形式的UIView,提供在App中展示内容的基础窗口
只作为容器,和ViewController一起协同工作
一般来说一个屏幕上面只能出现和展示一个UIWindow
一般storyboard会自动创建,当然我们可以手动创建
1 2 3 |
self.window = [[UIWindow alloc]initWithFram:[[UIScreen mainScreen] bounds]]; self.window.rootViewController = viewController; [self window makeKeyAndVisable]; |
我们需要通过rootViewController的方法来设置这个window的rootViewController
Apple推荐使用的是以下类型:

或者将NavigationController放在前面,这样会产生一个整体的页面切换

这样的效果是在切换的时候TabBar的会消失不见
Delegate设计模式
tabBar.delegate = self;
设置self为delegate的接收者,也就是实现方法的对象
需要实现部分方法
1 2 |
- (BOOL) tabBarController: (UITabBarController *) tabBarController shouldSelectViewController:(UIViewController *)viewController;//是否可以执行Controller的切换 - (void) tabBarController: (UITabBarController *) tabBarController didSelectViewController: (UIVIewController *)viewController;//执行完点击和切换操作后要执行的操作 |
设计者角度
提供一些使用者可以自定义的操作
@optional/@required 注解
提供@property – delegate
在对应的时机,让delegate自动执行对应的方法
使用者角度
使用delegate=self来自己调用自己的delegate
设置self为delegate的接收者:
1 |
tabBar.delegate = self; |
UITableView
用来处理的问题:
- 数据量大
- 样式较为统一
- 通常需要分组
- 垂直滚动
- 一般来说一个可视区只有一个
拥有以下控件:
- tableHeaderView 页眉
- tableFootView 页脚
- UITableViewCell 每一个模块
- UITableView 中间的列表模块
1 2 |
UITableView *tableView = [[UITableView alloc] initWithFrame: self.view.bounds]; [self.view addSubView: tableView]; |
UITableViewDataSource
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
UITableView *tableView = [[UITableView alloc] initWithFrame: self.view.bounds]; tableView.dataSource = self; [self.view addSubView: tableView]; //以下是required - (NSIngeter) tableView: (UITableView *)tableView numberOfRowsInSection (NSIngeter)section{ return 20; } - (UITableViewCell *)tableView: (UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier:@"id"]; cell.textLabel.text = @"主标题"; cell.detainTextLabel.text = @"副标题"; cell.imageView.image = [UIImage imageNamed:@"..."]; return cell; } |
UITableViewCell默认提供四种样式:
- UITableViewCellStyleDefault
- UITableViewCellStyleSubtitle
- UITableViewCellStyleValue1
- UITableViewCellStyleValue2
默认可以设置的地方:
- cell.imagecell
- cell.contentView
- cell.textLabel
- cell.detailTextLabel
内存回收
1 2 3 4 5 6 7 8 9 10 |
- (UITableViewCell *)tableView: (UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: @"id"]; if(!cell){ UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier:@"id"]; } cell.textLabel.text = @"主标题"; cell.detainTextLabel.text = @"副标题"; cell.imageView.image = [UIImage imageNamed:@"..."]; return cell; } |
需要展现的时候,从系统的复用回收池中取,如果取不到的话,就生成一个
这样的话就可以实现复用回收机制,如果数据特别多的话,那么只需要提供一部分即可
如何标记一个TableViewCell
NSIndexPath其中有两个属性section和row,标记了cell的位置
1 2 3 4 5 6 7 8 9 10 |
- (UITableViewCell *)tableView: (UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: @"id"]; if(!cell){ UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier:@"id"]; } cell.textLabel.text = [NSString stringWithFormat: @"主标题 - %@", @(indexPath.row)]; cell.detainTextLabel.text = @"副标题"; cell.imageView.image = [UIImage imageNamed:@"..."]; return cell; } |
这是只有一个section的时候,会自动标记位置
UITableViewDelegate
1 2 3 4 5 |
- (void) viewDidLoad{ ... tableView.delegate = self; ... } |
需要在ViewController的@interface中添加协议UITableViewDelegate
常用函数:
- willDisplayCell
- willDisplayHeaderView
- willDisplayFooterView
- didEndDisplayingCell
- didEndDisplayingHeaderView
- didEndDisplayingFooterView
- heightForRowAtIndexPath 设置高度(像素为单位,类型CGFloat)
- didSelectRowAtIndexPath 点击的回调函数,一般在这里写UIViewController等视图
1 2 3 4 5 |
- (void) tableView: (UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ UIViewController *controller = [[UIViewController alloc] init]; controller.title = [NSString stringWithFormat :@"%@", @(indexPath.row)]; [self.navigationController pushViewController: controller animated:YES]; } |
UICollectionView
提供列表展示的容器,内置复用回收池
相比UITableView支持纵向和横向的布局,会更加灵活,更多的动画
基于dataSource和delegated驱动的
不提供默认的样式
只有contentView / backgroundView
继承自UICollectionReusableView
必须先注册Cell才能进行重用
1 2 3 4 5 6 |
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc]init]; UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame: self.view.bounds collectionViewLayout:flowLayout]; collcetionView.delegate = self; collcetionView.dataSource = self; [collcetionView registerClass: [UICollectionViewCell class] forCellWithReuseIdentifier:@"UICollectionViewCell"]; [self.view addSubview: collectionView]; |
需要加入协议UICollectionViewDataSource、UICollectionViewDelegate
和UITable类似需要用- (NSInteger) collectionView:numberOfItemsInSection:来控制列表大小
也可以通过- (__kindof) UICollectionViewCell *)collectionView:cellForItemAtIndexPath:来从复用回收池中取一个(return [collectionView dequeueReusableCellWithReuseIdentifer:@”UICollectionViewCell” forIndexPath: indexPath])
默认大小50×50
UICollectionViewDataSource
- numberOfItemsInSection: (NSIngeter) section;
- cellForItemAtIndexPath: (NSIndexPath *)indexPath;
UICollectionViewDelegates
- willDisplayCell / endDisplayCell…
- – (void) collectionView: (UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *) indexPath;
UICollectionViewLayout
提供基本的容器、滚动、复用功能
布局信息交给开发者
Layout管理很多的Attributes,每一个cell都对应一个Attribute
系统默认Layout
minimumLineSpacing 行间大小
ItemSize cell大小
minimumInteritemSpacing 纵向大小
1 2 3 4 |
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc]init]; flowLayout.minimumLineSpacing = 10; flowLayout.minimumInteritemSpacing = 10; flowLayout.itemSize = CGSizeMake((self.view.frame.size.width - 10)/2, 300);//这里需要匹配,保证大小合适 |
区分处理indexPath,通过以下方法可以自定义任何的size,可以设置很多的样式
1 2 3 4 5 6 7 |
- (CGSize) collectionView: (UICollectionView *) collectionView layout: (UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ if(indexPath.item % 3==0){ return CGSizeMake(self.view.frame.size.width,100); }else{ return CGSizeMake((self.view.frame.size.width-10)/2,3 00); } } |
UITableView算是一个特殊Flow布局的UICollectionView,UICollectionView理论完全呃可以替代
在有双向的布局,特殊Flow布局等非普通场景(瀑布流、弹幕)都只能使用UICollectionView
UIScrollView
滚动展示的一个逻辑
contentOffset:滚动区域左上角与视图左上角的距离
frame:视图在屏幕中展示的大小、
contentSize:视图内部,内容可以滚动的区域
- scrollEnabled 是否允许滚动
- pagingEnabled 是否在一页内进行滚动
- showHorizontalScrollIndicator 是否展示垂直滚动条
- showVerticalScrollIndicator 是否展示水平滚动条
- setContentOffset:animated:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
- (void) viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:self.view.bounds]; scrollView.backgroundColor = [UIColor lightGrayColor]; scrollView.contentSize = CGSizeMake(self.view.bounds.size.width*5, self.view.bounds.size.height);//设置滚动的范围 NSArray *colorArray = @[[UIColor redColor], [UIColor blueColor], [UIColor yellowColor], [UIColor lightGrayColor], [UIColor grayColor]]; for(int i=0;i<5;i++){ [scrollView addSubView:({ UIView *view = [[UIView alloc] initWithFrame:CGRectMake(scrollView.bounds.size.width * i, 0, scrollView.bounds.size.width, scrollView.bounds.size.height)]; view.background.Color = [ColorArray objectAtIndex:i]; view; })]; } scrollView.pagingEnabled = YES;//翻页的效果,就是中间会产生一个一个的页面 [self.view addSubview: scrollView]; } |
UIScrollViewDelegate
- scrollViewDidScroll
- scrollViewWillBeginDragging 将要开始拖拽
- scrollViewWillEndDragging 将要结束拖拽
- scrollViewDidEndDragging 结束拖拽
- scrollViewWillBeginDecelerating 将要开始停止
- scrollViewDIdEndDecelerating 停止
1 2 |
scrollView.delegate=self; //记得上面声明一下协议 |
可以实现以下功能:滚动、拽、减速
小结
UIView 渲染绘制/子视图管理
UIScrollView 滚动功能
UITableView、UICollectionView 继承了上面的功能并加上了子视图(Cell)布局和应用
UIScrollViewDelegate 滚动相关回调
UICollectionViewDelegate、UITableViewDelegate 基于滚动,视图(Cell)相关回调
UILable
展示一行或者多行只读文字的视图
原来的UIView
- text 文字
- font 字体
- textColor 文字颜色
- textAlignment 对齐方式
- numberOfLines 最大展示行数
- lineBreakMode
- – (void)sizeToFit 固定大小,通过展示行数阶段;可变大小使用sizeToFit确定大小;从固定方向顺序统一布局
替换UITableViewCell中的默认布局样式,使用自定义UILabel进行复杂布局
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
@interface ... @property(nonatomic, strong, readwrite) UILabel *titleLabel; @property(nonatomic, strong, readwrite) UILabel *sourceLabel; @property(nonatomic, strong, readwrite) UILabel *commentLabel; @property(nonatomic, strong, readwrite) UILabel *timeLabel; @end - (instance) initWithStyle: (UITableViewCellStyle) style reuseIdentifier:(nullable NSString *)reuseIdentifier{ if(self = [super initWithStyle:style reuseIdentifier:reuseIdentifier){ [self.contentView addSubView:({ self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 15, 300, 50)]; self.titleLabel.backgroundColor = [UIColor redColor]; self.titleLabel.font = [UIFont systemFontOfSize: 16]; self.titleLabel.textColor = [UIColor blackColor]; self.titleLabel; })]; [self.contentView addSubView:({ self.sourceLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 80, 50, 20)]; self.sourceLabel.font = [UIFont systemFontOfSize: 12]; self.sourceLabel.backgroundColor = [UIColor redColor]; self.sourceLabel.textColor = [UIColor grayColor]; self.sourceLabel; })]; [self.contentView addSubView:({ self.commentLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 80, 50, 20)]; self.commentLabel.font = [UIFont systemFontOfSize: 12]; self.commentLabel.backgroundColor = [UIColor redColor]; self.commentLabel.backgroundColor = [UIColor grayColor]; self.commentLabel; })]; [self.contentView addSubView:({ self.timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(150, 80, 50, 20)]; self.timeLabel.font = [UIFont systemFontOfSize: 12]; self.timeLabel.backgroundColor = [UIColor redColor]; self.timeLabel.backgroundColor = [UIColor grayColor]; self.timeLabel; })]; } } - (void) layoutTableViewCell{//public 方法 在前面调用即可 self.titleLabel.text = @"..." self.sourceLabel.text = @"..." [self.sourceLabel sizeToFit]; self.commentLabel.frame = CGRectMake(...);//用来确定位置 ... } |
UIImage
包含以下类方法
1 2 3 4 |
+(nullable UIImage *)imageNamed: (NSString *)name; +(nullable UIImage *)imageWithContentsOfFile: (NSString *)path; +(nullable UIImage *)imageWithData: (NSData *) data; +(UIImage *)imageWithCGImage: (CGImageRef) cgImage; |
UIImageView
静态图片使用UIImageView.image = UIImage;
1 2 3 |
UIImageView.animationImages = @[UIImage,UIImage...]; UIImageView.animationDuration = 1; [UIImageView startAnimating]; |
接之前的代码,要在右边生成图片,需要设置位置
1 2 3 4 5 6 7 8 9 10 |
[self.contentView addSubView:({ self.rightImageView = [[UIImageView alloc]initWithFrame:CGRectMake(330,15,70,70); self.rightImageView.backgroundColor = [UIColor redColor]; self.rightImageView; })]; - (void) layoutTableViewCell{ ... self.rightImageView.frame = CGRectMake(); self.rightImageView.image = [UIImage imageNamed:...]; } |
UIViewContentMode
当图片尺寸与UIImageView尺寸不符的时候,自定义填充方式
- ScaleToFill
- TopLeft
- BottomLeft
- Center
- AspectFit
- AspectFill
…
UIButton
作为一个视图来说,可以展示图片,文字,不止有静态的展示功能,同时增加了用户交互的功能
具有按钮状态的功能,不同的按钮状态有不同的功能(enabled, selected, highlighted)
UITabBar就是一个UIButton
添加UIButton
1 2 3 4 5 6 7 8 |
@property (nonatomic, strong, readwrite) UIButton *deleteButton; [self.contentView addSubView:({ self.deleteButton = [[UIButton alloc]initWithFrame:CGRectMake(290,80,30,20); [self.deleteButton setTitle: @"X" forState: UIControlStateNormal]; [self.deleteButton setTitle: @"V" forState: UIControlStateHighlighted];// forState:转换到的状态 self.deleteButton.backgroundColor = [UIColor redColor]; self.deleteButton; })]; |
Target-Action设计模式
让一个对象执行一个操作
缺点是传值的限制比较多
1 2 3 |
[self.button addTarget: self//target action: @selector(clickButton:) //执行action forControlEvents: UIControlEventTouchUpInside;//包含所有可交互的事件 |
1 2 3 4 5 6 7 8 9 10 11 12 |
@property (nonatomic, strong, readwrite) UIButton *deleteButton; [self.contentView addSubView:({ self.deleteButton = [[UIButton alloc]initWithFrame:CGRectMake(290,80,30,20); [self.deleteButton setTitle: @"X" forState: UIControlStateNormal]; [self.deleteButton setTitle: @"V" forState: UIControlStateHighlighted];// forState:转换到的状态 [self.deleteBotton addTarget:self action: @selector (deleteButtonClick) forControlEvents:UIControlEventTouchUpInside]; self.deleteButton.backgroundColor = [UIColor redColor]; self.deleteButton; })]; -(void)deleteButtonClick{ NSLog(@"deleteButtonClick"); } |
UIControl
在UIView上继承而来,集成了子类中可能用到的事件UIButton、UISlider等都是继承于UIControl
UIGestureRecognizer
手势封装:
UITapGestureRecognizer
UIPinchGestureRecognizer
UIRotationGestureRecognizer
UISwipeGestureRecognizer
UIPanGestureRecognizer
UILongPressGestureRecognizer
可以在任何视图上,增加一个或者多个手势,系统会自动识别手势,开发者自定义响应逻辑,采用Target-Action的方式进行处理
- 创建手势
- 设置响应处理
- 从视图中添加
1 2 3 4 5 6 7 8 9 10 |
[view addSubView:({ UIView *view = [[UIView alloc] initWithFrame:CGRectMake(100, 200, 100, 100)]; view.backgroundColor = [UIColor yellowColor]; UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(viewClick)]; [view addGestureRecognizer: tapGesture] view; })] - (void) viewClick{ NSLog(@"viewClick"); } |
UIGestureRecognizerDelegate
手势的不同阶段:UIGestureRecognizerState
- UIGestureRecognizerStateBegan
- UIGestureRecognizerStateChanged
- UIGestureRecognizerStateEnded
- UIGestureRecognizerStateCancelled
- UIGestureRecognizerStateFailed
此方式可以扩展手势操作
是否响应手势
是否支持多手势
多个手势冲突如何处理
– gestureRecognizerShouldBegin是否要响应手势
UIAlertView
苹果已经废弃该API
基本逻辑:
- 创建View、Label、Button以及分割线
- 通过UILabel、UIButton、UIView设计样式
- 内置Button点击手势,取消隐藏
开发者需要提供
- 主标题和副标题文字
- 按钮文字
将基本按钮中的可定制业务,封装Delegate,来自定义一部分方法
小结
提供构建App最核心的模块:视图、用户交互等
MVC设计模式:系统封装视图和逻辑,开发者提供数据驱动
交互:Delegate或者Target-Action方式
WKWebView
WebKit框架
UIWebView已经废弃,支持差,内存泄露等Bug
IOS 8+版本WKWebView,独立进程,内存,更好的支持,Crash不影响App,采用了较新的JIT技术
-(instancetype) initWithFrame: (CGRect) frame configuration: (WKWebViewConfiguration *) configuration;
-(nullable WKNavigation *) loadRequest: (NSURLRequest *)request;
-(nullable WKNavigation *) loadHTMLString: (NSString *)string baseURL: (nullable NSURL *) baseURL;
WKWebViewDelegates
WKNavigationDelegate
decidePolicyForNavigationAction 是否加载请求
didFinishNavigation WebView完成加载
didFailNavigation WebView加载失败(loading View展示,重试按钮)
webViewWebContentProcessDidTerminate WebView Crash回调(自动重新加载)
WKUIDelegate
runJavaScriptAlertPanelWithMessage 处理alert
runJavaScriptConfirmPanelWithMessage 处理confirm
runJavaScriptTextInputPanelWithMessage 处理prompt
1 2 3 4 5 6 7 8 9 10 11 12 |
@interface ... @property(nonatomic, strong, readwrite) WKWebView *webView; @end @implementation ... - (void) viewDidLoad{ [super viewDidLoad]; [self.view addSubview: ({ self.webView = [[WKWebView alloc] initWithFrame: CGRectMake(0, 88, self.view.frame.size.width, self.view.frame.size.height - 88); self.webView; })]; [self.webView loadRequest: [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://time.geekbang.org"]]]; } |
使用WKWebView流程
- 创建WKWebView
- 设置Delegate以及样式,JS注入等
- 加载URL或HTML字符串
- 在相应的回调中处理业务逻辑
观察者模式(KVO)
定义了一种一对多的关系,可以让多个观察者同时监听一个对象
每一个观察者在被观察者身上注册一个,被观察者状态改变的时候通过广播给所有的观察者
注册监听
1 2 3 4 |
[self.webview addObserver: self forKeyPath: @"estimatedProgress" Options: NSKeyValueObservingOptionNew context: nil]; |
- self作为监听者,接受事件
- 监听estimatedProcess属性,这个属性是加载的进度
移除监听
1 |
[self.webview removeObserver: self forKeyPath: @"estimatedProcess"]; |
接收通知
1 2 3 4 5 6 7 |
- (void) observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id) object change:(nullable id) NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context{ // 业务逻辑 ... } |
监听WebView属性:
1 2 3 4 5 6 7 8 9 10 11 12 |
- (void) viewDidLoad{ [super viewDidLoad]; [self.view addSubview: ({ self.webView = [[WKWebView alloc] initWithFrame: CGRectMake(0, 88, self.view.frame.size.width, self.view.frame.size.height - 88); self.webView; })]; [self.webView loadRequest: [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://time.geekbang.org"]]]; [self.webView addObserver:self forKeyPath: @"estimateProgress" options: NSKeyValueObservingOptionNew context:nil];//属性有新变化告诉我们 } - (void) dealloc{ [self.webView removeObserver:self forKeyPath: @"estimateProgress"]; } |
添加进度条:
1 2 3 4 5 6 7 8 |
@property(nonatomic, strong, readwrite) UIProgressView *progressView; - (void) viewDidLoad中添加: [self.view addSubView:({ self.progressView = [[UIProgressView alloc] initWithFrame: CGRectMake(0, 88, self.view.frame.size.width, 20] self.progressView; })]; - (void) observeValueForKeyPath中添加: self.progressView.progress = self.webView.estimatedProgress; |
注意:需要移除Crash风险、复杂的方法名 & 参数
常用的开源KVO:KVOController
0 条评论