本分享是iOS开发中有趣的UI模块的相关内容技术点分享。如果您是一位已经有C基础了的iOS爱好者,但还未接触Objectiov C语言,您需要学习我之前分享的 iOS开发核心语言Objective C 系列
如果您是零基础,建议您从我之前分享的iOS开发分分钟搞定C语言 系列开始学习。另外将无偿分享自己整理出来的大概400G iOS学习视频及学习资料,都是干货哦!可以新浪微博私信➕关注极客James,期待与您的共同学习和探讨!!由于时间有限,每天在工作之余整理的学习分享,难免有不足之处,也希望各路大神指正!
1.UIView
苹果将控件的共同属性都抽取到父类UIView中,所有的控件最终都继承自UIView,所以说UIView是UI控件的父类。
2.UIView的常见属性
@property(nonatomic,readonly) UIView *superview;
获得自己的父控件对象
@property(nonatomic,readonly,copy) NSArray *subviews;
获得自己的所有子控件对象
@property(nonatomic) NSInteger tag;
控件的ID(标识),父控件可以通过tag来找到对应的子控件
@property(nonatomic) CGAffineTransform transform;
控件的形变属性(可以设置旋转角度、比例缩放、平移等属性)
@property(nonatomic,readonly) UIView *superview;
获得自己的父控件对象
@property(nonatomic,readonly,copy) NSArray *subviews;
获得自己的所有子控件对象
@property(nonatomic) NSInteger tag;
控件的ID(标识),父控件可以通过tag来找到对应的子控件
@property(nonatomic) CGAffineTransform transform;
控件的形变属性(可以设置旋转角度、比例缩放、平移等属性)
@property(nonatomic) CGRect frame;
控件矩形框在父控件中的位置和尺寸(以父控件的左上角为坐标原点)
@property(nonatomic) CGRect bounds;
控件矩形框的位置和尺寸(以自己左上角为坐标原点,所以bounds的x、y一般为0)
@property(nonatomic) CGPoint center;
控件中点的位置(以父控件的左上角为坐标原点)
3.UIKit的坐标
左上角为(0,0)原点,x轴向右为x轴正方向,y轴向下为正方向。
UIViewController是视图控制器,也就是说UI控件一般都要在这里进行加载创建和显示。
UIImageView极其常用,功能比较专一:显示图片。
1.常见属性
UIImageView极其常用,功能比较专一:显示图片
@property(nonatomic,retain) UIImage *image;
显示的图片
@property(nonatomic,copy) NSArray *animationImages;
显示的动画图片
@property(nonatomic) NSTimeInterval animationDuration;
动画图片的持续时间
@property(nonatomic) NSInteger animationRepeatCount;
动画的播放次数(默认是0,代表无限播放)
2.通过UIImageView实现的经典案例 拳皇
实现效果图:
项目需求:点击相应的按钮,实现相应的动画,在动画结束后让它站立并且一直进行站立的动画。
实现思路:
需要用到的控件:UIImageView UIImage Button
实现方式:通过StoryBoard 和代码的方式完成
主要涉及内容:图片的帧动画
实现步骤:
1> 导入项目所需素材到Supporting File文件下
2> 在StoryBoard 中通过拖控件的方式搭建界面
3>搭建完界面之后通过StoryBoard和UIViewController建立相应的联系
通过IBOutlet让视图与UIViewController建立关系
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
通过IBAction让StoryBoard中的UIButton和UIViewController建立相应的联系。
4>分析实现过程。
帧动画的整体思路为:在特定时间内图片的连续展示。
以下是过程:
在整个实现过程中由于是动画帧的实现方式,所有的点击事件接受的内容除了图片不一样之外其他的都一样,所有采用抽取封装的思想,将它抽取为一个方法,后面有需要用到的直接调用,然后传入相应的参数就可以。
- (void)play:(int)count prefixname:(NSString *)prename{
// (1)创建一个可变的空数组,用来后面装加载好的图片
NSMutableArray *images = [NSMutableArray array];
// (2) 通过for循环来遍历文件中的图片
for (int i = 1; i <= count; i++) {
// (3) 用以下图片加载方式,能避免图片产生缓存
NSString *filename = [NSString stringWithFormat:@"%@_%d",prename,i];
NSString *file = [[NSBundle mainBundle]pathForResource: filename ofType:@"png"];
// (4) 初始化一个UIImage
UIImage *image = [UIImage imageWithContentsOfFile:file];
// (5) 将加载后的图片添加到可变数组中
[images addObject:image];
}
// (6)设置动画
self.imageView.animationImages = images;
// (7)设置播放次数 和stand做对比(让动画完成后就站立)
self.imageView.animationRepeatCount = [prename isEqualToString:@"stand"]? 0 :1;
// (8)设置动画完成后显示的图片
self.imageView.image = [UIImage imageNamed:@"stand_1"];
// (9)设置动画时间
self.imageView.animationDuration = 10 * 0.09;
// (10)开始动画
[self.imageView startAnimating];
// (11)判断
if ([prename isEqualToString:@"stand"]) {
return;
}
// (12)播放完动画,让它一直动
[self performSelector:@selector(stand) withObject:nil afterDelay:self.imageView.animationDuration];
}
点击相应的按钮进行相应素材的加载例如:
// 跑步事件
- (IBAction)run {
// 图片数量6张 图片名前缀 run
[self play:6 prefixname:@"run"];
}
5>音频的添加
点击相应的图标就会有相应的动画和音效,上面只是完成了动画的特效,下面来实现音频的添加。
(1)首先导入音频文件到 Supporting File文件下
(2)然后在头文件中导入音频的框架(必须导入,否则无法播放)
// 音视频头文件
#import <AVFoundation/AVFoundation.h>
(3)创建音视频的方法,由于每个控件事件除了音频路径不一样之外,其他的都一样,所以我们采用封装抽取的思想。
// 音频方法
-(void)audioWithName:(NSString *)name {
// 音频的路径及音频的格式
NSURL *url = [[NSBundle mainBundle]URLForResource:name withExtension:@"mp3"];
// 创建一个播放器
self.player = [AVPlayer playerWithURL:url];
// 播放
[self.player play];
}
九宫格布局,用手机输入法时经常见到。先按3行3列写。
代码的实现主要是计算插入图片的位置。
九宫格购物车项目分析:
实现效果:
项目需求:通过按钮进行商品的添加和删除,当商品为0时,删除按钮不能触发事件,当商品全部添加完成后,增加按钮不能触发事件。
**需要用到的控件:**UIImageView UIImage Button UILabel
实现方式:通过StoryBoard 和代码的方式完成
主要涉及内容:九宫格 label 按钮数据处理
实现步骤:
基本界面及点击事件实现
1>将所用到的素材导入到Supporting File文件中
2> 在storyboard中拖一个大小为300*300的UIView
3>在.m文件中进行类扩展以下方法
@property (weak, nonatomic)UIButton *addBtn;
@property (weak, nonatomic)UIButton *removeBtn;
@property (strong,nonatomic)NSArray *shop;
4>增加按钮和删除按钮的代码实现
由于增加按钮和删除按钮具有相同的属性,仅是图片,位置,以及点击时触发的事件不一样所有我们采用方法抽取及封装的思想来做。
代码如下:
// 增加和删除按钮的方法
- (UIButton *)addButtonWithImage:(NSString *)image hightImage:(NSString *)hightImage disableImage:(NSString *)disableImage frame:(CGRect)frame action:(SEL)action{
// 创建按钮
UIButton *btn = [[UIButton alloc]init];
// 设置背景图片正常下显示
[btn setBackgroundImage:[UIImage imageNamed:image] forState:UIControlStateNormal];
// 设置背景图片在高亮下显示
[btn setBackgroundImage:[UIImage imageNamed:hightImage] forState:UIControlStateHighlighted];
// 设置背景图片在啊不选中样式下显示
[btn setBackgroundImage:[UIImage imageNamed:disableImage] forState:UIControlStateDisabled];
// 设置尺寸
btn.frame = frame;
// 监听按钮点击
[btn addTarget:self action:action forControlEvents:UIControlEventTouchUpInside];
// 将按钮增加到视图上
[self.view addSubview:btn];
return btn;
}
由于本项目需要数据,为了程序的拓展性和可维护性,我们采用数据转模型的方式进行操作。
数据转模型实现步骤:
1>导入.plist文件
2>创建shopsModel文件(MVC思想)
在shopsModel.h文件中声明如下:
// 将数据中的属性进行定义和重写
/** * 商品名称 */
@property (nonatomic,strong)NSString *name;
/** * 商品图标 */
@property (nonatomic,strong)NSString *icon;
// 初始化
- (instancetype)initWithDict:(NSDictionary *)dict;
+ (instancetype)shopWithDict:(NSDictionary *)dict;
在shopsModel.m中实现如下
- (instancetype)initWithDict:(NSDictionary *)dict{
if (self = [super init]) {
self.name = dict[@"name"];
self.icon = dict[@"icon"];
}
return self;
}
+ (instancetype)shopWithDict:(NSDictionary *)dict{
return [[self alloc] initWithDict:dict];
}
3>将创建好的数据模型的头文件导入ViewController.m中
声明一个数组
@property (strong,nonatomic)NSArray *shop;
4>对数组进行懒加载(在需要的时候进行在调用)
- (NSArray *)shop{
if (_shop == nil) {
// 加载plist文件
NSArray *dictArray =[NSArray arrayWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"shops" ofType:@"plist"]];
// 创建一个空得可变数组
NSMutableArray *shopArray = [NSMutableArray array];
// 遍历字典
for (NSDictionary *dict in dictArray) {
shopsModel *shop = [shopsModel shopWithDict:dict];
[shopArray addObject:shop];
}
_shop = shopArray;
}
return _shop;
}
5>让视图一加载完就调用以下方法
- (void)viewDidLoad {
[super viewDidLoad];
// 增加按钮
self.addBtn = [self addButtonWithImage:@"add" hightImage:@"add_highlighted"disableImage:@"add_disabled" frame:CGRectMake(30, 30, 50, 50) action:@selector(add)];
// 删除按钮
self.removeBtn = [self addButtonWithImage:@"remove" hightImage:@"remove_highlighted"
disableImage:@"remove_disabled" frame:CGRectMake(270, 30, 50, 50) action:@selector(remove)];
self.removeBtn.enabled = NO;
}
6.>增加按钮
- (void)add{
self.shopView.clipsToBounds = YES;
// 设置每个商品的尺寸
CGFloat shopW = 80;
CGFloat shopH = 90;
// 设置显示的列数
int cols = 3;
// 设置每一列之间的间距
CGFloat colMargin = (self.shopView.frame.size.width - cols * shopW) / (cols -1);
// 设置每一行之间的间距
CGFloat rowMargin = 10;
// 创建一个父控件(用来存放图片和文字)
UIView *shopView = [[UIView alloc]init];
shopView.backgroundColor = [UIColor redColor];
// 商品的索引
NSUInteger index = self.shopView.subviews.count;
// 商品的x值(取余运算,将算出商品在第几列)
NSUInteger col = index % cols;
CGFloat shopX = col * (shopW + colMargin);
// 商品的y值(除法运算,将算出商品在第几行)
NSUInteger row = index / cols;
CGFloat shopY = row * (shopH + rowMargin);
shopView.frame = CGRectMake(shopX, shopY, shopW, shopH);
// 添加到视图上
[self.shopView addSubview:shopView];
// 获得index位置对应的商品数据
shopsModel *shops = self.shop[index];
// 添加图片
UIImageView *iconView = [[UIImageView alloc]init];
iconView.image = [UIImage imageNamed:shops.icon];
// 设置位置
iconView.frame = CGRectMake(0, 0, shopW, shopW);
iconView.backgroundColor = [UIColor blueColor];
[shopView addSubview:iconView];
// 添加文字
UILabel *label = [[UILabel alloc]init];
label.text = shops.name;
label.frame = CGRectMake(0, shopW, shopW, shopH - shopW );
label.font = [UIFont systemFontOfSize:11];
label.textAlignment = NSTextAlignmentCenter;
[shopView addSubview:label];
// 按钮点击事件是否可以继续点击的判断
[self checkState];
}
7>删除按钮
- (void)remove{
self.shopView.clipsToBounds = YES;
[[self.shopView.subviews lastObject]removeFromSuperview];
[self checkState];
}
8>按钮点击状态的状态监听(优化部分)
要在类扩展中进行label的声明并且和storyboard建立联系
@property (weak, nonatomic) IBOutlet UILabel *hud;
- (void)checkState{
// 删除按钮什么时候可以点击
self.removeBtn.enabled = (self.shopView.subviews.count > 0);
// 增加按钮什么时候可以点击
self.addBtn.enabled = (self.shopView.subviews.count < self.shop.count);
// 先将hud清0
NSString *text = nil;
if (self.removeBtn.enabled == NO) {
text = @"已经全部删除";
}
else if(self.addBtn.enabled == NO){
text = @"所有物品已加入";
}
if (text == nil) return;
self.hud.text = text;
self.hud.alpha = 1.0;
// 通过多线程来做时间的延迟
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.hud.alpha = 0.0;
});
}