触控(Touch) 、 布局(Layout)
1 使用触控实现一个简易的画板
1.1 问题
触控(Touch)是一个UITouch类型的对象,当用户触摸了屏幕上的视图时自动被创建,通常使用触控实现绘图、涂鸦、手写等功能。本案例使用触控实现一个简易的画板,可以在画板上勾画出一条线,如图-1所示:
图-1
1.2 方案
首先在创建好的SingleViewApplication项目中创建一个画板类TRDrawView,继承至UIView,该类有一个NSMutableArray类型的属性points,用于存储手指触摸的轨迹也就是点。
其次在Stroyboard的场景中拖放一个View控件,和屏幕一样大小,然后将View的类型修改为TRDrawView。
然后在TRDrawView类中通过touchesBegan:、touchesMoved:方法获取到手指的触摸点,将点存储到points数组中。
最后在TRDrawView类中重写drawRect方法,该方法中根据手指的触摸轨迹points进行屏幕绘制。切记要在touchesMoved方法中调用setNeedDisplay刷新界面。
1.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建项目和画板类
首先在创建好的SingleViewApplication项目中创建一个画板类TRDrawView,继承至UIView,该类有一个NSMutableArray类型的属性points,用于存储手指触摸的轨迹也就是点,代码如下所示:
- @interface TRDrawView ()
- @property (strong, nonatomic) NSMutableArray *points;
- @end
然后从对象库中拖放一个View控件到Storyboard场景中,View控件的大小和屏幕一样。在右边栏的检查器三将View的类型设置为TRDrawView,如图-2所示:
图-2
步骤二:在TRDawView中获取手指触摸轨迹
在TRDrawView类中首先重写touchesBegan:,在该方法将points属性进行初始化,并获取当前手指的触摸点,存储到points数组中,代码如下所示:
- - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
- {
- //初始化数组
- self.points = [@[]mutableCopy];
- //获取当前触摸点
- UITouch *touch = [touches anyObject];
- CGPoint point = [touch locationInView:self];
- //将点放进数组中
- NSValue *value = [NSValue valueWithCGPoint:point];
- [self.points addObject:value];
- }
然后再重写touchesMove:方法,在该方法中继续获取手指的当前触摸点,并将触摸点存储到points数组中,代码如下所示:
- - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
- {
- //获取当前触摸点
- UITouch *touch = [touches anyObject];
- CGPoint point = [touch locationInView:self];
- //将点放进数组中
- NSValue *value = [NSValue valueWithCGPoint:point];
- [self.points addObject:value];
- }
步骤三:重写drawRect方法,进行屏幕绘制
在TRDrawView类中重写drawRect方法,该方法中根据手指的触摸轨迹points进行屏幕绘制,代码如下所示:
- - (void)drawRect:(CGRect)rect
- {
- UIBezierPath *path = [UIBezierPath bezierPath];
- NSValue *value = [self.points firstObject];
- [path moveToPoint:[value CGPointValue]];
- for (NSValue *value in self.points) {
- [path addLineToPoint:[value CGPointValue]];
- }
- path.lineWidth = 4;
- [[UIColor redColor]setStroke];
- [path stroke];
- }
最后要在touchesMoved:和touchesEnded:方法中调用setNeedDisplay刷新界面,代码如下所示:
- - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
- {
- //获取当前触摸点
- UITouch *touch = [touches anyObject];
- CGPoint point = [touch locationInView:self];
- //将点放进数组中
- NSValue *value = [NSValue valueWithCGPoint:point];
- [self.points addObject:value];
- //刷新界面
- [self setNeedsDisplay];
- }
- - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
- {
- [self setNeedsDisplay];
- }
1.4 完整代码
本案例中,TRDrawView.m文件中的完整代码如下所示:
2 使用纯代码进行界面布局
2.1 问题
纯代码布局就是重写布局方法viewDidLayoutSubviews,在该方法内部计算每个子视图的frame属性。本案例将学习如何使用纯代码进行布局,使界面上的Button和Label控件始终保持在固定的位置,如图-3、图-4所示:
图-3
图-4
2.2 方案
首先创建一个SingleViewApplication项目,将自动布局功能关闭。
在Stroyboard的场景中拖放两个Button控件和一个Label控件,Button放置在屏幕的上方,并且大小一样,Label控件放置在屏幕的右下角。
然后在TRViewController类中重写布局方法viewDidLayoutSubviews,在该方法中根据父视图的bounds计算Button和Label的frame。
2.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建项目,添加控件
首先创建一个SingleViewApplication项目,在右边栏的检查器一中将自动布局功能关闭,如图-5所示:
图-5
在Stroyboard的场景中拖放两个Button控件和一个Label控件,Button放置在屏幕的上方,并且大小一样,Label控件放置在屏幕的右下角,如图-6所示:
图-6
步骤二:重写布局方法viewDidLayoutSubviews,进行界面布局
将Storyboard中的Button控件和Label控件关联成TRViewController的私有属性,代码如下所示:
- @interface TRViewController ()
- @property (weak, nonatomic) IBOutlet UIButton *button1;
- @property (weak, nonatomic) IBOutlet UIButton *button2;
- @property (weak, nonatomic) IBOutlet UILabel *label;
- @end
在TRViewController类中重写布局方法viewDidLayoutSubviews,在该方法中根据父视图的bounds计算Button和Label的frame,代码如下所示:
- - (void)viewDidLayoutSubviews
- {
- [super viewDidLayoutSubviews];
- CGFloat buttonWidth = (self.view.bounds.size.width - 20 - 20 - 10) * 0.5;
- CGRect frame = CGRectMake(20, self.button1.frame.origin.y, buttonWidth, 40);
- self.button1.frame = frame;
- frame = CGRectMake(self.button1.frame.size.width+30, self.button2.frame.origin.y, buttonWidth, 40);
- self.button2.frame = frame;
- frame = self.label.frame;
- self.label.frame = CGRectMake(self.view.bounds.size.width-20-frame.size.width, self.view.bounds.size.height-20-frame.size.height, frame.size.width, frame.size.height);
- }
2.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "TRViewController.h"
- @interface TRViewController ()
- @property (weak, nonatomic) IBOutlet UIButton *button1;
- @property (weak, nonatomic) IBOutlet UIButton *button2;
- @property (weak, nonatomic) IBOutlet UILabel *label;
- @end
- @implementation TRViewController
- - (void)viewDidLayoutSubviews
- {
- [super viewDidLayoutSubviews];
- CGFloat buttonWidth = (self.view.bounds.size.width - 20 - 20 - 10) * 0.5;
- CGRect frame = CGRectMake(20, self.button1.frame.origin.y, buttonWidth, 40);
- self.button1.frame = frame;
- frame = CGRectMake(self.button1.frame.size.width+30, self.button2.frame.origin.y, buttonWidth, 40);
- self.button2.frame = frame;
- frame = self.label.frame;
- self.label.frame = CGRectMake(self.view.bounds.size.width-20-frame.size.width, self.view.bounds.size.height-20-frame.size.height, frame.size.width, frame.size.height);
- }
- @end
3 根据上边栏和下边栏的高度进行布局
3.1 问题
从iOS7开始,视图控制器会渗透到各种Bar下面,包括:NavigationBar、ToolBar、TabBar、StatusBar等;这些Bar会挤占视图的空间,在布局时就需要根据各种Bar所挤占的空间大小来计算控件的frame,本案例直接在上一个案例的基础上实现,根据上边栏和下边栏的高度对界面进行布局,如图-7、图-8所示:
图-7
图-8
3.2 方案
首先在上一个案例的基础上增加一个NavigationController和TabBarController,在界面的中间拖放一个Button控件,标题设置为“隐藏NavigationBar”,并将Button控件关联成TRViewController的私有方法hideNavigationBar。
然后在TRViewController类中重写布局方法viewDidLayoutSubviews,在该方法中根据父视图的bounds和上下边栏的高度计算Button和Label的frame。
3.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建项目,添加按钮控件
在上一个案例的基础上增加一个NavigationController和TabBarController,在界面的中间拖放一个Button控件,标题设置为“隐藏NavigationBar”,如图-9所示:
图-9
然后将Button控件关联成TRViewController的私有方法hideNavigationBar,该方法的功能是将导航栏隐藏或显示,代码如下所示:
- - (IBAction)hideNavigationBar
- {
- self.navigationController.navigationBarHidden = !self.navigationController.navigationBarHidden;
- }
步骤二:重写布局方法viewDidLayoutSubviews,进行界面布局
在TRViewController类中重写布局方法viewDidLayoutSubviews,在该方法中根据先通过属性self.topLayoutGuide.length和self.bottomLayoutGuide.length获取到上下边栏的高度,然后再通过父视图的bounds和上下边栏的高度计算出Button和Label的frame,代码如下所示:
- - (void)viewDidLayoutSubviews
- {
- [super viewDidLayoutSubviews];
- CGFloat buttonWidth = (self.view.bounds.size.width - 20 - 20 - 10) * 0.5;
- //从iOS7开始,可以随时知道VC的上面和下面被各种Bar占据了多少的空间
- CGFloat top = self.topLayoutGuide.length;
- CGRect frame = CGRectMake(20, top+10, buttonWidth, 40);
- self.button1.frame = frame;
- frame.origin.x += buttonWidth + 10;
- self.button2.frame = frame;
- //下面的各种Bar(TabBar或ToolBar)占了VC多高的空间
- CGFloat bottom = self.bottomLayoutGuide.length;
- frame = self.label.frame;
- frame = CGRectMake(self.view.bounds.size.width - 20 - frame.size.width , self.view.bounds.size.height - 10 - frame.size.height - bottom, frame.size.width, frame.size.height);
- self.label.frame = frame;
- frame = self.hideButton.frame;
- frame.origin.x = self.view.bounds.size.width * 0.5 - frame.size.width * 0.5;
- frame.origin.y = self.view.bounds.size.height * 0.5 - frame.size.height * 0.5;
- self.hideButton.frame = frame;
- }
3.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "TRViewController.h"
- @interface TRViewController ()
- @property (weak, nonatomic) IBOutlet UIButton *button1;
- @property (weak, nonatomic) IBOutlet UIButton *button2;
- @property (weak, nonatomic) IBOutlet UILabel *label;
- @property (weak, nonatomic) IBOutlet UIButton *hideButton;
- @end
- @implementation TRViewController
- - (IBAction)hideNavigationBar
- {
- self.navigationController.navigationBarHidden = !self.navigationController.navigationBarHidden;
- }
- - (void)viewDidLayoutSubviews
- {
- [super viewDidLayoutSubviews];
- CGFloat buttonWidth = (self.view.bounds.size.width - 20 - 20 - 10) * 0.5;
- //从iOS7开始,可以随时知道VC的上面和下面被各种Bar占据了多少的空间
- CGFloat top = self.topLayoutGuide.length;
- CGRect frame = CGRectMake(20, top+10, buttonWidth, 40);
- self.button1.frame = frame;
- frame.origin.x += buttonWidth + 10;
- self.button2.frame = frame;
- //下面的各种Bar(TabBar或ToolBar)占了VC多高的空间
- CGFloat bottom = self.bottomLayoutGuide.length;
- frame = self.label.frame;
- frame = CGRectMake(self.view.bounds.size.width - 20 - frame.size.width , self.view.bounds.size.height - 10 - frame.size.height - bottom, frame.size.width, frame.size.height);
- self.label.frame = frame;
- frame = self.hideButton.frame;
- frame.origin.x = self.view.bounds.size.width * 0.5 - frame.size.width * 0.5;
- frame.origin.y = self.view.bounds.size.height * 0.5 - frame.size.height * 0.5;
- self.hideButton.frame = frame;
- }
- @end
4 演示绘制图形的布局
4.1 问题
使用纯代码布局并且AutoLayout关闭的状态下,在drawRect方法中绘制的图形,在视图大小发生变化时图形会失真,本案例学习绘制图形的布局如图-10,图-11所示:
图-10
图-11
4.2 方案
首先在创建好的项目中将自动布局功能关闭,再创建一个TRView类,继承至UIView。
其次在Stroyboard的场景中拖放一个View控件,和屏幕一样大小,然后将View的类型修改为TRView。
然后在TRView类中重写drawRect方法,在屏幕左上方绘制一个三角形。
最后将TRView的contentMode属性设置成Redraw,即可实现绘制的布局,屏幕切换或者变化绘制的图形也不会失真。
4.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建TRView类,绘制图像
首先在创建好的项目中将自动布局功能关闭,创建一个TRView类,继承至UIView,用于绘制图形。在Storyboard中拖放一个View控件,和屏幕同等大小,并将View的类型修改为TRView,如图-12所示:
图-12
然后将View控件关联成TRViewController的私有属性myView,代码如下所示:
- @interface TRViewController ()
- @property (weak, nonatomic) IBOutlet TRView *myView;
- @end
最后在TRView类中重写drawRect方法,在屏幕左上方绘制一个三角形,代码如下所示:
- - (void)drawRect:(CGRect)rect
- {
- UIBezierPath *path = [UIBezierPath bezierPath];
- [path moveToPoint:CGPointMake(20, 20)];
- [path addLineToPoint:CGPointMake(20, 120)];
- [path addLineToPoint:CGPointMake(120, 20)];
- [path closePath];
- path.lineWidth = 4;
- [[UIColor redColor] setStroke];
- [path stroke];
- }
步骤二:进行绘制布局
完成绘制代码,运行程序可见屏幕左上方有一个三角形,但是当切换成横屏时发现三角形失真,如图-13所示:
图-13
解决的办法是,当视图大小发生变化时,进行重新绘制图形,即在布局方法viewDidLayoutSubviews里面调用setNeedDisplay方法即可,代码如下所示:
- - (void)viewDidLayoutSubviews
- {
- [super viewDidLayoutSubviews];
- [self.myView setNeedsDisplay];
- }
但是通常直接将myView的contentMode属性设置为Redraw即可实现绘制布局,相当于调用了上面的代码,将myView的contentMode属性设置为Redraw有两个方法,第一种可以直接通过代码设置,代码如下所示:
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- self.myView.contentMode = UIViewContentModeRedraw;
- }
第二种方法可以直接在Stroyboard中设置,右边栏的检查器四中将Mode选项设置为Redraw即可,如图-14所示:
图-14
将contentMode设置为Redraw之后就不需要再写布局代码,此时切换屏幕绘制图形就不会失真了。
4.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "TRViewController.h"
- #import "TRView.h"
- @interface TRViewController ()
- @property (weak, nonatomic) IBOutlet TRView *myView;
- @end
- @implementation TRViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- self.myView.contentMode = UIViewContentModeRedraw;
- }
- //- (void)viewDidLayoutSubviews
- //{
- // [super viewDidLayoutSubviews];
- // [self.myView setNeedsDisplay];
- //}
- @end
本案例中,TRView.m文件中的完整代码如下所示:
- #import "TRView.h"
- @implementation TRView
- - (void)drawRect:(CGRect)rect
- {
- UIBezierPath *path = [UIBezierPath bezierPath];
- [path moveToPoint:CGPointMake(20, 20)];
- [path addLineToPoint:CGPointMake(20, 120)];
- [path addLineToPoint:CGPointMake(120, 20)];
- [path closePath];
- path.lineWidth = 4;
- [[UIColor redColor] setStroke];
- [path stroke];
- }
- @end
5 对乐库项目的播放列表单元格进行布局
5.1 问题
视图自身也可以使用布局方法layoutSubviews对自己的子视图进行布局,本案例使用视图的layoutSubviews方法给乐库项目的播放列表单元格进行布局,如图-15所示:
图-15
5.2 方案
首先创建一个SingleViewApplication项目,将Xcode自带的TRViewController类删除,创建一个TRMusicsTableViewController类,继承至UITableViewController,该类有一个NSArray类型的属性musics用于存储歌曲数据源。
再将Storyboard中自带的场景删除,拖放一个TableViewController到界面中,嵌入一个NavigaitionController。在右边栏的检查器中将TableViewController设置为动态表视图,并和TRMusicsTableViewController类进行绑定。
其次创建一个带有xib的TRMusicCell类,继承至UITableViewCell,在xib文件中进行自定义cell,往cell的contentView视图上拖放所需要的控件。
首先在cell的上方拖放一个Label控件,用于显示歌曲的名字。在cell的下方依次拖放两个ImageView控件和两个Label控件,两个ImageView控件分别用于表示歌曲是否为本地歌曲和是否高清。两个Label控件分别用于显示歌曲的信息和时长。
调整好cell上面各个控件的大小,将个控件关联为TRMusicCell的属性musicNameLabel、albumAndArtistLabel、durationLabel、downloadedImageView以及hdImageView。
然后再创建一个TRMusic类用于存储歌曲的相关信息,该类继承至NSObject,有五个属性,分别为:
NSString类型的name,用于记录歌曲名称;
NSString类型的album,用于记录歌曲所属专辑;
NSString类型的artist,用于记录歌曲的演唱者;
NSString类型的duration,用于记录歌曲的时长;
BOOL类型的highQuality和downloaded,分别用于记录是否高清和是否本地下载。
我们创建一个TRMusicGroup类,用于生成一组模拟的歌曲数据。
最后在TRMusicCell类中定义一个TRMusic类型属性music,用于存储单元格需要展示的歌曲。重写layoutSubviews方法,进行cell的界面布局,该方法中会根据每首歌曲的信息,计算子视图的frame进行布局。
在TRMusicTableViewController类注册Cell,回答三问给表视图加载歌曲数据。
5.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建播放列表项目
首先创建一个SingleViewApplication项目,将Xcode自带的TRViewController类删除,创建一个TRMusicsTableViewController类,继承至UITableViewController,该类有一个NSArray类型的属性musics用于存储歌曲数据源,代码如下所示:
- @interface TRMusicTableViewController : UITableViewController
- @property (strong, nonatomic) NSArray *musics;
- @end
然后将Storyboard中自带的场景删除,拖放一个TableViewController到界面中,嵌入一个NavigaitionController。在右边栏的检查器中将TableViewController设置为动态表视图,并和TRMusicsTableViewController类进行绑定,如图-16所示:
图-16
为了能更灵活的使用自定义cell,由于本案例使用xib的方式进行自定义cell,所以将Storyboard中表视图自带的cell对象删除,如图-17所示:
图-17
步骤二:创建TRMusicCell类,自定义Cell
首先创建一个带有xib的TRMusicCell类,继承至UITableViewCell,在xib文件中进行自定义cell,往cell的contentView视图上拖放所需要的控件。
先在cell的上方拖放一个Label控件,用于显示歌曲的名字。
再在cell的下方依次拖放两个ImageView控件和两个Label控件,两个ImageView控件分别用于表示歌曲是否为本地歌曲和是否高清。两个Label控件分别用于显示歌曲的信息和时长。
设置好cell上面各个控件的大小和属性,如图-18所示:
图-18
最后将cell上的各个控件关联为TRMusicCell的属性musicNameLabel、albumAndArtistLabel、durationLabel、downloadedImageView以及hdImageView,代码如下所示:
- @interface TRMusicCell ()
- @property (weak, nonatomic) IBOutlet UILabel *musicNameLabel;
- @property (weak, nonatomic) IBOutlet UILabel *albumAndArtistLabel;
- @property (weak, nonatomic) IBOutlet UILabel *durationLabel;
- @property (weak, nonatomic) IBOutlet UIImageView *downloadedImageView;
- @property (weak, nonatomic) IBOutlet UIImageView *hdImageView;
- @end
步骤三:创建TRMusic类和歌曲模拟数据
首先创建一个TRMusic类用于存储歌曲的相关信息,该类继承至NSObject,有五个属性,分别为:
NSString类型的name,用于记录歌曲名称;
NSString类型的album,用于记录歌曲所属专辑;
NSString类型的artist,用于记录歌曲的演唱者;
NSString类型的duration,用于记录歌曲的时长;
BOOL类型的highQuality和downloaded,分别用于记录是否高清和是否本地下载。
代码如下所示:
- @interface TRMusic : NSObject
- @property (nonatomic, copy) NSString * name;
- @property (nonatomic, copy) NSString * album;
- @property (nonatomic, copy) NSString * artist;
- @property (nonatomic) NSTimeInterval duration;
- @property (nonatomic) BOOL highQuality;
- @property (nonatomic) BOOL downloaded;
- @end
然后再创建一个TRMusicGroup类,该类提供一个静态方法fakeData,用于生成一组模拟的歌曲数据,代码如下所示:
- + (NSArray *) fakeData
- {
- NSMutableArray * musics = nil;
- TRMusic * music = nil;
- musics = [NSMutableArray array];
- music = [[TRMusic alloc] init];
- music.name = @"Burn";
- music.album = @"Burn - Single";
- music.artist = @"Ellie Goulding";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Summertime Sadness (Cedric Gervais Remix)";
- music.album = @"Summertime Sadness (Cedric Gervais Remix) - Single";
- music.artist = @"Lana Del Rey";
- music.duration = [self durationWithMinutes:6 andSeconds:52];
- music.downloaded = YES;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Spectrum";
- music.album = @"Clarity";
- music.artist = @"Zedd";
- music.duration = [self durationWithMinutes:4 andSeconds:3];
- music.downloaded = YES;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"It's Time";
- music.album = @"It’s Time";
- music.artist = @"Imagine Dragons";
- music.duration = [self durationWithMinutes:4 andSeconds:0];
- music.downloaded = NO;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Dancing in The Moonlight";
- music.album = @"Dancing In The Moonlight: The Best Of Toploader";
- music.artist = @"Toploader";
- music.duration = [self durationWithMinutes:3 andSeconds:53];
- music.downloaded = YES;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Thinking About You (feat. Ayah Marar)";
- music.album = @"18 Months (Deluxe Edition)";
- music.artist = @"Calvin Harris";
- music.duration = [self durationWithMinutes:4 andSeconds:8];
- music.downloaded = YES;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"You Make Me (feat. Salem Al Fakir)";
- music.album = @"True";
- music.artist = @"Avicii";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Safe and Sound";
- music.album = @"Capital Cities EP";
- music.artist = @"Capital Cities";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Reaching Out";
- music.album = @"Welcome Reality (Deluxe Version)";
- music.artist = @"nero";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Recover";
- music.album = @"Recover - EP";
- music.artist = @"CHVRCHES";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Hold On, We're Going Home (feat. Majid Jordan)";
- music.album = @"Hold On, We're Going Home (feat. Majid Jordan) - Single";
- music.artist = @"Drake";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"The Mother We Share";
- music.album = @"The Mother We Share - Single";
- music.artist = @"CHVRCHES";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Promises";
- music.album = @"nero";
- music.artist = @"Promises - EP";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Alone Together";
- music.album = @"Save Rock and Roll";
- music.artist = @"Fall Out Boy";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Reload (Radio Edit)";
- music.album = @"Reload (Radio Edit) - Single";
- music.artist = @"Sebastian Ingrosso";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"I Love It (feat. Charli XCX)";
- music.album = @"Iconic";
- music.artist = @"Icona Pop";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Feel the Love";
- music.album = @"Feel the Love (feat. John Newman) [Remixes] - EP";
- music.artist = @"Rudimental";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Goin' Crazy (feat. Robbie Williams)";
- music.album = @"Goin' Crazy (feat. Robbie Williams) - Single";
- music.artist = @"Dizzee Rascal";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Still Into You";
- music.album = @"Paramore";
- music.artist = @"Paramore";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Heart Attack";
- music.album = @"Demi";
- music.artist = @"Demi Lovato";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Explosions";
- music.album = @"Halcyon (Deluxe Edition)";
- music.artist = @"Ellie Goulding";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"I Need Your Love (feat. Ellie Goulding)";
- music.album = @"I Need Your Love";
- music.artist = @"Calvin Harris";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Starry Eyed";
- music.album = @"Bright Lights";
- music.artist = @"Ellie Goulding";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Lights (Single Version)";
- music.album = @"Bright Lights";
- music.artist = @"Ellie Goulding";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Who's That Chick?";
- music.album = @"Who's That Chick - Single";
- music.artist = @"David Guetta";
- music.duration = [self durationWithMinutes:2 andSeconds:47];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- TRMusicGroup * g1 = [[TRMusicGroup alloc] init];
- g1.name = @"国外单曲";
- g1.musics = [musics copy];
- g1.state = TRMusicGroupStateDownloaded;
- musics = [NSMutableArray array];
- music = [[TRMusic alloc] init];
- music.name = @"致青春";
- music.album = @"致青春";
- music.artist = @"王菲";
- music.duration = [self durationWithMinutes:3 andSeconds:18];
- music.downloaded = NO;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"好汉歌";
- music.album = @"六十年代生人";
- music.artist = @"刘欢";
- music.duration = [self durationWithMinutes:3 andSeconds:41];
- music.downloaded = NO;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"忐忑";
- music.album = @"自由鸟";
- music.artist = @"龚琳娜";
- music.duration = [self durationWithMinutes:4 andSeconds:03];
- music.downloaded = NO;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"爱情买卖";
- music.album = @"我们的爱我不放手";
- music.artist = @"慕容晓晓";
- music.duration = [self durationWithMinutes:3 andSeconds:31];
- music.downloaded = NO;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"法海你不懂爱";
- music.album = @"法海你不懂爱 - 单曲";
- music.artist = @"龚琳娜";
- music.duration = [self durationWithMinutes:3 andSeconds:33];
- music.downloaded = NO;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"最炫民族风";
- music.album = @"我们的爱我不放手";
- music.artist = @"凤凰传奇";
- music.duration = [self durationWithMinutes:4 andSeconds:46];
- music.downloaded = NO;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"金箍棒";
- music.album = @"金箍棒 - 单曲";
- music.artist = @"龚琳娜";
- music.duration = [self durationWithMinutes:2 andSeconds:52];
- music.downloaded = NO;
- music.highQuality = NO;
- [musics addObject:music];
- TRMusicGroup * g2 = [[TRMusicGroup alloc] init];
- g2.name = @"国内神曲";
- g2.musics = [musics copy];
- g2.state = TRMusicGroupStateNormal;
- TRMusicGroup * g3 = [[TRMusicGroup alloc] init];
- g3.name = @"Calvin Harris 专辑";
- g3.musics = @[];
- g3.state = TRMusicGroupStateNormal;
- TRMusicGroup * g4 = [[TRMusicGroup alloc] init];
- g4.name = @"Ellie Gounding 专辑";
- g4.musics = @[];
- g4.state = TRMusicGroupStateNormal;
- return @[g1, g2, g3, g4];
- }
步骤四:进行自定义cell布局
首先在TRMusicTableViewController类注册Cell,并在TRAppDelegate中对属性musics进行初始化,获取到模拟的歌曲数据,代码如下所示:
- //在TRAppDelegate中进行musics属性的初始化
- -(BOOL)application:(UIApplication *)application
- didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
- {
- NSArray *musicGroups = [TRMusicGroup fakeData];
- TRMusicGroup *group = musicGroups[0];
- UINavigationController *navi = (UINavigationController *)self.window.rootViewController;
- TRMusicTableViewController *musicTVC = (TRMusicTableViewController *) navi.topViewController;
- musicTVC.musics = group.musics;
- return YES;
- }
- //在TRMusicsTableViewController中注册cell
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- [self.tableView registerNib:[UINib nibWithNibName: @"TRMusicCell" bundle:nil] forCellReuseIdentifier:musicCellIdentifier];
- }
然后在TRMusicCell类中定义一个TRMusic类型属性music,用于存储单元格需要展示的歌曲,代码如下所示:
- //TRMusicCell.h文件中定义属性music
- @interface TRMusicCell : UITableViewCell
- @property (strong, nonatomic) TRMusic *music;
- @end
在TRMusicCell重写layoutSubviews方法,进行cell的界面布局,该方法中会根据每首歌曲的信息,计算子视图的frame进行布局,代码如下所示:
- - (void)layoutSubviews
- {
- [super layoutSubviews];
- CGFloat x = self.downloadedImageView.frame.origin.x;
- if (self.music.downloaded){
- x += 20;
- }
- if (self.music.highQuality) {
- CGRect frame = self.hdImageView.frame;
- frame.origin.x = x;
- self.hdImageView.frame = frame;
- x += 20;
- }
- CGRect frame = self.albumAndArtistLabel.frame;
- frame.origin.x = x;
- self.albumAndArtistLabel.frame = frame;
- }
歌曲的高清和下载图标需要根据歌曲的相关信息进行显示,可以将此部分功能通过重写music的setter方法来实现,代码如下所示:
- //TRMusicCell.m文件候中重写music的setter方法
- - (void)setMusic:(TRMusic *)music
- {
- _music = music;
- self.musicNameLabel.text = music.name;
- self.albumAndArtistLabel.text = [NSString stringWithFormat:@"%@ - %@", music.album, music.artist];
- self.durationLabel.text = [NSString stringWithFormat:@"%d:%02d", (int)music.duration/60, (int)music.duration%60];
- self.downloadedImageView.hidden = !music.downloaded;
- self.hdImageView.hidden = !music.highQuality;
- //根据是否高清或下载状态,需要重新布局
- [self setNeedsLayout];
- }
最后在TRMusicsTableViewController类中回答三问给表视图加载歌曲数据,并将单元格的行高设置为50,代码如下所示:
- -(NSInteger)tableView:(UITableView *)tableView
- numberOfRowsInSection:(NSInteger)section
- {
- return self.musics.count;
- }
- -(UITableViewCell *)tableView:(UITableView *)tableView
- cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- TRMusicCell *cell = [tableView dequeueReusableCellWithIdentifier:musicCellIdentifier forIndexPath:indexPath];
- cell.music = self.musics[indexPath.row];
- return cell;
- }
- -(CGFloat)tableView:(UITableView *)tableView
- heightForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- return 50;
- }
5.4 完整代码
本案例中,TRAppDelegate.m文件中的完整代码如下所示:
- #import "TRAppDelegate.h"
- #import "TRMusicGroup.h"
- #import "TRMusicTableViewController.h"
- @implementation TRAppDelegate
- -(BOOL)application:(UIApplication *)application
- didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
- {
- NSArray *musicGroups = [TRMusicGroup fakeData];
- TRMusicGroup *group = musicGroups[0];
- UINavigationController *navi = (UINavigationController *)self.window.rootViewController;
- TRMusicTableViewController *musicTVC = (TRMusicTableViewController *) navi.topViewController;
- musicTVC.musics = group.musics;
- return YES;
- }
- @end
本案例中,TRMusicTableViewController.h文件中的完整代码如下所示:
- #import <UIKit/UIKit.h>
- @interface TRMusicTableViewController : UITableViewController
- @property (strong, nonatomic) NSArray *musics;
- @end
本案例中,TRMusicCell.h文件中的完整代码如下所示:
- #import <UIKit/UIKit.h>
- #import "TRMusic.h"
- @interface TRMusicCell : UITableViewCell
- @property (strong, nonatomic) TRMusic *music;
- @end
本案例中,TRMusicCell.m文件中的完整代码如下所示:
- #import "TRMusicCell.h
- @interface TRMusicCell ()
- @property (weak, nonatomic) IBOutlet UILabel *musicNameLabel;
- @property (weak, nonatomic) IBOutlet UILabel *albumAndArtistLabel;
- @property (weak, nonatomic) IBOutlet UILabel *durationLabel;
- @property (weak, nonatomic) IBOutlet UIImageView *downloadedImageView;
- @property (weak, nonatomic) IBOutlet UIImageView *hdImageView;
- @end
- @implementation TRMusicCell
- - (void)setMusic:(TRMusic *)music
- {
- _music = music;
- self.musicNameLabel.text = music.name;
- self.albumAndArtistLabel.text = [NSString stringWithFormat:@"%@ - %@", music.album, music.artist];
- self.durationLabel.text = [NSString stringWithFormat:@"%d:%02d", (int)music.duration/60, (int)music.duration%60];
- self.downloadedImageView.hidden = !music.downloaded;
- self.hdImageView.hidden = !music.highQuality;
- [self setNeedsLayout];//需要重新布局
- }
- //当当前视图的大小发生变化时调用
- - (void)layoutSubviews
- {
- [super layoutSubviews];
- CGFloat x = self.downloadedImageView.frame.origin.x;
- if (self.music.downloaded){
- x += 20;
- }
- if (self.music.highQuality) {
- CGRect frame = self.hdImageView.frame;
- frame.origin.x = x;
- self.hdImageView.frame = frame;
- x += 20;
- }
- CGRect frame = self.albumAndArtistLabel.frame;
- frame.origin.x = x;
- self.albumAndArtistLabel.frame = frame;
- }
- @end
本案例中,TRMusic.h文件中的完整代码如下所示:
- #import <Foundation/Foundation.h>
- @interface TRMusic : NSObject
- @property (nonatomic, copy) NSString * name;
- @property (nonatomic, copy) NSString * album;
- @property (nonatomic, copy) NSString * artist;
- @property (nonatomic) NSTimeInterval duration;
- @property (nonatomic) BOOL highQuality;
- @property (nonatomic) BOOL downloaded;
- @end
本案例中,TRMusicGroup.h文件中的完整代码如下所示:
- #import <Foundation/Foundation.h>
- #import "TRMusic.h"
- typedef NS_ENUM(NSInteger, TRMusicGroupState) {
- TRMusicGroupStateNormal,
- TRMusicGroupStateDownloading,
- TRMusicGroupStateDownloaded
- };
- @interface TRMusicGroup : NSObject
- @property (nonatomic, copy) NSString * name;
- @property (nonatomic, strong) NSArray * musics;
- @property (nonatomic) TRMusicGroupState state;
- + (NSArray *) fakeData;
- @end
本案例中,TRMusicGroup.m文件中的完整代码如下所示:
- #import "TRMusicGroup.h"
- @implementation TRMusicGroup
- + (NSArray *) fakeData
- {
- NSMutableArray * musics = nil;
- TRMusic * music = nil;
- musics = [NSMutableArray array];
- music = [[TRMusic alloc] init];
- music.name = @"Burn";
- music.album = @"Burn - Single";
- music.artist = @"Ellie Goulding";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Summertime Sadness (Cedric Gervais Remix)";
- music.album = @"Summertime Sadness (Cedric Gervais Remix) - Single";
- music.artist = @"Lana Del Rey";
- music.duration = [self durationWithMinutes:6 andSeconds:52];
- music.downloaded = YES;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Spectrum";
- music.album = @"Clarity";
- music.artist = @"Zedd";
- music.duration = [self durationWithMinutes:4 andSeconds:3];
- music.downloaded = YES;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"It's Time";
- music.album = @"It’s Time";
- music.artist = @"Imagine Dragons";
- music.duration = [self durationWithMinutes:4 andSeconds:0];
- music.downloaded = NO;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Dancing in The Moonlight";
- music.album = @"Dancing In The Moonlight: The Best Of Toploader";
- music.artist = @"Toploader";
- music.duration = [self durationWithMinutes:3 andSeconds:53];
- music.downloaded = YES;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Thinking About You (feat. Ayah Marar)";
- music.album = @"18 Months (Deluxe Edition)";
- music.artist = @"Calvin Harris";
- music.duration = [self durationWithMinutes:4 andSeconds:8];
- music.downloaded = YES;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"You Make Me (feat. Salem Al Fakir)";
- music.album = @"True";
- music.artist = @"Avicii";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Safe and Sound";
- music.album = @"Capital Cities EP";
- music.artist = @"Capital Cities";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Reaching Out";
- music.album = @"Welcome Reality (Deluxe Version)";
- music.artist = @"nero";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Recover";
- music.album = @"Recover - EP";
- music.artist = @"CHVRCHES";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Hold On, We're Going Home (feat. Majid Jordan)";
- music.album = @"Hold On, We're Going Home (feat. Majid Jordan) - Single";
- music.artist = @"Drake";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"The Mother We Share";
- music.album = @"The Mother We Share - Single";
- music.artist = @"CHVRCHES";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Promises";
- music.album = @"nero";
- music.artist = @"Promises - EP";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Alone Together";
- music.album = @"Save Rock and Roll";
- music.artist = @"Fall Out Boy";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Reload (Radio Edit)";
- music.album = @"Reload (Radio Edit) - Single";
- music.artist = @"Sebastian Ingrosso";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"I Love It (feat. Charli XCX)";
- music.album = @"Iconic";
- music.artist = @"Icona Pop";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Feel the Love";
- music.album = @"Feel the Love (feat. John Newman) [Remixes] - EP";
- music.artist = @"Rudimental";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Goin' Crazy (feat. Robbie Williams)";
- music.album = @"Goin' Crazy (feat. Robbie Williams) - Single";
- music.artist = @"Dizzee Rascal";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Still Into You";
- music.album = @"Paramore";
- music.artist = @"Paramore";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Heart Attack";
- music.album = @"Demi";
- music.artist = @"Demi Lovato";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Explosions";
- music.album = @"Halcyon (Deluxe Edition)";
- music.artist = @"Ellie Goulding";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"I Need Your Love (feat. Ellie Goulding)";
- music.album = @"I Need Your Love";
- music.artist = @"Calvin Harris";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Starry Eyed";
- music.album = @"Bright Lights";
- music.artist = @"Ellie Goulding";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Lights (Single Version)";
- music.album = @"Bright Lights";
- music.artist = @"Ellie Goulding";
- music.duration = [self durationWithMinutes:3 andSeconds:51];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"Who's That Chick?";
- music.album = @"Who's That Chick - Single";
- music.artist = @"David Guetta";
- music.duration = [self durationWithMinutes:2 andSeconds:47];
- music.downloaded = YES;
- music.highQuality = NO;
- [musics addObject:music];
- TRMusicGroup * g1 = [[TRMusicGroup alloc] init];
- g1.name = @"国外单曲";
- g1.musics = [musics copy];
- g1.state = TRMusicGroupStateDownloaded;
- musics = [NSMutableArray array];
- music = [[TRMusic alloc] init];
- music.name = @"致青春";
- music.album = @"致青春";
- music.artist = @"王菲";
- music.duration = [self durationWithMinutes:3 andSeconds:18];
- music.downloaded = NO;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"好汉歌";
- music.album = @"六十年代生人";
- music.artist = @"刘欢";
- music.duration = [self durationWithMinutes:3 andSeconds:41];
- music.downloaded = NO;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"忐忑";
- music.album = @"自由鸟";
- music.artist = @"龚琳娜";
- music.duration = [self durationWithMinutes:4 andSeconds:03];
- music.downloaded = NO;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"爱情买卖";
- music.album = @"我们的爱我不放手";
- music.artist = @"慕容晓晓";
- music.duration = [self durationWithMinutes:3 andSeconds:31];
- music.downloaded = NO;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"法海你不懂爱";
- music.album = @"法海你不懂爱 - 单曲";
- music.artist = @"龚琳娜";
- music.duration = [self durationWithMinutes:3 andSeconds:33];
- music.downloaded = NO;
- music.highQuality = NO;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"最炫民族风";
- music.album = @"我们的爱我不放手";
- music.artist = @"凤凰传奇";
- music.duration = [self durationWithMinutes:4 andSeconds:46];
- music.downloaded = NO;
- music.highQuality = YES;
- [musics addObject:music];
- music = [[TRMusic alloc] init];
- music.name = @"金箍棒";
- music.album = @"金箍棒 - 单曲";
- music.artist = @"龚琳娜";
- music.duration = [self durationWithMinutes:2 andSeconds:52];
- music.downloaded = NO;
- music.highQuality = NO;
- [musics addObject:music];
- TRMusicGroup * g2 = [[TRMusicGroup alloc] init];
- g2.name = @"国内神曲";
- g2.musics = [musics copy];
- g2.state = TRMusicGroupStateNormal;
- TRMusicGroup * g3 = [[TRMusicGroup alloc] init];
- g3.name = @"Calvin Harris 专辑";
- g3.musics = @[];
- g3.state = TRMusicGroupStateNormal;
- TRMusicGroup * g4 = [[TRMusicGroup alloc] init];
- g4.name = @"Ellie Gounding 专辑";
- g4.musics = @[];
- g4.state = TRMusicGroupStateNormal;
- return @[g1, g2, g3, g4];
- }
- + (NSTimeInterval) durationWithMinutes:(int)minutes andSeconds:(int)seconds
- {
- return minutes * 60 + seconds;
- }
- @end
触控(Touch) 、 布局(Layout)的更多相关文章
- 触控(Touch)
1 使用触控实现一个简易的画板 1.1 问题 触控(Touch)是一个UITouch类型的对象,当用户触摸了屏幕上的视图时自动被创建,通常使用触控实现绘图.涂鸦.手写等功能.本案例使用触控实现一个简易 ...
- sencha touch 入门系列 (九) sencha touch 布局layout
布局用来描述你应用程序中组件的大小和位置,在sencha touch中,为我们提供了下面几种布局: 1.HBox: HBox及horizontal box布局,我们这里将其称为水平布局,下面是一段演示 ...
- Duilib源码分析(五)UI布局—Layout与各子控件
接下来,继续分析duilib之UI布局Layout,目前提供的布局有:VerticalLayout.HorizontalLayout.TileLayout.TabLayout.ChildLayout分 ...
- 移动端H5混合开发,Touch触控,拖拽,长按, 滑屏 实现方案
概述 近期由于产品快速原型开发的需要,不想用原声的方式开发App两端一起搞时间来不及,目前产品处于大量上feature的阶段,采用混合开发是最合适的选择,所以花了3天的时间研究怎么去实现移动端,拖拽, ...
- cocos creator Touch事件应用(触控选择多个子节点)
最近参与了cocos creator的研究,开发小游戏,结果被一个事件坑得不行不行的.现在终于解决了,分享给大家. 原理 1.触控事件是针对节点的 2.触控事件的冒泡,是一级一级往上冒泡,中间可以阻止 ...
- Touch Bar 废物利用系列 | 在触控栏上显示 Dock 应用图标
都说 Intel 第八代 CPU 对比上代是牙膏不小心挤多了,而配备第八代 CPU 的 MacBook Pro,只有 Touch Bar 版本,虽然贵了一点,但就一个字 -- 买! 收到电脑后,兴冲冲 ...
- 【朝花夕拾】Android自定义View篇之(八)多点触控(上)MotionEvent简介
前言 在前面的文章中,介绍了不少触摸相关的知识,但都是基于单点触控的,即一次只用一根手指.但是在实际使用App中,常常是多根手指同时操作,这就需要用到多点触控相关的知识了.多点触控是在Android2 ...
- Android多点触控技术实战,自由地对图片进行缩放和移动
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11100327 在上一篇文章中我带着大家一起实现了Android瀑布流照片墙的效果, ...
- MultiTouch————多点触控,伸缩图片,变换图片位置
前言:当今的手机都支持多点触控功能(可以进行图片伸缩,变换位置),但是我们程序员要怎样结合硬件去实现这个功能呢? 跟随我一起,来学习这个功能 国际惯例:先上DEMO免费下载地址:http://down ...
随机推荐
- SQL Server数据库(作业讲解和复习)
--第一题 查询Student表中的所有记录的Sname.Ssex和Class列.select Sname,Ssex,Class from student --第二题 查询教师所有的单位即不重复的De ...
- Java 正则表达式 向前、向后匹配
//向后匹配 String a = "I paid $90 for 10 oranges, 12 pears and 8 apples. I saved $5 on "; Patt ...
- 告别node-forever,拥抱PM2
告别node-forever,拥抱PM2 返回原文英文原文:Goodbye node-forever,hello PM2 devo.ps团队对JavaScript的迷恋已经不是什么秘密了;node.j ...
- 我的R代码备份
1 #f1=scan(file="f1.txt"); 2 #f2=scan(file="f2.txt"); 3 f=scan(file="5.2_ ...
- 转:Nginx+Apache环境的安装与配置
转:http://www.server110.com/nginx/201404/8817.html 我们依然尽可能采用yum来安装我们需要的软件,由系统官方维护的软件,其安全性和稳定性都值得信赖,并且 ...
- js中Array自定义contains, indexOf, delete方法.
Array.prototype.contains = function (elem) { for (var i = 0; i < this.length; i++) { if (this[i] ...
- jquery返回上一页面
window.location.href=document.referrer; 返回然后刷新 window.history.back(-1); 返回不刷新
- ICTCLA中科院分词工具用法(java)
摘要:为解决中文搜索的问题,最开始使用PHP版开源的SCWS,但是处理人名和地名时,会出现截断人名地名出现错误.开始使用NLPIR分词,在分词准确性上效果要比SCWS好.本文介绍如何在windows系 ...
- Codeforces Round #326 (Div. 2)-Duff and Meat
题意: Duff每天要吃ai千克肉,这天肉的价格为pi(这天可以买好多好多肉),现在给你一个数值n为Duff吃肉的天数,求出用最少的钱满足Duff的条件. 思路: 只要判断相邻两天中,今天的总花费 = ...
- 【转发】RedHat Enterprise Linux 6.4 使用 Centos 6 的yum源问题
作为一名新手,学习Linux已经一个月了,其间遇到了不少问题,而今天笔者遇到的问题是 #yum install pam-devel #This system is not registered to ...