目录
一、导航控制器和工具栏
1.1 导航控制器
1.1.1 导航控制器基础
导航控制器(UINavigationController)负责控制导航栏(navigationBar),在导航栏上的按钮叫UINavigationIitm,在导航控制器中也控制一个视图控制器(UIViewController),每个视图控制器中对应一个导航引入项(navigationItem),导航引入项就是显示在导航栏上的内容,包括leftBarButtonItem(导航栏左侧按钮),titleView(导航栏中间标题),rightBarButtonItem(导航栏右侧按钮)
继承关系:NSObject->UIResponder->UIViewController->UINavigationController
接下来用代码来演示导航控制器的创建及使用:
首先我们需要一个VCRoot类来做为我们的根视图,在创建导航控制器的时候一定要有根视图:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface VCRoot : UIViewController
@end
NS_ASSUME_NONNULL_END
#import "VCRoot.h"
@interface VCRoot ()
@end
@implementation VCRoot
- (void)viewDidLoad {
[super viewDidLoad];
//设置根视图颜色
self.view.backgroundColor = [UIColor yellowColor];
//设置导航栏文字内容
self.title = @"根视图";
//设置导航元素项的标题,它和上面那一条的区别是
//如果没有设置navigationItem的title,为nil,系统会自动使用self.title作为标题
//如果navigationItem的title不为nil,则将navigationItem的title设置为标题
//如果navigationItem的title和self.title都为nil,则没有标题
self.navigationItem.title = @"title";
//创建一个导航栏左侧的按钮,这是根据title文字来创建的,传入四个参数
//第一个参数是按钮上的文字内容;第二个参数是按钮风格
//第三个参数是事件的拥有者;第四个参数是按钮的事件函数
UIBarButtonItem *leftBtn = [[UIBarButtonItem alloc] initWithTitle: @"左侧" style: UIBarButtonItemStyleDone target: self action: @selector(pressLeft)];
//给导航栏的左侧按钮属性赋值为我们创建好的左侧按钮
self.navigationItem.leftBarButtonItem = leftBtn;
//右侧按钮
//和左侧按钮不同的是,这里创建右侧按钮的时候我们使用的初始化方法是不一样的
//这里的初始化方法不需要输入文字内容,而是指定了系统提供的风格样式,系统风格的按钮内容或标题文字不可更改
UIBarButtonItem *rightBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemAdd target: self action: @selector(pressRight)];
self.navigationItem.rightBarButtonItem = rightBtn;
//创建多按钮:
//先创建一个标签对象
UILabel *label = [[UILabel alloc] initWithFrame: CGRectMake(10, 10, 50, 40)];
label.text = @"test";
//将label设置为居中
label.textAlignment = NSTextAlignmentCenter;
label.textColor = [UIColor blueColor];
//将UIlabel类型的控件添加到导航栏按钮
//initWithCustomView就代表以自定义控件来初始化
UIBarButtonItem *item3 = [[UIBarButtonItem alloc] initWithCustomView: label];
//创建一个按钮数组
NSArray *arrayBtn = [NSArray arrayWithObjects: rightBtn, item3, nil];
//将右侧按钮数组赋值
self.navigationItem.rightBarButtonItems = arrayBtn;
}
- (void) pressLeft {
NSLog(@"左侧按钮被按下");
}
- (void) pressRight {
NSLog(@"右侧按钮被按下");
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
然后在SceneDelegate.m中创建根视图和导航控制器:
#import "SceneDelegate.h"
#import "VCRoot.h"
@interface SceneDelegate ()
@end
@implementation SceneDelegate
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
self.window.frame = [UIScreen mainScreen].bounds;
//创建一个根视图控制器
VCRoot *root = [[VCRoot alloc] init];
//创建导航控制器,它主要是用于管理多个视图控制器的切换
//用层级的方式来管理多个视图的切换
//创建导航控制器的时候一定要有一个根视图控制器
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController: root];
//将window的根视图设置为导航控制器
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
}
- (void)sceneDidDisconnect:(UIScene *)scene {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
- (void)sceneDidBecomeActive:(UIScene *)scene {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
- (void)sceneWillResignActive:(UIScene *)scene {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
- (void)sceneWillEnterForeground:(UIScene *)scene {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
- (void)sceneDidEnterBackground:(UIScene *)scene {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
@end
运行上面的代码,结果得到:
1.1.2 导航控制器切换
有以下几个方法:
navigationBar:导航栏对象
navigationItem:导航元素项对象
translucent:导航栏透明度
pushViewController:推入视图控制器
popViewController:弹出视图控制器
用代码演示如何切换:
在这段代码中,首先要创建三个视图:
根视图VCRoot:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface VCRoot : UIViewController
@end
NS_ASSUME_NONNULL_END
#import "VCRoot.h"
#import "VCSecond.h"
@interface VCRoot ()
@end
@implementation VCRoot
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor orangeColor];
//设置导航栏的透明度
//默认透明度为YES:可透明的;NO:不透明的
self.navigationController.navigationBar.translucent = YES;
//设置导航栏风格颜色,默认为UIBarStyleDefault
self.navigationController.navigationBar.barStyle = UIBarStyleDefault;
self.title = @"根视图";
//为根视图的导航控制器设置右侧按钮
UIBarButtonItem *next = [[UIBarButtonItem alloc] initWithTitle: @"下一级" style: UIBarButtonItemStylePlain target: self action: @selector(pressNext)];
self.navigationItem.rightBarButtonItem = next;
}
//右侧按钮执行的事件函数
- (void)pressNext {
//创建新的视图控制器
VCSecond *vcSecond = [[VCSecond alloc] init];
//使用当前视图控制器的导航控制器对象
[self.navigationController pushViewController: vcSecond animated: YES];
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
第二个视图VCSecond:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface VCSecond : UIViewController
@end
NS_ASSUME_NONNULL_END
#import "VCSecond.h"
#import "VCThird.h"
@interface VCSecond ()
@end
@implementation VCSecond
- (void)viewDidLoad {
[super viewDidLoad];
//设置视图二的标题和颜色
self.view.backgroundColor = [UIColor whiteColor];
self.title = @"视图二";
//为视图控制器导航栏设置右侧按钮
UIBarButtonItem *btnNext = [[UIBarButtonItem alloc] initWithTitle: @"下一级" style: UIBarButtonItemStylePlain target: self action: @selector(pressNext)];
self.navigationItem.rightBarButtonItem = btnNext;
//为视图控制器导航栏设置返回的左侧按钮
UIBarButtonItem *btnLeft = [[UIBarButtonItem alloc] initWithTitle: @"返回上一级" style: UIBarButtonItemStylePlain target: self action: @selector(pressBack)];
self.navigationItem.leftBarButtonItem = btnLeft;
}
- (void)pressNext {
//创建新的视图控制器
VCThird *vcThird = [[VCThird alloc] init];
//推入第三个视图控制器对象
[self.navigationController pushViewController: vcThird animated: YES];
}
- (void)pressBack {
//将当前视图控制器弹出,返回到上一级界面
[self.navigationController popViewControllerAnimated: YES];
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
第三个视图VCThird:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface VCThird : UIViewController
@end
NS_ASSUME_NONNULL_END
#import "VCThird.h"
@interface VCThird ()
@end
@implementation VCThird
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithRed: 0.7 green: 0.2 blue: 0.5 alpha: 1];
self.title = @"视图三";
UIBarButtonItem *btnLeft = [[UIBarButtonItem alloc] initWithTitle: @"返回上一级" style: UIBarButtonItemStylePlain target: self action: @selector(pressBack)];
self.navigationItem.leftBarButtonItem = btnLeft;
UIBarButtonItem *btnRight = [[UIBarButtonItem alloc] initWithTitle: @"返回根视图" style: UIBarButtonItemStylePlain target: self action: @selector(pressRoot)];
self.navigationItem.rightBarButtonItem = btnRight;
}
- (void)pressBack {
//将当前视图控制器弹出,返回到上一级界面
[self.navigationController popViewControllerAnimated: YES];
}
- (void)pressRoot {
//将当前视图弹出,并返回根视图
[self.navigationController popToRootViewControllerAnimated: YES];
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
SceneDelegate.m:
#import "SceneDelegate.h"
#import "VCRoot.h"
@interface SceneDelegate ()
@end
@implementation SceneDelegate
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
self.window.frame = [UIScreen mainScreen].bounds;
//在这里创建了一个根视图控制器,直接将这个根视图控制器赋值给了导航控制器的根视图对象,然后这个导航控制器又作为了window的根视图控制器
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController: [[VCRoot alloc] init]];
[self.window makeKeyAndVisible];
}
- (void)sceneDidDisconnect:(UIScene *)scene {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
- (void)sceneDidBecomeActive:(UIScene *)scene {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
- (void)sceneWillResignActive:(UIScene *)scene {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
- (void)sceneWillEnterForeground:(UIScene *)scene {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
- (void)sceneDidEnterBackground:(UIScene *)scene {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
@end
运行结果:开始界面:
点击“下一级”后:
再点击“下一级”:
点击“返回根视图”:
1.2 导航栏和工具栏
一些方法:
barStyle:导航栏风格
barTintColor:导航栏颜色
tintColor:导航栏风格颜色
toolBarItems:工具栏元素数组
UIBarItemFlexibleSpace:自动调整距离按钮
注:
在iOS13之后,设置导航栏的颜色等样式要按如下方式:
UIBarAppearance是iOS13后推出的一个对相应空间设置外观样式的类,可以统一配置NavigationBar、TabBar、ToolBar等的外观样式
UINavigationBarAppearance可以设置导航栏对象的外观样式
在使用这些方法设置导航栏外观样式之前,需要创建一个UINavigationBarAppearance对象
该类中的相关属性说明:
在self.navigationController.navigationBar.scrollEdgeAppearance = appearance;这行代码中:
scrollEdgeAppearance的意思是:在滚动样式的导航栏中,当可滚动内容的边缘和导航栏的边缘对齐时导航栏的外观设置,如果这个属性为nil, UIKit使用导航栏的standardAppearance外观属性的值,修改为有一个透明的背景。
在self.navigationController.navigationBar.standardAppearance = appearance;这行代码中:
standardAppearance的意思是:在普通样式的导航栏中:设置导航栏标准高度的样式设置,默认样式。此属性的默认值是一个包含系统默认外观设置的外观对象。
代码演示:
#import "SceneDelegate.h"
#import "VCRoot.h"
@interface SceneDelegate ()
@end
@implementation SceneDelegate
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
self.window.frame = [UIScreen mainScreen].bounds;
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController: [[VCRoot alloc] init]];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
}
- (void)sceneDidDisconnect:(UIScene *)scene {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
- (void)sceneDidBecomeActive:(UIScene *)scene {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
- (void)sceneWillResignActive:(UIScene *)scene {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
- (void)sceneWillEnterForeground:(UIScene *)scene {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
- (void)sceneDidEnterBackground:(UIScene *)scene {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
@end
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface VCRoot : UIViewController
@end
NS_ASSUME_NONNULL_END
#import "VCRoot.h"
#import "SecondVC.h"
@interface VCRoot ()
@end
@implementation VCRoot
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor orangeColor];
self.title = @"根视图";
UIBarButtonItem *btn = [[UIBarButtonItem alloc] initWithTitle: @"右侧按钮" style: UIBarButtonItemStylePlain target: self action: nil];
self.navigationItem.rightBarButtonItem = btn;
//UIBarAppearance是iOS13后推出的一个对相应空间设置外观样式的类,可以统一配置NavigationBar、TabBar、ToolBar等的外观样式
//UINavigationBarAppearance可以设置导航栏对象的外观样式
//创建一个UINavigationBarAppearance对象
UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
//设置该对象的背景颜色
appearance.backgroundColor = [UIColor blueColor];
//创建该对象的阴影图像
appearance.shadowImage = [[UIImage alloc] init];
//设置该对象的阴影颜色
appearance.shadowColor = nil;
//设置导航栏按钮的颜色
self.navigationController.navigationBar.tintColor = [UIColor purpleColor];
//设置普通样式导航栏
self.navigationController.navigationBar.standardAppearance = appearance;
//设置滚动样式导航栏
self.navigationController.navigationBar.scrollEdgeAppearance = appearance;
//隐藏导航栏的两个方法
//1、下面这一条的hidden是继承于UIView的
self.navigationController.navigationBar.hidden = NO;
//2、下面这一条的navigationBarHidden是一个属性
self.navigationController.navigationBarHidden = NO;
//显示工具栏对象
//隐藏工具栏,默认为YES:即隐藏;NO:不隐藏
self.navigationController.toolbarHidden = NO;
//设置工具栏是否透明,默认为YES:半透明
self.navigationController.toolbar.translucent = NO;
UIBarButtonItem *btn1 = [[UIBarButtonItem alloc] initWithTitle: @"left" style: UIBarButtonItemStylePlain target: nil action: nil];
UIBarButtonItem *btn2 = [[UIBarButtonItem alloc] initWithTitle: @"right" style: UIBarButtonItemStylePlain target: self action: @selector(pressBack)];
//设置一个自定义类型的button,使用图片创建
UIButton *btnC = [UIButton buttonWithType: UIButtonTypeCustom];
[btnC setImage: [UIImage imageNamed: @"btnC.jpg"] forState: UIControlStateNormal];
btnC.frame = CGRectMake(0, 0, 60, 60);
UIBarButtonItem *btn3 = [[UIBarButtonItem alloc] initWithCustomView: btnC];
//设置一个占位按钮,放到数组中可以用来分隔开各按钮
//设置宽度固定的占位按钮,注:此处方法名为UIBarButtonSystemItemFixedSpace(FixedSpace!!!!!)
UIBarButtonItem *btnF1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemFixedSpace target: nil action: nil];
btnF1.width = 110;
//设置自动计算宽度的占位按钮,注:此处方法名为UIBarButtonSystemItemFlexibleSpace (FlexibleSpace!!!!!)
UIBarButtonItem *btnF2 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemFlexibleSpace target: nil action: nil];
NSArray *arrayBtn = [NSArray arrayWithObjects: btn1, btnF2, btn3, btnF2, btn2, nil];
self.toolbarItems = arrayBtn;
}
- (void)pressBack {
SecondVC *vc = [[SecondVC alloc] init];
[self.navigationController pushViewController: vc animated: YES];
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
运行结果:
二、布局子视图
当我们想让父视图变化的时候使子视图也随着进行相应的变化的时候,我们可以自动布局子视图,也可以手动布局子视图。
2.1 手动布局子视图
superView类:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface SuperView : UIView {
UIView *_view1;
UIView *_view2;
UIView *_view3;
UIView *_view4;
UIView *_view5;
}
- (void)createSubViews;
@end
NS_ASSUME_NONNULL_END
#import "SuperView.h"
@implementation SuperView
- (void)createSubViews {
//左上角视图
_view1 = [[UIView alloc] init];
_view1.frame = CGRectMake(0, 0, 40, 40);
//右上角视图
_view2 = [[UIView alloc] init];
_view2.frame = CGRectMake(self.bounds.size.width - 40, 0, 40, 40);
//右下角视图
_view3 = [[UIView alloc] init];
_view3.frame = CGRectMake(self.bounds.size.width - 40, self.bounds.size.height - 40, 40, 40);
//左下角视图
_view4 = [[UIView alloc] init];
_view4.frame = CGRectMake(0, self.bounds.size.height - 40, 40, 40);
_view1.backgroundColor = [UIColor orangeColor];
_view2.backgroundColor = [UIColor orangeColor];
_view3.backgroundColor = [UIColor orangeColor];
_view4.backgroundColor = [UIColor orangeColor];
[self addSubview: _view1];
[self addSubview: _view2];
[self addSubview: _view3];
[self addSubview: _view4];
}
- (void)layoutSubviews {
[UIView animateWithDuration: 1.0 animations:^ {
self->_view1.frame = CGRectMake(0, 0, 40, 40);
self->_view2.frame = CGRectMake(self.bounds.size.width - 40, 0, 40, 40);
self->_view3.frame = CGRectMake(self.bounds.size.width - 40, self.bounds.size.height - 40, 40, 40);
self->_view4.frame = CGRectMake(0, self.bounds.size.height - 40, 40, 40);
}];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end
ViewController:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
#import "ViewController.h"
#import "SuperView.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
SuperView *sView = [[SuperView alloc] init];
sView.frame = CGRectMake(20, 20, 180, 280);
[sView createSubViews];
sView.backgroundColor = [UIColor blueColor];
[self.view addSubview: sView];
UIButton *btn = [UIButton buttonWithType: UIButtonTypeRoundedRect];
btn.frame = CGRectMake(240, 480, 80, 40);
[btn setTitle: @"放大" forState: UIControlStateNormal];
[btn addTarget: self action: @selector(pressLarge) forControlEvents: UIControlEventTouchUpInside];
[self.view addSubview: btn];
UIButton *btn2 = [UIButton buttonWithType: UIButtonTypeRoundedRect];
btn2.frame = CGRectMake(240, 520, 80, 40);
[btn2 setTitle: @"缩小" forState: UIControlStateNormal];
[btn2 addTarget: self action: @selector(pressSmall) forControlEvents: UIControlEventTouchUpInside];
[self.view addSubview: btn2];
sView.tag = 101;
}
- (void) pressLarge {
SuperView *sView = (SuperView*)[self.view viewWithTag: 101];
[UIView animateWithDuration: 1.0 animations:^{
sView.frame = CGRectMake(20, 20, 300, 480);
}];
}
- (void) pressSmall {
SuperView *sView = (SuperView*)[self.view viewWithTag: 101];
[UIView animateWithDuration: 1.0 animations: ^{
sView.frame = CGRectMake(20, 20, 180, 280);
}];
}
@end
运行结果:
点击“放大”后:
2.2 自动布局子视图
自动布局子视图是可以直接通过OC中提供的属性和方法来完成子视图随父视图改变。
代码演示:ViewController:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController {
//创建父亲视图对象
UIView *_superView;
//左上角视图
UILabel *_label1;
//右上角视图
UILabel *_label2;
//右下角视图
UILabel *_label3;
//左下角视图
UILabel *_label4;
UIView *_viewCenter;
}
@end
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_superView = [[UIView alloc] init];
_superView.frame = CGRectMake(20, 20, 180, 280);
_superView.backgroundColor = [UIColor blueColor];
_label1 = [[UILabel alloc] init];
_label1.frame = CGRectMake(0, 0, 40, 40);
_label1.text = @"1";
_label1.backgroundColor = [UIColor greenColor];
_label2 = [[UILabel alloc] init];
_label2.frame = CGRectMake(180 - 40, 0, 40, 40);
_label2.text = @"2";
_label2.backgroundColor = [UIColor greenColor];
_label3 = [[UILabel alloc] init];
_label3.frame = CGRectMake(180 - 40, 280 - 40, 40, 40);
_label3.text = @"3";
_label3.backgroundColor = [UIColor greenColor];
_label4 = [[UILabel alloc] init];
_label4.frame = CGRectMake(0, 280 - 40, 40, 40);
_label4.text = @"4";
_label4.backgroundColor = [UIColor greenColor];
[_superView addSubview: _label1];
[_superView addSubview: _label2];
[_superView addSubview: _label3];
[_superView addSubview: _label4];
[self.view addSubview: _superView];
_viewCenter = [[UIView alloc] init];
_viewCenter.frame = CGRectMake(0, 0, _superView.bounds.size.width, 40);
_viewCenter.center = CGPointMake(180 / 2, 280 / 2);
_viewCenter.backgroundColor = [UIColor orangeColor];
[_superView addSubview: _viewCenter];
//设置自动布局属性,通过此变量来调整视图在父亲视图中的位置和大小
//在这里,等于号后面三个变量分别代表随着父视图的宽度改变,随着父视图改变距顶部的距离,随着父视图改变距底部距离
//当要使一个视图同时随父视图改变多个位置,要用“|”;
_viewCenter.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
//这里要使label2,3,4在父视图的四个角
_label2.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
_label3.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin;
_label4.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
}
//触摸屏幕调用该函数来改变位置和大小
- (void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//用一个局部变量来区分视图的大小的状态
static BOOL isLarge = NO;
//设置动画效果
[UIView animateWithDuration: 1.0 animations:^{
if (isLarge == NO) {
self->_superView.frame = CGRectMake(10, 10, 350, 580);
isLarge = YES;
} else {
self->_superView.frame = CGRectMake(20, 20, 180, 280);
isLarge = NO;
}
}];
}
@end
运行结果:
点击空白处后:
三、分栏控制器
3.1 分栏控制器基础
有以下几个属性:
UITabBarltem:分栏按钮元素对象
badgeValue:分栏按钮提示信息
selectedIndex:分栏控制器选中的控制索引
viewControllers:分栏控制器管理数组
selectedViewController:分栏控制器选中的控制器对象
要注意的是,在SceneDelegate中改了按钮的标题内容,然后又在创建的视图控制器对象的.m文件中更改标题时,应该在SceneDelegate中把会用到视图控制器对象的.m中的viewDidLoad函数的语句放在在SceneDelegate的标题赋值语句的后面,因为如果不放在后面就会导致标题被覆盖,无法更改为创建的视图控制器对象的标题内容
代码演示:
首先需要创建三个视图控制器:FirstVC、SecondVC、ThirdVC:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface FirstVC : UIViewController
@end
NS_ASSUME_NONNULL_END
#import "FirstVC.h"
@interface FirstVC ()
@end
@implementation FirstVC
- (void)viewDidLoad {
[super viewDidLoad];
//创建一个分栏按钮对象,传入三个参数
//第一个参数表示标题文字内容
//第二个参数表示显示图片
//第三个参数表示对象的标记值
UITabBarItem *tabBarItem = [[UITabBarItem alloc] initWithTitle: @"发现" image: nil tag: 101];
self.tabBarItem = tabBarItem;
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface SecondVC : UIViewController
@end
NS_ASSUME_NONNULL_END
#import "SecondVC.h"
@interface SecondVC ()
@end
@implementation SecondVC
- (void)viewDidLoad {
[super viewDidLoad];
//根据系统风格设置分栏控制器按钮,传入两个参数
//第一个参数指分栏控制器的按钮风格,第二个参数是分栏控件对象的标签值
UITabBarItem *tabBarItem = [[UITabBarItem alloc] initWithTabBarSystemItem: UITabBarSystemItemContacts tag: 103];
//为分栏按钮设置提示的标记值信息,是系统的,无法变更
tabBarItem.badgeValue = @"22";
self.tabBarItem = tabBarItem;
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface ThirdVC : UIViewController
@end
NS_ASSUME_NONNULL_END
#import "ThirdVC.h"
@interface ThirdVC ()
@end
@implementation ThirdVC
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
然后在SceneDelegate.m中:
#import "SceneDelegate.h"
#import "FirstVC.h"
#import "SecondVC.h"
#import "ThirdVC.h"
@interface SceneDelegate ()
@end
@implementation SceneDelegate
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
//创建三个视图控制器并更改背景颜色和标题
FirstVC *vc1 = [[FirstVC alloc] init];
vc1.title = @"视图1";
SecondVC *vc2 = [[SecondVC alloc] init];
vc2.title = @"视图2";
ThirdVC *vc3 = [[ThirdVC alloc] init];
vc3.title = @"视图3";
vc1.view.backgroundColor = [UIColor brownColor];
vc2.view.backgroundColor = [UIColor orangeColor];
vc3.view.backgroundColor = [UIColor yellowColor];
//创建分栏控制器对象
UITabBarController *tbc = [[UITabBarController alloc] init];
//创建一个控制器数组对象,并将所有要被分栏控制器管理的对象添加进数组
//分栏控制器的按钮的位置就取决于在数组中存放的位置
NSArray *arrVC = [NSArray arrayWithObjects: vc1, vc2, vc3, nil];
//将分栏控制器管理数组赋值
tbc.viewControllers = arrVC;
//将分栏控制器做为根视图控制器
self.window.rootViewController = tbc;
//设置选中的视图控制器的索引
//通过索引来确定一打开程序的时候是显示的哪一个视图控制器,并且此时分栏控制器选中的控制器对象就是索引为2的视图控制器
tbc.selectedIndex = 2;
//分栏控制器选中的控制器对象
if (tbc.selectedViewController == vc3) {
NSLog(@"分栏控制器选中的控制器对象是索引为2的视图控制器");
}
//设置分栏控制器的工具栏的透明度
tbc.tabBar.translucent = NO;
//设置分栏控制器工具栏的背景颜色
tbc.tabBar.backgroundColor = [UIColor whiteColor];
//设置分栏控制器工具栏的按钮选择时颜色
tbc.tabBar.tintColor = [UIColor redColor];
}
- (void)sceneDidDisconnect:(UIScene *)scene {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
- (void)sceneDidBecomeActive:(UIScene *)scene {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
- (void)sceneWillResignActive:(UIScene *)scene {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
- (void)sceneWillEnterForeground:(UIScene *)scene {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
- (void)sceneDidEnterBackground:(UIScene *)scene {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
@end
运行结果:
3.2 分栏控制器高级
一些方法:
willBeginCustomizingViewControllers:即将显示编辑方法
willEndCustomizingViewControllers:即将结束编辑方法
didEndCustomizingViewControllers:已经结束编辑方法
didSelectViewController:选中控制器切换方法
在给分栏控件添加按钮的时候,为了用户体验,下面页面最多显示五个按钮,当添加的按钮多于五个的时候,系统就会自动把最后一个按钮替换成“more”,然后点开more,才能看见被折叠的其他按钮。然后在点开more后的页面中的右上角会有一个edit按钮,这个按钮点开后,会出现我们创建的全部视图,拖动上面的任意视图到下面的分栏视图中,可以交换被折叠和被显示的那两个视图
UITabBarControllerDelegate协议
为了实现UITabBarControllerDelegate协议,要在SceneDelegate.h中先引用该协议
代码演示:
在此之前需要创建六个视图控制器:FirstViewController、SecondViewController、ThirdViewController、ForthViewController、FifthViewController、sixthViewController
然后在在SceneDelegate.m中:
#import "SceneDelegate.h"
#import "FirstViewController.h"
#import "SecondViewController.h"
#import "ThirdViewController.h"
#import "ForthViewController.h"
#import "FifthViewController.h"
#import "SixthViewController.h"
@interface SceneDelegate ()
@end
@implementation SceneDelegate
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
FirstViewController *vc1 = [[FirstViewController alloc] init];
SecondViewController *vc2 = [[SecondViewController alloc] init];
ThirdViewController *vc3 = [[ThirdViewController alloc] init];
ForthViewController *vc4 = [[ForthViewController alloc] init];
FifthViewController *vc5 = [[FifthViewController alloc] init];
SixthViewController *vc6 = [[SixthViewController alloc] init];
vc1.title = @"视图1";
vc2.title = @"视图2";
vc3.title = @"视图3";
vc4.title = @"视图4";
vc5.title = @"视图5";
vc6.title = @"视图6";
vc1.view.backgroundColor = [UIColor redColor];
vc2.view.backgroundColor = [UIColor orangeColor];
vc3.view.backgroundColor = [UIColor yellowColor];
vc4.view.backgroundColor = [UIColor greenColor];
vc5.view.backgroundColor = [UIColor blueColor];
vc6.view.backgroundColor = [UIColor purpleColor];
NSArray *arrVC = [NSArray arrayWithObjects: vc1, vc2, vc3, vc4, vc5, vc6, nil];
UITabBarController *btc = [[UITabBarController alloc] init];
btc.viewControllers = arrVC;
self.window.rootViewController = btc;
//处理UITabBarControllerDelegate协议函数
//设置代理
btc.delegate = self;
}
//以下是协议中函数的用法,其中“编辑”是指在分栏控制器中的more中通过拖动更改和交换显示和折叠的视图控制器的操作------------------------------------------------------------
//即将开始编辑前会调用此协议函数
- (void)tabBarController:(UITabBarController *)tabBarController willBeginCustomizingViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers {
NSLog(@"编辑前");
}
//即将结束前调用该协议函数
- (void)tabBarController:(UITabBarController *)tabBarController willEndCustomizingViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers changed:(BOOL)changed {
NSLog(@"即将结束前");
}
//已经结束编辑时调用该协议函数
- (void)tabBarController:(UITabBarController *)tabBarController didEndCustomizingViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers changed:(BOOL)changed {
if (changed == YES) {
NSLog(@"顺序发生改变");
}
NSLog(@"已经结束编辑");
}
//选中控制器对象时调用该协议函数
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
// if (tabBarController.viewControllers[tabBarController.selectedIndex] == viewController) {
// NSLog(@"选中的视图索引与当前传入的视图索引相同");
// }
NSLog(@"选中控制器对象");
}
- (void)sceneDidDisconnect:(UIScene *)scene {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
- (void)sceneDidBecomeActive:(UIScene *)scene {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
- (void)sceneWillResignActive:(UIScene *)scene {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
- (void)sceneWillEnterForeground:(UIScene *)scene {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
- (void)sceneDidEnterBackground:(UIScene *)scene {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
@end
运行结果:
点击“more”:
点击”Edit“:
通过拖动更改显示的视图:
四、多界面传值
代理是一个传值的过程,它将第二个对象访问不到的第一个对象的情况下,将代理(delegate)做为类之间的接收对象。但是有个条件:就是传值的对象必须实现这个协议才能使用
即定义一个代理对象,通过代理对象实现协议函数,达到代理对象改变本身属性的目的,但是代理对象一定要实现代理协议
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
NS_ASSUME_NONNULL_BEGIN
//首先在FirstViewController中实现控制视图二的代理
@interface FirstViewController : UIViewController<SecondVCDelegate>
- (void)changeColor:(UIColor *)color;
@end
NS_ASSUME_NONNULL_END
#import "FirstViewController.h"
#import "SecondViewController.h"
@interface FirstViewController ()
@end
@implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
//点击视图的空白处的时候,推出视图控制器二
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
SecondViewController *vc2 = [[SecondViewController alloc] init];
vc2.view.backgroundColor = [UIColor grayColor];
//将当前控制器做为代理对象
vc2.delegate = self;
//推出视图控制器二
[self.navigationController pushViewController: vc2 animated: YES];
}
- (void)changeColor:(UIColor *)color {
self.view.backgroundColor = color;
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
//定义一个视图控制器二的代理协议
@protocol SecondVCDelegate <NSObject>
- (void)changeColor: (UIColor*)color;
@end
@interface SecondViewController : UIViewController
@property (assign, nonatomic) NSInteger tag;
//定义一个代理对象,代理对象会执行协议函数
//通过代理对象实现协议函数,达到代理对象改变本身属性的目的
//代理对象一定要实现代理协议
@property (assign, nonatomic) id<SecondVCDelegate> delegate;
@end
NS_ASSUME_NONNULL_END
五、UITableView
5.1 UITableView基础
UITableView是指数据视图,即表格等。
在创建数据视图时,比较复杂,必须实现协议中的几个函数,不实现的话程序就崩溃了。
要实现的有:1、tableView(获取每组元素的个数);2、numberOfSectionsInTableView(设置数据视图的组数);3、tableView: cellForRowAtIndexPath:(创建单元格对象函数)
dataSource:数据代理对象
delegate:普通代理对象
numberOfSectionsInTableView:获得数组协议
numberOfRowsInSection:获取行数协议
cellForRowAtIndexPath:创建单元格协议
代码演示:
#import <UIKit/UIKit.h>
//第一个协议:先要实现数据视图的普通协议,该协议负责数据视图的普通事件处理
//第二个协议:然后要实现数据视图的数据代理协议,负责处理数据视图的数据代理
@interface ViewController : UIViewController<UITableViewDelegate,UITableViewDataSource> {
//定义一个数据视图对象
//数据视图是用来显示大量相同格式的大量信息的视图
//例如通讯录,微信好友、朋友圈等
UITableView *_tableView;
}
@end
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//创建数据视图,传入两个参数
//第一个参数是数据视图的位置
//第二个参数是数据视图的风格——UITableViewStylePlain:普通风格; UITableViewStyleGrouped:分组风格
_tableView = [[UITableView alloc] initWithFrame: self.view.bounds style: UITableViewStyleGrouped];
//设置数据视图的代理对象
_tableView.delegate = self;
//设置数据视图的代理源对象
_tableView.dataSource = self;
[self.view addSubview: _tableView];
}
//这个是必须要实现的协议函数,程序在显示数据视图的时候会调用此函数
//它的作用是获取每组元素的个数(行数)
//它的返回值表示每组元素的个数
//传入两个参数,第一个参数是数据视图对象本身;第二个参数是:那一组需要的行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 5;
}
//设置数据视图的组数
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
}
//创建单元格对象函数,传入两个参数
//第一个参数是传入这个函数的对象,第二个参数是单元格的索引,即我们上面写的行数和组数
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellStr = @"cell";
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier: cellStr];
if (cell == nil) {
//创建一个单元格对象,传入两个参数
//第一个参数是单元格的样式,第二个参数是指单元格的复用标记
cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: cellStr];
}
//indexPath.section表示创建的单元格的组数,indexPath.row表示创建的单元格的行数;
//每创建一个单元格,都要调用一次上面的cellForRowAtIndexPath函数
NSString *str = [NSString stringWithFormat: @"第%ld组,第%ld行", indexPath.section, indexPath.row];
//将单元格的主文字内容赋值
cell.textLabel.text = str;
return cell;
}
@end
运行结果:
5.2 UITableView协议
有以下几个基本协议函数:
heightForRowAtIndexPath:获得单元格高度协议
heightForHeaderInSection:数据视图头部高度协议
heightForFooterInSection:数据视图尾部高度协议
titleForFooterInSection:数据视图尾部的标题协议
titleForHeaderInSection:数据视图头部标题协议
用代码演示:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController<UITableViewDelegate,UITableViewDataSource> {
//定义数据视图对象
UITableView *_tableView;
//声明一个数据源
NSMutableArray *_arrayData;
}
@end
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//创建数据视图对象
_tableView = [[UITableView alloc] initWithFrame: CGRectMake(0, 40, 394, 852) style: UITableViewStyleGrouped];
//设置代理对象
_tableView.delegate = self;
//设置数据视图代理对象
_tableView.dataSource = self;
[self.view addSubview: _tableView];
//创建一个可变数组
_arrayData = [[NSMutableArray alloc] init];
for (int i = 'A'; i < 'Z'; i++) {
//定义小数组
NSMutableArray *arraySmall = [[NSMutableArray alloc] init];
for (int j = 1; j <= 5; j++) {
NSString *str = [NSString stringWithFormat: @"%c%d", i, j];
[arraySmall addObject: str];
}
//这里就相当于生成一个二维数组
[_arrayData addObject: arraySmall];
}
}
//获取组数
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return _arrayData.count;
}
//获取每组的元素个数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//因为前面创建了一个二维数组,这里的section返回的是_arrayData二维数组中的以行为元素的一维数组,然后再对用其count方法取这个一维数组的元素个数
NSInteger numRow = [[_arrayData objectAtIndex:section] count];
return numRow;
}
//获取单元格
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *str = @"cell";
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier: str];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: str];
}
cell.textLabel.text = _arrayData[indexPath.section][indexPath.row];
return cell;
}
//以下是几个协议函数------------------------------------------------------------------------------------------------------------------------------------
//获取单元格的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 100;
}
//获取显示在每组头部的标题
- (NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return @"头部标题";
}
//获取显示在每组尾部的标题
- (NSString*)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
return @"尾部标题";
}
//获取头部高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 40;
}
//获取尾部高度
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 20;
}
@end
运行结果:
5.3 UITableView高级协议与单元格
有以下几个高级协议函数:
commitEditingStyle:提交编辑函数
canEditRowAtIndexPath:开启关闭编辑单元格
editingStyleForRowAtIndexPath:编辑单元格风格设定
didSelectRowAtIndexPath:选中单元格相应协议
didDeselectRowAtIndexPath:反选单元格相应协议
首先,要添加一个导航控制器:
#import "SceneDelegate.h"
#import "ViewController.h"
@interface SceneDelegate ()
@end
@implementation SceneDelegate
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
self.window.frame = [UIScreen mainScreen].bounds;
//添加一个导航控制器
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController: [[ViewController alloc] init]];
self.window.rootViewController = nav;
}
然后引用协议:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController<UITableViewDelegate,UITableViewDataSource> {
UITableView *_tableView;
//数据源
NSMutableArray *_arrayData;
//添加导航按钮
UIBarButtonItem *_btnEdit;
UIBarButtonItem *_btnFinish;
UIBarButtonItem *_btnDelete;
//设置编辑状态
BOOL _isEdit;
}
@end
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_tableView = [[UITableView alloc] initWithFrame: self.view.bounds style: UITableViewStylePlain];
//自动调整子视图的大小
_tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
//设置代理
_tableView.delegate = self;
_tableView.dataSource = self;
//数据视图头部视图的设定
_tableView.tableHeaderView = nil;
//数据视图尾部视图的设定
_tableView.tableFooterView = nil;
[self.view addSubview: _tableView];
//初始化数据源数组
_arrayData = [[NSMutableArray alloc] init];
for (int i = 1; i < 20; i++) {
NSString *str = [NSString stringWithFormat: @"A %d", i];
[_arrayData addObject: str];
}
//当数据的数据源发生变化的时候
//更新数据视图,重新加载数据
[_tableView reloadData];
}
//返回行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _arrayData.count;
}
//返回组数,默认组数返回1
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *strID = @"ID";
//尝试获取可以复用的单元格
//如果得不到,返回nil
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier: strID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: strID];
}
//单元格文字赋值
cell.textLabel.text = [_arrayData objectAtIndex: indexPath.row];
//设置文字子标题
cell.detailTextLabel.text = @"子标题";
//为单元格添加图片,即设置图标
NSString *str = [NSString stringWithFormat: @"xmy%ld.jpg", indexPath.row % 8 + 1];
UIImage *image = [UIImage imageNamed: str];
UIImageView *iView = [[UIImageView alloc] initWithImage: image];
cell.imageView.image = image;
//调用创建功能按钮方法
[self creatBtn];
return cell;
}
- (void)creatBtn {
_isEdit = NO;
//设置导航栏按钮
_btnEdit = [[UIBarButtonItem alloc] initWithTitle: @"编辑" style: UIBarButtonItemStylePlain target: self action: @selector(pressEdit)];
_btnFinish = [[UIBarButtonItem alloc] initWithTitle: @"完成" style: UIBarButtonItemStylePlain target: self action: @selector(pressFinish)];
_btnDelete = [[UIBarButtonItem alloc] initWithTitle: @"删除" style: UIBarButtonItemStylePlain target: self action: @selector(pressDelete)];
self.navigationItem.rightBarButtonItem = _btnEdit;
}
- (void)pressEdit {
//修改对象编辑状态
_isEdit = YES;
self.navigationItem.rightBarButtonItem = _btnFinish;
//开启编辑状态
[_tableView setEditing: YES];
self.navigationItem.leftBarButtonItem = _btnDelete;
}
- (void)pressFinish {
_isEdit = NO;
self.navigationItem.rightBarButtonItem = _btnEdit;
[_tableView setEditing: NO];
self.navigationItem.leftBarButtonItem = nil;
}
//单元格显示效果协议
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
//默认为删除状态
return UITableViewCellEditingStyleDelete;
//设置为添加状态
//return UITableViewCellEditingStyleInsert;
//设置为空状态
//return UITableViewCellEditingStyleNone;
//组合在一起就会表现多选状态
//return UITableViewCellEditingStyleDelete|UITableViewCellEditingStyleInsert;
}
//当手指在单元格上移动时可以显示编辑状态
//这里通过手指滑动来实现删除按钮的功能
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
//删除数据源对应的数据
[_arrayData removeObjectAtIndex: indexPath.row];
//数据源更新
[_tableView reloadData];
NSLog(@"删除");
}
//选中单元格时执行
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"选中单元格! %lu, %lu", indexPath.section, indexPath.row);
}
//这个函数可以使在已经选择单元格的情况下,再选择另一个单元格的时候取消选中上一个单元格,即使每次选择时只能选择一个
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"取消选中单元格! %lu,%lu", indexPath.section, indexPath.row);
}
@end
运行结果:
六、UIView动画基础
在iOS13之后,UIView的动画的方法有变,现在的方法如下:
一些动画;
第一部分就是一些常规动画
UIViewAnimationOptionLayoutSubviews:动画过程中保证子视图跟随运动
UIViewAnimationOptionAllowUserInteraction:动画过程中允许用户交互。
UIViewAnimationOptionBeginFromCurrentState:所有视图从当前状态开始运行。
UIViewAnimationOptionRepeat:重复运行动画。
UIViewAnimationOptionAutoreverse :动画运行到结束点后仍然以动画方式回到初始点。
UIViewAnimationOptionOverrideInheritedDuration:忽略嵌套动画时间设置。
UIViewAnimationOptionOverrideInheritedCurve:忽略嵌套动画速度设置。
UIViewAnimationOptionAllowAnimatedContent:动画过程中重绘视图(注意:仅仅适用于转场动画)。
UIViewAnimationOptionShowHideTransitionViews:视图切换时直接隐藏旧视图、显示新视图,而不是将旧视图从父视图移除(仅仅适用于转场动画
UIViewAnimationOptionOverrideInheritedOptions :不继承父动画设置或动画类型。
第二部分是最常用也是效果最炫的,应用最多的就是跳页的时候使用
UIViewAnimationOptionTransitionNone:没有动画效果。
UIViewAnimationOptionTransitionFlipFromLeft :从左侧翻转效果。
UIViewAnimationOptionTransitionFlipFromRight:从右侧翻转效果。
UIViewAnimationOptionTransitionCurlUp:向后翻页的动画过渡效果。
UIViewAnimationOptionTransitionCurlDown :向前翻页的动画过渡效果。
UIViewAnimationOptionTransitionCrossDissolve:旧视图溶解消失显示下一个新视图的效果。
UIViewAnimationOptionTransitionFlipFromTop :从上方翻转效果。
UIViewAnimationOptionTransitionFlipFromBottom:从底部翻转效果。
第三部分是跟时间速度相关的
UIViewAnimationOptionCurveEaseInOut:动画效果先缓后逐渐加速再逐渐减速。
UIViewAnimationOptionCurveEaseIn :动画效果逐渐变慢。
UIViewAnimationOptionCurveEaseOut:动画效果逐渐加速。
UIViewAnimationOptionCurveLinear :动画效果匀速执行(默认)。
这些动画效果我们都在什么时候使用呢,最常用的就是下面的方法
[UIView transitionWithView:@"动画视图" duration:@"时间" options:@"上述动画效果" animations:^{
dispatch_async(dispatch_get_main_queue(), ^{
//动画执行过程中的动作,可以是跳页的等
});
} completion:^(BOOL finished) {
}];
以上就是动画的效果和简单使用
用代码演示:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController {
//创建一个图片视图对象
UIImageView *_imageView;
}
@end
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//创建图像视图
_imageView = [[UIImageView alloc] init];
_imageView.frame = CGRectMake(100, 100, 130, 130);
_imageView.image = [UIImage imageNamed: @"xmy5.jpg"];
[self.view addSubview: _imageView];
//创建移动按钮
UIButton *btnMove = [UIButton buttonWithType: UIButtonTypeRoundedRect];
btnMove.frame = CGRectMake(120, 360, 80, 40);
[btnMove setTitle: @"移动" forState: UIControlStateNormal];
//添加移动事件按钮
[btnMove addTarget: self action: @selector(pressMove) forControlEvents: UIControlEventTouchUpInside];
[self.view addSubview: btnMove];
//添加圆角按钮
UIButton *btnScale = [UIButton buttonWithType: UIButtonTypeRoundedRect];
btnScale.frame = CGRectMake(120, 400, 80, 40);
[btnScale setTitle: @"缩放" forState: UIControlStateNormal];
[btnScale addTarget: self action: @selector(pressScale) forControlEvents: UIControlEventTouchUpInside];
[self.view addSubview: btnScale];
}
- (void)pressMove {
//设置动画的执行时间和执行动作
// [UIView animateWithDuration: 3 animations: ^ {
// self->_imageView.frame = CGRectMake(50, 700, 130, 130);
// }];
//设置动画开始的延时时间长度
//进行延时动画的处理
//options有几个属性:UIViewAnimationOptionRepeat表示动画重复执行;UIViewAnimationOptionAutoreverse表示动画结束后再逆执行动画
[UIView animateWithDuration: 3 delay: 4 options: UIViewAnimationOptionCurveLinear animations: ^{
self->_imageView.frame = CGRectMake(50, 700, 130, 130);
} completion:^(BOOL finished) {
}];
}
- (void)pressScale {
}
@end
运行结果:
点击“移动”后会移动至相应位置
七、导航控制器动画
CATransition:动画对象
duration:设置动画时间长度
type:设置动画类型
timingFunction:设置动画运动类型
subType:设置动画子类型
代码演示:
#import "SceneDelegate.h"
#import "FirstViewController.h"
@interface SceneDelegate ()
@end
@implementation SceneDelegate
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
self.window.frame = [UIScreen mainScreen].bounds;
//创建导航控制器
FirstViewController *vc1 = [[FirstViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController: vc1];
vc1.title = @"控制器一";
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
}
然后创建两个视图控制器:FirstViewController、SecondViewController:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface FirstViewController : UIViewController {
UIImageView *_imageView;
}
@end
NS_ASSUME_NONNULL_END
#import "FirstViewController.h"
#import "SecondViewController.h"
@interface FirstViewController ()
@end
@implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
_imageView = [[UIImageView alloc] initWithFrame: CGRectMake(0, 0, 394, 852)];
_imageView.image = [UIImage imageNamed: @"xmy3.jpg"];
[self.view addSubview: _imageView];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//使用高级动画
//定义一个动画变换对象,它是一个层动画对象
//用类方法获取动画对象
CATransition *amin = [CATransition animation];
//设置动画的时间长度
amin.duration = 1.0;
//设置动画主类型,决定动画的效果形式
//有cube、reveal、pageCurl、pageUnCurl、suckEffect、rippleEffect
amin.type = @"cube";
//设置动画的子类型,例如动画的方向等
amin.subtype = kCATransitionFromLeft;
//设置动画的轨迹模式
amin.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseOut];
//将动画设置对象添加到动画上
[self.navigationController.view.layer addAnimation: amin forKey: nil];
//创建控制器二
SecondViewController *vc2 = [[SecondViewController alloc] init];
//推出到前面显示
[self.navigationController pushViewController: vc2 animated: YES];
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface SecondViewController : UIViewController {
UIImageView *_imageView;
}
@end
NS_ASSUME_NONNULL_END
#import "SecondViewController.h"
@interface SecondViewController ()
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"控制器二";
_imageView = [[UIImageView alloc] initWithFrame: CGRectMake(0, 0, 394, 852)];
_imageView.image = [UIImage imageNamed: @"xmy7.jpg"];
[self.view addSubview: _imageView];
}
//点击屏幕空白处返回到控制器一
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//为视图二添加高级动画
CATransition *ami = [CATransition animation];
ami.duration = 1.0;
ami.type = @"cube";
ami.subtype = kCATransitionFromRight;
[self.navigationController.view.layer addAnimation: ami forKey: nil];
[self.navigationController popViewControllerAnimated: YES];
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
运行结果:
通过动画的方式切换图片: