当前位置: 首页 > 编程日记 > 正文

触控(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,用于存储手指触摸的轨迹也就是点,代码如下所示:

  1. @interface TRDrawView ()
  2. @property (strong, nonatomicNSMutableArray *points;
  3. @end

然后从对象库中拖放一个View控件到Storyboard场景中,View控件的大小和屏幕一样。在右边栏的检查器三将View的类型设置为TRDrawView,如图-2所示:

图-2

步骤二:在TRDawView中获取手指触摸轨迹

在TRDrawView类中首先重写touchesBegan:,在该方法将points属性进行初始化,并获取当前手指的触摸点,存储到points数组中,代码如下所示:

  1. (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
  2. {
  3. //初始化数组
  4. self.points [@[]mutableCopy];
  5. //获取当前触摸点
  6. UITouch *touch [touches anyObject];
  7. CGPoint point [touch locationInView:self];
  8. //将点放进数组中
  9. NSValue *value [NSValue valueWithCGPoint:point];
  10. [self.points addObject:value];
  11. }

然后再重写touchesMove:方法,在该方法中继续获取手指的当前触摸点,并将触摸点存储到points数组中,代码如下所示:

  1. (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
  2. {
  3. //获取当前触摸点
  4. UITouch *touch [touches anyObject];
  5. CGPoint point [touch locationInView:self];
  6. //将点放进数组中
  7. NSValue *value [NSValue valueWithCGPoint:point];
  8. [self.points addObject:value];
  9. }

步骤三:重写drawRect方法,进行屏幕绘制

在TRDrawView类中重写drawRect方法,该方法中根据手指的触摸轨迹points进行屏幕绘制,代码如下所示:

  1. (void)drawRect:(CGRect)rect
  2. {
  3. UIBezierPath *path [UIBezierPath bezierPath];
  4. NSValue *value [self.points firstObject];
  5. [path moveToPoint:[value CGPointValue]];
  6. for (NSValue *value in self.points{
  7. [path addLineToPoint:[value CGPointValue]];
  8. }
  9. path.lineWidth 4;
  10. [[UIColor redColor]setStroke];
  11. [path stroke];
  12. }

最后要在touchesMoved:和touchesEnded:方法中调用setNeedDisplay刷新界面,代码如下所示:

  1. (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
  2. {
  3. //获取当前触摸点
  4. UITouch *touch [touches anyObject];
  5. CGPoint point [touch locationInView:self];
  6. //将点放进数组中
  7. NSValue *value [NSValue valueWithCGPoint:point];
  8. [self.points addObject:value];
  9. //刷新界面
  10. [self setNeedsDisplay];
  11. }
  12. (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
  13. {
  14. [self setNeedsDisplay];
  15. }

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的私有属性,代码如下所示:

  1. @interface TRViewController ()
  2. @property (weak, nonatomicIBOutlet UIButton *button1;
  3. @property (weak, nonatomicIBOutlet UIButton *button2;
  4. @property (weak, nonatomicIBOutlet UILabel *label;
  5. @end

在TRViewController类中重写布局方法viewDidLayoutSubviews,在该方法中根据父视图的bounds计算Button和Label的frame,代码如下所示:

  1. (void)viewDidLayoutSubviews
  2. {
  3. [super viewDidLayoutSubviews];
  4. CGFloat buttonWidth (self.view.bounds.size.width 20 20 100.5;
  5. CGRect frame CGRectMake(20, self.button1.frame.origin.y, buttonWidth40);
  6. self.button1.frame = frame;
  7. frame CGRectMake(self.button1.frame.size.width+30, self.button2.frame.origin.y, buttonWidth40);
  8. self.button2.frame = frame;
  9. frame = self.label.frame;
  10. 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);
  11. }

2.4 完整代码

本案例中,TRViewController.m文件中的完整代码如下所示:

  1. #import "TRViewController.h"
  2. @interface TRViewController ()
  3. @property (weak, nonatomicIBOutlet UIButton *button1;
  4. @property (weak, nonatomicIBOutlet UIButton *button2;
  5. @property (weak, nonatomicIBOutlet UILabel *label;
  6. @end
  7. @implementation TRViewController
  8. (void)viewDidLayoutSubviews
  9. {
  10. [super viewDidLayoutSubviews];
  11. CGFloat buttonWidth (self.view.bounds.size.width 20 20 100.5;
  12. CGRect frame CGRectMake(20, self.button1.frame.origin.y, buttonWidth40);
  13. self.button1.frame = frame;
  14. frame CGRectMake(self.button1.frame.size.width+30, self.button2.frame.origin.y, buttonWidth40);
  15. self.button2.frame = frame;
  16. frame = self.label.frame;
  17. 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);
  18. }
  19. @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,该方法的功能是将导航栏隐藏或显示,代码如下所示:

  1. (IBAction)hideNavigationBar
  2. {
  3. self.navigationController.navigationBarHidden !self.navigationController.navigationBarHidden;
  4. }

步骤二:重写布局方法viewDidLayoutSubviews,进行界面布局

在TRViewController类中重写布局方法viewDidLayoutSubviews,在该方法中根据先通过属性self.topLayoutGuide.length和self.bottomLayoutGuide.length获取到上下边栏的高度,然后再通过父视图的bounds和上下边栏的高度计算出Button和Label的frame,代码如下所示:

  1. (void)viewDidLayoutSubviews
  2. {
  3. [super viewDidLayoutSubviews];
  4. CGFloat buttonWidth (self.view.bounds.size.width 20 20 100.5;
  5. //从iOS7开始,可以随时知道VC的上面和下面被各种Bar占据了多少的空间
  6. CGFloat top = self.topLayoutGuide.length;
  7. CGRect frame CGRectMake(20, top+10, buttonWidth40);
  8. self.button1.frame = frame;
  9. frame.origin.x += buttonWidth 10;
  10. self.button2.frame = frame;
  11. //下面的各种Bar(TabBar或ToolBar)占了VC多高的空间
  12. CGFloat bottom = self.bottomLayoutGuide.length;
  13. frame = self.label.frame;
  14. 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);
  15. self.label.frame = frame;
  16. frame = self.hideButton.frame;
  17. frame.origin.x = self.view.bounds.size.width 0.5 - frame.size.width 0.5;
  18. frame.origin.y = self.view.bounds.size.height 0.5 - frame.size.height 0.5;
  19. self.hideButton.frame = frame;
  20. }

3.4 完整代码

本案例中,TRViewController.m文件中的完整代码如下所示:

  1. #import "TRViewController.h"
  2. @interface TRViewController ()
  3. @property (weak, nonatomicIBOutlet UIButton *button1;
  4. @property (weak, nonatomicIBOutlet UIButton *button2;
  5. @property (weak, nonatomicIBOutlet UILabel *label;
  6. @property (weak, nonatomicIBOutlet UIButton *hideButton;
  7. @end
  8. @implementation TRViewController
  9. (IBAction)hideNavigationBar
  10. {
  11. self.navigationController.navigationBarHidden !self.navigationController.navigationBarHidden;
  12. }
  13. (void)viewDidLayoutSubviews
  14. {
  15. [super viewDidLayoutSubviews];
  16. CGFloat buttonWidth (self.view.bounds.size.width 20 20 100.5;
  17. //从iOS7开始,可以随时知道VC的上面和下面被各种Bar占据了多少的空间
  18. CGFloat top = self.topLayoutGuide.length;
  19. CGRect frame CGRectMake(20, top+10, buttonWidth40);
  20. self.button1.frame = frame;
  21. frame.origin.x += buttonWidth 10;
  22. self.button2.frame = frame;
  23. //下面的各种Bar(TabBar或ToolBar)占了VC多高的空间
  24. CGFloat bottom = self.bottomLayoutGuide.length;
  25. frame = self.label.frame;
  26. 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);
  27. self.label.frame = frame;
  28. frame = self.hideButton.frame;
  29. frame.origin.x = self.view.bounds.size.width 0.5 - frame.size.width 0.5;
  30. frame.origin.y = self.view.bounds.size.height 0.5 - frame.size.height 0.5;
  31. self.hideButton.frame = frame;
  32. }
  33. @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,代码如下所示:

  1. @interface TRViewController ()
  2. @property (weak, nonatomicIBOutlet TRView *myView;
  3. @end

最后在TRView类中重写drawRect方法,在屏幕左上方绘制一个三角形,代码如下所示:

  1. (void)drawRect:(CGRect)rect
  2. {
  3. UIBezierPath *path [UIBezierPath bezierPath];
  4. [path moveToPoint:CGPointMake(2020)];
  5. [path addLineToPoint:CGPointMake(20120)];
  6. [path addLineToPoint:CGPointMake(12020)];
  7. [path closePath];
  8. path.lineWidth 4;
  9. [[UIColor redColor] setStroke];
  10. [path stroke];
  11. }

步骤二:进行绘制布局

完成绘制代码,运行程序可见屏幕左上方有一个三角形,但是当切换成横屏时发现三角形失真,如图-13所示:

图-13

解决的办法是,当视图大小发生变化时,进行重新绘制图形,即在布局方法viewDidLayoutSubviews里面调用setNeedDisplay方法即可,代码如下所示:

  1. (void)viewDidLayoutSubviews
  2. {
  3. [super viewDidLayoutSubviews];
  4. [self.myView setNeedsDisplay];
  5. }

但是通常直接将myView的contentMode属性设置为Redraw即可实现绘制布局,相当于调用了上面的代码,将myView的contentMode属性设置为Redraw有两个方法,第一种可以直接通过代码设置,代码如下所示:

  1. (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. self.myView.contentMode = UIViewContentModeRedraw;
  5. }

第二种方法可以直接在Stroyboard中设置,右边栏的检查器四中将Mode选项设置为Redraw即可,如图-14所示:

图-14

将contentMode设置为Redraw之后就不需要再写布局代码,此时切换屏幕绘制图形就不会失真了。

4.4 完整代码

本案例中,TRViewController.m文件中的完整代码如下所示:

  1. #import "TRViewController.h"
  2. #import "TRView.h"
  3. @interface TRViewController ()
  4. @property (weak, nonatomicIBOutlet TRView *myView;
  5. @end
  6. @implementation TRViewController
  7. (void)viewDidLoad
  8. {
  9. [super viewDidLoad];
  10. self.myView.contentMode = UIViewContentModeRedraw;
  11. }
  12. //- (void)viewDidLayoutSubviews
  13. //{
  14. // [super viewDidLayoutSubviews];
  15. // [self.myView setNeedsDisplay];
  16. //}
  17. @end
 

本案例中,TRView.m文件中的完整代码如下所示:

  1. #import "TRView.h"
  2. @implementation TRView
  3. (void)drawRect:(CGRect)rect
  4. {
  5. UIBezierPath *path [UIBezierPath bezierPath];
  6. [path moveToPoint:CGPointMake(2020)];
  7. [path addLineToPoint:CGPointMake(20120)];
  8. [path addLineToPoint:CGPointMake(12020)];
  9. [path closePath];
  10. path.lineWidth 4;
  11. [[UIColor redColor] setStroke];
  12. [path stroke];
  13. }
  14. @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用于存储歌曲数据源,代码如下所示:

  1. @interface TRMusicTableViewController : UITableViewController
  2. @property (strong, nonatomicNSArray *musics;
  3. @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,代码如下所示:

  1. @interface TRMusicCell ()
  2. @property (weak, nonatomicIBOutlet UILabel *musicNameLabel;
  3. @property (weak, nonatomicIBOutlet UILabel *albumAndArtistLabel;
  4. @property (weak, nonatomicIBOutlet UILabel *durationLabel;
  5. @property (weak, nonatomicIBOutlet UIImageView *downloadedImageView;
  6. @property (weak, nonatomicIBOutlet UIImageView *hdImageView;
  7. @end

步骤三:创建TRMusic类和歌曲模拟数据

首先创建一个TRMusic类用于存储歌曲的相关信息,该类继承至NSObject,有五个属性,分别为:

NSString类型的name,用于记录歌曲名称;

NSString类型的album,用于记录歌曲所属专辑;

NSString类型的artist,用于记录歌曲的演唱者;

NSString类型的duration,用于记录歌曲的时长;

BOOL类型的highQuality和downloaded,分别用于记录是否高清和是否本地下载。

代码如下所示:

  1. @interface TRMusic : NSObject
  2. @property (nonatomic, copy) NSString * name;
  3. @property (nonatomic, copy) NSString * album;
  4. @property (nonatomic, copy) NSString * artist;
  5. @property (nonatomicNSTimeInterval duration;
  6. @property (nonatomicBOOL highQuality;
  7. @property (nonatomicBOOL downloaded;
  8. @end

然后再创建一个TRMusicGroup类,该类提供一个静态方法fakeData,用于生成一组模拟的歌曲数据,代码如下所示:

  1. (NSArray *) fakeData
  2. {
  3. NSMutableArray * musics = nil;
  4. TRMusic * music = nil;
  5. musics [NSMutableArray array];
  6. music [[TRMusic alloc] init];
  7. music.name = @"Burn";
  8. music.album = @"Burn - Single";
  9. music.artist = @"Ellie Goulding";
  10. music.duration [self durationWithMinutes:3 andSeconds:51];
  11. music.downloaded = YES;
  12. music.highQuality = NO;
  13. [musics addObject:music];
  14. music [[TRMusic alloc] init];
  15. music.name = @"Summertime Sadness (Cedric Gervais Remix)";
  16. music.album = @"Summertime Sadness (Cedric Gervais Remix) - Single";
  17. music.artist = @"Lana Del Rey";
  18. music.duration [self durationWithMinutes:6 andSeconds:52];
  19. music.downloaded = YES;
  20. music.highQuality = YES;
  21. [musics addObject:music];
  22. music [[TRMusic alloc] init];
  23. music.name = @"Spectrum";
  24. music.album = @"Clarity";
  25. music.artist = @"Zedd";
  26. music.duration [self durationWithMinutes:4 andSeconds:3];
  27. music.downloaded = YES;
  28. music.highQuality = YES;
  29. [musics addObject:music];
  30. music [[TRMusic alloc] init];
  31. music.name = @"It's Time";
  32. music.album = @"It’s Time";
  33. music.artist = @"Imagine Dragons";
  34. music.duration [self durationWithMinutes:4 andSeconds:0];
  35. music.downloaded = NO;
  36. music.highQuality = YES;
  37. [musics addObject:music];
  38. music [[TRMusic alloc] init];
  39. music.name = @"Dancing in The Moonlight";
  40. music.album = @"Dancing In The Moonlight: The Best Of Toploader";
  41. music.artist = @"Toploader";
  42. music.duration [self durationWithMinutes:3 andSeconds:53];
  43. music.downloaded = YES;
  44. music.highQuality = YES;
  45. [musics addObject:music];
  46. music [[TRMusic alloc] init];
  47. music.name = @"Thinking About You (feat. Ayah Marar)";
  48. music.album = @"18 Months (Deluxe Edition)";
  49. music.artist = @"Calvin Harris";
  50. music.duration [self durationWithMinutes:4 andSeconds:8];
  51. music.downloaded = YES;
  52. music.highQuality = YES;
  53. [musics addObject:music];
  54. music [[TRMusic alloc] init];
  55. music.name = @"You Make Me (feat. Salem Al Fakir)";
  56. music.album = @"True";
  57. music.artist = @"Avicii";
  58. music.duration [self durationWithMinutes:3 andSeconds:51];
  59. music.downloaded = YES;
  60. music.highQuality = NO;
  61. [musics addObject:music];
  62. music [[TRMusic alloc] init];
  63. music.name = @"Safe and Sound";
  64. music.album = @"Capital Cities EP";
  65. music.artist = @"Capital Cities";
  66. music.duration [self durationWithMinutes:3 andSeconds:51];
  67. music.downloaded = YES;
  68. music.highQuality = NO;
  69. [musics addObject:music];
  70. music [[TRMusic alloc] init];
  71. music.name = @"Reaching Out";
  72. music.album = @"Welcome Reality (Deluxe Version)";
  73. music.artist = @"nero";
  74. music.duration [self durationWithMinutes:3 andSeconds:51];
  75. music.downloaded = YES;
  76. music.highQuality = NO;
  77. [musics addObject:music];
  78. music [[TRMusic alloc] init];
  79. music.name = @"Recover";
  80. music.album = @"Recover - EP";
  81. music.artist = @"CHVRCHES";
  82. music.duration [self durationWithMinutes:3 andSeconds:51];
  83. music.downloaded = YES;
  84. music.highQuality = NO;
  85. [musics addObject:music];
  86. music [[TRMusic alloc] init];
  87. music.name = @"Hold On, We're Going Home (feat. Majid Jordan)";
  88. music.album = @"Hold On, We're Going Home (feat. Majid Jordan) - Single";
  89. music.artist = @"Drake";
  90. music.duration [self durationWithMinutes:3 andSeconds:51];
  91. music.downloaded = YES;
  92. music.highQuality = NO;
  93. [musics addObject:music];
  94. music [[TRMusic alloc] init];
  95. music.name = @"The Mother We Share";
  96. music.album = @"The Mother We Share - Single";
  97. music.artist = @"CHVRCHES";
  98. music.duration [self durationWithMinutes:3 andSeconds:51];
  99. music.downloaded = YES;
  100. music.highQuality = NO;
  101. [musics addObject:music];
  102. music [[TRMusic alloc] init];
  103. music.name = @"Promises";
  104. music.album = @"nero";
  105. music.artist = @"Promises - EP";
  106. music.duration [self durationWithMinutes:3 andSeconds:51];
  107. music.downloaded = YES;
  108. music.highQuality = NO;
  109. [musics addObject:music];
  110. music [[TRMusic alloc] init];
  111. music.name = @"Alone Together";
  112. music.album = @"Save Rock and Roll";
  113. music.artist = @"Fall Out Boy";
  114. music.duration [self durationWithMinutes:3 andSeconds:51];
  115. music.downloaded = YES;
  116. music.highQuality = NO;
  117. [musics addObject:music];
  118. music [[TRMusic alloc] init];
  119. music.name = @"Reload (Radio Edit)";
  120. music.album = @"Reload (Radio Edit) - Single";
  121. music.artist = @"Sebastian Ingrosso";
  122. music.duration [self durationWithMinutes:3 andSeconds:51];
  123. music.downloaded = YES;
  124. music.highQuality = NO;
  125. [musics addObject:music];
  126. music [[TRMusic alloc] init];
  127. music.name = @"I Love It (feat. Charli XCX)";
  128. music.album = @"Iconic";
  129. music.artist = @"Icona Pop";
  130. music.duration [self durationWithMinutes:3 andSeconds:51];
  131. music.downloaded = YES;
  132. music.highQuality = NO;
  133. [musics addObject:music];
  134. music [[TRMusic alloc] init];
  135. music.name = @"Feel the Love";
  136. music.album = @"Feel the Love (feat. John Newman) [Remixes] - EP";
  137. music.artist = @"Rudimental";
  138. music.duration [self durationWithMinutes:3 andSeconds:51];
  139. music.downloaded = YES;
  140. music.highQuality = NO;
  141. [musics addObject:music];
  142. music [[TRMusic alloc] init];
  143. music.name = @"Goin' Crazy (feat. Robbie Williams)";
  144. music.album = @"Goin' Crazy (feat. Robbie Williams) - Single";
  145. music.artist = @"Dizzee Rascal";
  146. music.duration [self durationWithMinutes:3 andSeconds:51];
  147. music.downloaded = YES;
  148. music.highQuality = NO;
  149. [musics addObject:music];
  150. music [[TRMusic alloc] init];
  151. music.name = @"Still Into You";
  152. music.album = @"Paramore";
  153. music.artist = @"Paramore";
  154. music.duration [self durationWithMinutes:3 andSeconds:51];
  155. music.downloaded = YES;
  156. music.highQuality = NO;
  157. [musics addObject:music];
  158. music [[TRMusic alloc] init];
  159. music.name = @"Heart Attack";
  160. music.album = @"Demi";
  161. music.artist = @"Demi Lovato";
  162. music.duration [self durationWithMinutes:3 andSeconds:51];
  163. music.downloaded = YES;
  164. music.highQuality = NO;
  165. [musics addObject:music];
  166. music [[TRMusic alloc] init];
  167. music.name = @"Explosions";
  168. music.album = @"Halcyon (Deluxe Edition)";
  169. music.artist = @"Ellie Goulding";
  170. music.duration [self durationWithMinutes:3 andSeconds:51];
  171. music.downloaded = YES;
  172. music.highQuality = NO;
  173. [musics addObject:music];
  174. music [[TRMusic alloc] init];
  175. music.name = @"I Need Your Love (feat. Ellie Goulding)";
  176. music.album = @"I Need Your Love";
  177. music.artist = @"Calvin Harris";
  178. music.duration [self durationWithMinutes:3 andSeconds:51];
  179. music.downloaded = YES;
  180. music.highQuality = NO;
  181. [musics addObject:music];
  182. music [[TRMusic alloc] init];
  183. music.name = @"Starry Eyed";
  184. music.album = @"Bright Lights";
  185. music.artist = @"Ellie Goulding";
  186. music.duration [self durationWithMinutes:3 andSeconds:51];
  187. music.downloaded = YES;
  188. music.highQuality = NO;
  189. [musics addObject:music];
  190. music [[TRMusic alloc] init];
  191. music.name = @"Lights (Single Version)";
  192. music.album = @"Bright Lights";
  193. music.artist = @"Ellie Goulding";
  194. music.duration [self durationWithMinutes:3 andSeconds:51];
  195. music.downloaded = YES;
  196. music.highQuality = NO;
  197. [musics addObject:music];
  198. music [[TRMusic alloc] init];
  199. music.name = @"Who's That Chick?";
  200. music.album = @"Who's That Chick - Single";
  201. music.artist = @"David Guetta";
  202. music.duration [self durationWithMinutes:2 andSeconds:47];
  203. music.downloaded = YES;
  204. music.highQuality = NO;
  205. [musics addObject:music];
  206. TRMusicGroup * g1 [[TRMusicGroup alloc] init];
  207. g1.name = @"国外单曲";
  208. g1.musics [musics copy];
  209. g1.state = TRMusicGroupStateDownloaded;
  210. musics [NSMutableArray array];
  211. music [[TRMusic alloc] init];
  212. music.name = @"致青春";
  213. music.album = @"致青春";
  214. music.artist = @"王菲";
  215. music.duration [self durationWithMinutes:3 andSeconds:18];
  216. music.downloaded = NO;
  217. music.highQuality = NO;
  218. [musics addObject:music];
  219. music [[TRMusic alloc] init];
  220. music.name = @"好汉歌";
  221. music.album = @"六十年代生人";
  222. music.artist = @"刘欢";
  223. music.duration [self durationWithMinutes:3 andSeconds:41];
  224. music.downloaded = NO;
  225. music.highQuality = YES;
  226. [musics addObject:music];
  227. music [[TRMusic alloc] init];
  228. music.name = @"忐忑";
  229. music.album = @"自由鸟";
  230. music.artist = @"龚琳娜";
  231. music.duration [self durationWithMinutes:4 andSeconds:03];
  232. music.downloaded = NO;
  233. music.highQuality = YES;
  234. [musics addObject:music];
  235. music [[TRMusic alloc] init];
  236. music.name = @"爱情买卖";
  237. music.album = @"我们的爱我不放手";
  238. music.artist = @"慕容晓晓";
  239. music.duration [self durationWithMinutes:3 andSeconds:31];
  240. music.downloaded = NO;
  241. music.highQuality = YES;
  242. [musics addObject:music];
  243. music [[TRMusic alloc] init];
  244. music.name = @"法海你不懂爱";
  245. music.album = @"法海你不懂爱 - 单曲";
  246. music.artist = @"龚琳娜";
  247. music.duration [self durationWithMinutes:3 andSeconds:33];
  248. music.downloaded = NO;
  249. music.highQuality = NO;
  250. [musics addObject:music];
  251. music [[TRMusic alloc] init];
  252. music.name = @"最炫民族风";
  253. music.album = @"我们的爱我不放手";
  254. music.artist = @"凤凰传奇";
  255. music.duration [self durationWithMinutes:4 andSeconds:46];
  256. music.downloaded = NO;
  257. music.highQuality = YES;
  258. [musics addObject:music];
  259. music [[TRMusic alloc] init];
  260. music.name = @"金箍棒";
  261. music.album = @"金箍棒 - 单曲";
  262. music.artist = @"龚琳娜";
  263. music.duration [self durationWithMinutes:2 andSeconds:52];
  264. music.downloaded = NO;
  265. music.highQuality = NO;
  266. [musics addObject:music];
  267. TRMusicGroup * g2 [[TRMusicGroup alloc] init];
  268. g2.name = @"国内神曲";
  269. g2.musics [musics copy];
  270. g2.state = TRMusicGroupStateNormal;
  271. TRMusicGroup * g3 [[TRMusicGroup alloc] init];
  272. g3.name = @"Calvin Harris 专辑";
  273. g3.musics = @[];
  274. g3.state = TRMusicGroupStateNormal;
  275. TRMusicGroup * g4 [[TRMusicGroup alloc] init];
  276. g4.name = @"Ellie Gounding 专辑";
  277. g4.musics = @[];
  278. g4.state = TRMusicGroupStateNormal;
  279. return @[g1, g2, g3, g4];
  280. }

步骤四:进行自定义cell布局

首先在TRMusicTableViewController类注册Cell,并在TRAppDelegate中对属性musics进行初始化,获取到模拟的歌曲数据,代码如下所示:

  1. //在TRAppDelegate中进行musics属性的初始化
  2. -(BOOL)application:(UIApplication *)application 
  3. didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  4. {
  5. NSArray *musicGroups [TRMusicGroup fakeData];
  6. TRMusicGroup *group = musicGroups[0];
  7. UINavigationController *navi (UINavigationController *)self.window.rootViewController;
  8. TRMusicTableViewController *musicTVC (TRMusicTableViewController *) navi.topViewController;
  9. musicTVC.musics = group.musics;
  10. return YES;
  11. }
  12. //在TRMusicsTableViewController中注册cell
  13. (void)viewDidLoad
  14. {
  15. [super viewDidLoad];
  16. [self.tableView registerNib:[UINib nibWithNibName: @"TRMusicCell" bundle:nil] forCellReuseIdentifier:musicCellIdentifier];
  17. }

然后在TRMusicCell类中定义一个TRMusic类型属性music,用于存储单元格需要展示的歌曲,代码如下所示:

  1. //TRMusicCell.h文件中定义属性music
  2. @interface TRMusicCell : UITableViewCell
  3. @property (strong, nonatomicTRMusic *music;
  4. @end

在TRMusicCell重写layoutSubviews方法,进行cell的界面布局,该方法中会根据每首歌曲的信息,计算子视图的frame进行布局,代码如下所示:

  1. (void)layoutSubviews
  2. {
  3. [super layoutSubviews];
  4. CGFloat x = self.downloadedImageView.frame.origin.x;
  5. if (self.music.downloaded){
  6. += 20;
  7. }
  8. if (self.music.highQuality{
  9. CGRect frame = self.hdImageView.frame;
  10. frame.origin.x = x;
  11. self.hdImageView.frame = frame;
  12. += 20;
  13. }
  14. CGRect frame = self.albumAndArtistLabel.frame;
  15. frame.origin.x = x;
  16. self.albumAndArtistLabel.frame = frame;
  17. }

歌曲的高清和下载图标需要根据歌曲的相关信息进行显示,可以将此部分功能通过重写music的setter方法来实现,代码如下所示:

  1. //TRMusicCell.m文件候中重写music的setter方法
  2. (void)setMusic:(TRMusic *)music
  3. {
  4. _music = music;
  5. self.musicNameLabel.text = music.name;
  6. self.albumAndArtistLabel.text [NSString stringWithFormat:@"%@ - %@", music.album, music.artist];
  7. self.durationLabel.text [NSString stringWithFormat:@"%d:%02d"(int)music.duration/60(int)music.duration%60];
  8. self.downloadedImageView.hidden !music.downloaded;
  9. self.hdImageView.hidden !music.highQuality;
  10. //根据是否高清或下载状态,需要重新布局
  11. [self setNeedsLayout]; 
  12. }

最后在TRMusicsTableViewController类中回答三问给表视图加载歌曲数据,并将单元格的行高设置为50,代码如下所示:

  1. -(NSInteger)tableView:(UITableView *)tableView 
  2. numberOfRowsInSection:(NSInteger)section
  3. {
  4. return self.musics.count;
  5. }
  6. -(UITableViewCell *)tableView:(UITableView *)tableView 
  7. cellForRowAtIndexPath:(NSIndexPath *)indexPath
  8. {
  9. TRMusicCell *cell [tableView dequeueReusableCellWithIdentifier:musicCellIdentifier forIndexPath:indexPath];
  10. cell.music = self.musics[indexPath.row];
  11. return cell;
  12. }
  13. -(CGFloat)tableView:(UITableView *)tableView 
  14. heightForRowAtIndexPath:(NSIndexPath *)indexPath
  15. {
  16. return 50;
  17. }

5.4 完整代码

本案例中,TRAppDelegate.m文件中的完整代码如下所示:

  1. #import "TRAppDelegate.h"
  2. #import "TRMusicGroup.h"
  3. #import "TRMusicTableViewController.h"
  4. @implementation TRAppDelegate
  5. -(BOOL)application:(UIApplication *)application 
  6. didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  7. {
  8. NSArray *musicGroups [TRMusicGroup fakeData];
  9. TRMusicGroup *group = musicGroups[0];
  10. UINavigationController *navi (UINavigationController *)self.window.rootViewController;
  11. TRMusicTableViewController *musicTVC (TRMusicTableViewController *) navi.topViewController;
  12. musicTVC.musics = group.musics;
  13. return YES;
  14. }
  15. @end
 

本案例中,TRMusicTableViewController.h文件中的完整代码如下所示:

  1. #import <UIKit/UIKit.h>
  2. @interface TRMusicTableViewController : UITableViewController
  3. @property (strong, nonatomicNSArray *musics;
  4. @end
 

本案例中,TRMusicCell.h文件中的完整代码如下所示:

  1. #import <UIKit/UIKit.h>
  2. #import "TRMusic.h"
  3. @interface TRMusicCell : UITableViewCell
  4. @property (strong, nonatomicTRMusic *music;
  5. @end
 

本案例中,TRMusicCell.m文件中的完整代码如下所示:

  1. #import "TRMusicCell.h
  2. @interface TRMusicCell ()
  3. @property (weak, nonatomic) IBOutlet UILabel *musicNameLabel;
  4. @property (weak, nonatomic) IBOutlet UILabel *albumAndArtistLabel;
  5. @property (weak, nonatomic) IBOutlet UILabel *durationLabel;
  6. @property (weak, nonatomic) IBOutlet UIImageView *downloadedImageView;
  7. @property (weak, nonatomic) IBOutlet UIImageView *hdImageView;
  8. @end
  9. @implementation TRMusicCell
  10. - (void)setMusic:(TRMusic *)music
  11. {
  12. _music = music;
  13. self.musicNameLabel.text = music.name;
  14. self.albumAndArtistLabel.text = [NSString stringWithFormat:@"%@ %@", music.album, music.artist];
  15. self.durationLabel.text = [NSString stringWithFormat:@"%d:%02d", (int)music.duration/60, (int)music.duration%60];
  16. self.downloadedImageView.hidden = !music.downloaded;
  17. self.hdImageView.hidden = !music.highQuality;
  18. [self setNeedsLayout];//需要重新布局
  19. }
  20. //当当前视图的大小发生变化时调用
  21. - (void)layoutSubviews
  22. {
  23. [super layoutSubviews];
  24. CGFloat x = self.downloadedImageView.frame.origin.x;
  25. if (self.music.downloaded){
  26. x += 20;
  27. }
  28. if (self.music.highQuality) {
  29. CGRect frame = self.hdImageView.frame;
  30. frame.origin.x = x;
  31. self.hdImageView.frame = frame;
  32. x += 20;
  33. }
  34. CGRect frame = self.albumAndArtistLabel.frame;
  35. frame.origin.x = x;
  36. self.albumAndArtistLabel.frame = frame;
  37. }
  38. @end
 

本案例中,TRMusic.h文件中的完整代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. @interface TRMusic : NSObject
  3. @property (nonatomic, copy) NSString * name;
  4. @property (nonatomic, copy) NSString * album;
  5. @property (nonatomic, copy) NSString * artist;
  6. @property (nonatomicNSTimeInterval duration;
  7. @property (nonatomicBOOL highQuality;
  8. @property (nonatomicBOOL downloaded;
  9. @end
隐藏

本案例中,TRMusicGroup.h文件中的完整代码如下所示:

  1. #import <Foundation/Foundation.h>
  2. #import "TRMusic.h"
  3. typedef NS_ENUM(NSInteger, TRMusicGroupState{
  4. TRMusicGroupStateNormal,    
  5. TRMusicGroupStateDownloading,        
  6. TRMusicGroupStateDownloaded
  7. };
  8. @interface TRMusicGroup : NSObject
  9. @property (nonatomic, copy) NSString * name;
  10. @property (nonatomic, strong) NSArray * musics;
  11. @property (nonatomicTRMusicGroupState state;
  12. (NSArray *) fakeData;
  13. @end
 

本案例中,TRMusicGroup.m文件中的完整代码如下所示:

  1. #import "TRMusicGroup.h"
  2. @implementation TRMusicGroup
  3. (NSArray *) fakeData
  4. {
  5. NSMutableArray * musics = nil;
  6. TRMusic * music = nil;
  7. musics [NSMutableArray array];
  8. music [[TRMusic alloc] init];
  9. music.name = @"Burn";
  10. music.album = @"Burn - Single";
  11. music.artist = @"Ellie Goulding";
  12. music.duration [self durationWithMinutes:3 andSeconds:51];
  13. music.downloaded = YES;
  14. music.highQuality = NO;
  15. [musics addObject:music];
  16. music [[TRMusic alloc] init];
  17. music.name = @"Summertime Sadness (Cedric Gervais Remix)";
  18. music.album = @"Summertime Sadness (Cedric Gervais Remix) - Single";
  19. music.artist = @"Lana Del Rey";
  20. music.duration [self durationWithMinutes:6 andSeconds:52];
  21. music.downloaded = YES;
  22. music.highQuality = YES;
  23. [musics addObject:music];
  24. music [[TRMusic alloc] init];
  25. music.name = @"Spectrum";
  26. music.album = @"Clarity";
  27. music.artist = @"Zedd";
  28. music.duration [self durationWithMinutes:4 andSeconds:3];
  29. music.downloaded = YES;
  30. music.highQuality = YES;
  31. [musics addObject:music];
  32. music [[TRMusic alloc] init];
  33. music.name = @"It's Time";
  34. music.album = @"It’s Time";
  35. music.artist = @"Imagine Dragons";
  36. music.duration [self durationWithMinutes:4 andSeconds:0];
  37. music.downloaded = NO;
  38. music.highQuality = YES;
  39. [musics addObject:music];
  40. music [[TRMusic alloc] init];
  41. music.name = @"Dancing in The Moonlight";
  42. music.album = @"Dancing In The Moonlight: The Best Of Toploader";
  43. music.artist = @"Toploader";
  44. music.duration [self durationWithMinutes:3 andSeconds:53];
  45. music.downloaded = YES;
  46. music.highQuality = YES;
  47. [musics addObject:music];
  48. music [[TRMusic alloc] init];
  49. music.name = @"Thinking About You (feat. Ayah Marar)";
  50. music.album = @"18 Months (Deluxe Edition)";
  51. music.artist = @"Calvin Harris";
  52. music.duration [self durationWithMinutes:4 andSeconds:8];
  53. music.downloaded = YES;
  54. music.highQuality = YES;
  55. [musics addObject:music];
  56. music [[TRMusic alloc] init];
  57. music.name = @"You Make Me (feat. Salem Al Fakir)";
  58. music.album = @"True";
  59. music.artist = @"Avicii";
  60. music.duration [self durationWithMinutes:3 andSeconds:51];
  61. music.downloaded = YES;
  62. music.highQuality = NO;
  63. [musics addObject:music];
  64. music [[TRMusic alloc] init];
  65. music.name = @"Safe and Sound";
  66. music.album = @"Capital Cities EP";
  67. music.artist = @"Capital Cities";
  68. music.duration [self durationWithMinutes:3 andSeconds:51];
  69. music.downloaded = YES;
  70. music.highQuality = NO;
  71. [musics addObject:music];
  72. music [[TRMusic alloc] init];
  73. music.name = @"Reaching Out";
  74. music.album = @"Welcome Reality (Deluxe Version)";
  75. music.artist = @"nero";
  76. music.duration [self durationWithMinutes:3 andSeconds:51];
  77. music.downloaded = YES;
  78. music.highQuality = NO;
  79. [musics addObject:music];
  80. music [[TRMusic alloc] init];
  81. music.name = @"Recover";
  82. music.album = @"Recover - EP";
  83. music.artist = @"CHVRCHES";
  84. music.duration [self durationWithMinutes:3 andSeconds:51];
  85. music.downloaded = YES;
  86. music.highQuality = NO;
  87. [musics addObject:music];
  88. music [[TRMusic alloc] init];
  89. music.name = @"Hold On, We're Going Home (feat. Majid Jordan)";
  90. music.album = @"Hold On, We're Going Home (feat. Majid Jordan) - Single";
  91. music.artist = @"Drake";
  92. music.duration [self durationWithMinutes:3 andSeconds:51];
  93. music.downloaded = YES;
  94. music.highQuality = NO;
  95. [musics addObject:music];
  96. music [[TRMusic alloc] init];
  97. music.name = @"The Mother We Share";
  98. music.album = @"The Mother We Share - Single";
  99. music.artist = @"CHVRCHES";
  100. music.duration [self durationWithMinutes:3 andSeconds:51];
  101. music.downloaded = YES;
  102. music.highQuality = NO;
  103. [musics addObject:music];
  104. music [[TRMusic alloc] init];
  105. music.name = @"Promises";
  106. music.album = @"nero";
  107. music.artist = @"Promises - EP";
  108. music.duration [self durationWithMinutes:3 andSeconds:51];
  109. music.downloaded = YES;
  110. music.highQuality = NO;
  111. [musics addObject:music];
  112. music [[TRMusic alloc] init];
  113. music.name = @"Alone Together";
  114. music.album = @"Save Rock and Roll";
  115. music.artist = @"Fall Out Boy";
  116. music.duration [self durationWithMinutes:3 andSeconds:51];
  117. music.downloaded = YES;
  118. music.highQuality = NO;
  119. [musics addObject:music];
  120. music [[TRMusic alloc] init];
  121. music.name = @"Reload (Radio Edit)";
  122. music.album = @"Reload (Radio Edit) - Single";
  123. music.artist = @"Sebastian Ingrosso";
  124. music.duration [self durationWithMinutes:3 andSeconds:51];
  125. music.downloaded = YES;
  126. music.highQuality = NO;
  127. [musics addObject:music];
  128. music [[TRMusic alloc] init];
  129. music.name = @"I Love It (feat. Charli XCX)";
  130. music.album = @"Iconic";
  131. music.artist = @"Icona Pop";
  132. music.duration [self durationWithMinutes:3 andSeconds:51];
  133. music.downloaded = YES;
  134. music.highQuality = NO;
  135. [musics addObject:music];
  136. music [[TRMusic alloc] init];
  137. music.name = @"Feel the Love";
  138. music.album = @"Feel the Love (feat. John Newman) [Remixes] - EP";
  139. music.artist = @"Rudimental";
  140. music.duration [self durationWithMinutes:3 andSeconds:51];
  141. music.downloaded = YES;
  142. music.highQuality = NO;
  143. [musics addObject:music];
  144. music [[TRMusic alloc] init];
  145. music.name = @"Goin' Crazy (feat. Robbie Williams)";
  146. music.album = @"Goin' Crazy (feat. Robbie Williams) - Single";
  147. music.artist = @"Dizzee Rascal";
  148. music.duration [self durationWithMinutes:3 andSeconds:51];
  149. music.downloaded = YES;
  150. music.highQuality = NO;
  151. [musics addObject:music];
  152. music [[TRMusic alloc] init];
  153. music.name = @"Still Into You";
  154. music.album = @"Paramore";
  155. music.artist = @"Paramore";
  156. music.duration [self durationWithMinutes:3 andSeconds:51];
  157. music.downloaded = YES;
  158. music.highQuality = NO;
  159. [musics addObject:music];
  160. music [[TRMusic alloc] init];
  161. music.name = @"Heart Attack";
  162. music.album = @"Demi";
  163. music.artist = @"Demi Lovato";
  164. music.duration [self durationWithMinutes:3 andSeconds:51];
  165. music.downloaded = YES;
  166. music.highQuality = NO;
  167. [musics addObject:music];
  168. music [[TRMusic alloc] init];
  169. music.name = @"Explosions";
  170. music.album = @"Halcyon (Deluxe Edition)";
  171. music.artist = @"Ellie Goulding";
  172. music.duration [self durationWithMinutes:3 andSeconds:51];
  173. music.downloaded = YES;
  174. music.highQuality = NO;
  175. [musics addObject:music];
  176. music [[TRMusic alloc] init];
  177. music.name = @"I Need Your Love (feat. Ellie Goulding)";
  178. music.album = @"I Need Your Love";
  179. music.artist = @"Calvin Harris";
  180. music.duration [self durationWithMinutes:3 andSeconds:51];
  181. music.downloaded = YES;
  182. music.highQuality = NO;
  183. [musics addObject:music];
  184. music [[TRMusic alloc] init];
  185. music.name = @"Starry Eyed";
  186. music.album = @"Bright Lights";
  187. music.artist = @"Ellie Goulding";
  188. music.duration [self durationWithMinutes:3 andSeconds:51];
  189. music.downloaded = YES;
  190. music.highQuality = NO;
  191. [musics addObject:music];
  192. music [[TRMusic alloc] init];
  193. music.name = @"Lights (Single Version)";
  194. music.album = @"Bright Lights";
  195. music.artist = @"Ellie Goulding";
  196. music.duration [self durationWithMinutes:3 andSeconds:51];
  197. music.downloaded = YES;
  198. music.highQuality = NO;
  199. [musics addObject:music];
  200. music [[TRMusic alloc] init];
  201. music.name = @"Who's That Chick?";
  202. music.album = @"Who's That Chick - Single";
  203. music.artist = @"David Guetta";
  204. music.duration [self durationWithMinutes:2 andSeconds:47];
  205. music.downloaded = YES;
  206. music.highQuality = NO;
  207. [musics addObject:music];
  208. TRMusicGroup * g1 [[TRMusicGroup alloc] init];
  209. g1.name = @"国外单曲";
  210. g1.musics [musics copy];
  211. g1.state = TRMusicGroupStateDownloaded;
  212. musics [NSMutableArray array];
  213. music [[TRMusic alloc] init];
  214. music.name = @"致青春";
  215. music.album = @"致青春";
  216. music.artist = @"王菲";
  217. music.duration [self durationWithMinutes:3 andSeconds:18];
  218. music.downloaded = NO;
  219. music.highQuality = NO;
  220. [musics addObject:music];
  221. music [[TRMusic alloc] init];
  222. music.name = @"好汉歌";
  223. music.album = @"六十年代生人";
  224. music.artist = @"刘欢";
  225. music.duration [self durationWithMinutes:3 andSeconds:41];
  226. music.downloaded = NO;
  227. music.highQuality = YES;
  228. [musics addObject:music];
  229. music [[TRMusic alloc] init];
  230. music.name = @"忐忑";
  231. music.album = @"自由鸟";
  232. music.artist = @"龚琳娜";
  233. music.duration [self durationWithMinutes:4 andSeconds:03];
  234. music.downloaded = NO;
  235. music.highQuality = YES;
  236. [musics addObject:music];
  237. music [[TRMusic alloc] init];
  238. music.name = @"爱情买卖";
  239. music.album = @"我们的爱我不放手";
  240. music.artist = @"慕容晓晓";
  241. music.duration [self durationWithMinutes:3 andSeconds:31];
  242. music.downloaded = NO;
  243. music.highQuality = YES;
  244. [musics addObject:music];
  245. music [[TRMusic alloc] init];
  246. music.name = @"法海你不懂爱";
  247. music.album = @"法海你不懂爱 - 单曲";
  248. music.artist = @"龚琳娜";
  249. music.duration [self durationWithMinutes:3 andSeconds:33];
  250. music.downloaded = NO;
  251. music.highQuality = NO;
  252. [musics addObject:music];
  253. music [[TRMusic alloc] init];
  254. music.name = @"最炫民族风";
  255. music.album = @"我们的爱我不放手";
  256. music.artist = @"凤凰传奇";
  257. music.duration [self durationWithMinutes:4 andSeconds:46];
  258. music.downloaded = NO;
  259. music.highQuality = YES;
  260. [musics addObject:music];
  261. music [[TRMusic alloc] init];
  262. music.name = @"金箍棒";
  263. music.album = @"金箍棒 - 单曲";
  264. music.artist = @"龚琳娜";
  265. music.duration [self durationWithMinutes:2 andSeconds:52];
  266. music.downloaded = NO;
  267. music.highQuality = NO;
  268. [musics addObject:music];
  269. TRMusicGroup * g2 [[TRMusicGroup alloc] init];
  270. g2.name = @"国内神曲";
  271. g2.musics [musics copy];
  272. g2.state = TRMusicGroupStateNormal;
  273. TRMusicGroup * g3 [[TRMusicGroup alloc] init];
  274. g3.name = @"Calvin Harris 专辑";
  275. g3.musics = @[];
  276. g3.state = TRMusicGroupStateNormal;
  277. TRMusicGroup * g4 [[TRMusicGroup alloc] init];
  278. g4.name = @"Ellie Gounding 专辑";
  279. g4.musics = @[];
  280. g4.state = TRMusicGroupStateNormal;
  281. return @[g1, g2, g3, g4];
  282. }
  283. (NSTimeInterval) durationWithMinutes:(int)minutes andSeconds:(int)seconds
  284. {
  285. return minutes 60 + seconds;
  286. }
  287. @end

转载于:https://www.cnblogs.com/hytx/p/5049478.html

相关文章:

fail-fast和fail-safe的介绍和区别

2019独角兽企业重金招聘Python工程师标准>>> fail-fast和fail-safe 前言 前段时间公司招的实习生在使用迭代器遍历的时候,对集合内容进行了修改,从而抛出ConcurrentModificationException. 然后给他讲解之余也整理了这一篇文章. fail-fast ( 快速失败 ) 在使用迭代器…

hdu 4311 Meeting point-1

http://acm.hdu.edu.cn/showproblem.php?pid4311 思维呀 亲 你想到就可以做出来 想不到就做不出了 什么都不说了 上代码 不知道为什么 在hdu 上 long long 和 int 相乘就让我错 #include<iostream> #include<cstdio> #include<algorithm> #include<c…

Spring Boot 整合Pagehelper(为什么PageHelper分页不生效)

引入包https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter/1.2.10 <!--分页--><!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter --><dependency><groupId>com…

关于javascript的keycode

javascript event对象的具体功能是 event对象只在事件发生的过程中才有效&#xff08;比如鼠标点击&#xff0c;键盘按下等&#xff09;。event对象用以表示事件的状态&#xff0c;例如触发event对象的元素&#xff08;event.srcElement&#xff09;、鼠标的位置&#xff08;ev…

SQL-54 查找排除当前最大、最小salary之后的员工的平均工资avg_salary。

题目描述 查找排除当前最大、最小salary之后的员工的平均工资avg_salary。CREATE TABLE salaries ( emp_no int(11) NOT NULL,salary int(11) NOT NULL,from_date date NOT NULL,to_date date NOT NULL,PRIMARY KEY (emp_no,from_date));输出格式:avg_salary69462.5555555556SQ…

JqGridView 1.0.0.0发布

前几个月&#xff0c;客户要求显示列表做到列锁定表头锁定列组合,但从Extjs到Jquery EasyUi&#xff0c;从Jquery Grid到Telerik等等组件&#xff0c;发现无一符合条件&#xff0c;要么只能用列锁定&#xff0c;要么只能用列组合&#xff0c;当两者结合就不行了。于是只好开始自…

Struts2--ActionContext及CleanUP Filter

1. ActionContext ActionContext是被存放在当前线程中的&#xff0c;获取ActionContext也是从ThreadLocal中获取的。所以在执行拦截器、 action和result的过程中&#xff0c;由于他们都是在一个线程中按照顺序执行的&#xff0c;所以可以可以在任意时候在ThreadLocal中获取 Act…

HTML5跳转页面并传值以及localStorage的用法

1、首先&#xff0c;你得在那个页面把数据存入localStorage中吧。这个是必须的&#xff01; localStorage.setItem("user",JSON.stringify(data.allUser)); 用localStorage的setItem方法&#xff0c;这个方法看名字都知道得差不多了吧。。。setItem把数据存入localSt…

冒泡排序_python实现冒泡排序

冒泡排序是比较经典的面试题&#xff0c; 它重复地走访过要排序的元素列&#xff0c;依次比较两个相邻的元素&#xff0c;如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换&#xff0c;也就是说该元素列已经…

30分钟内让你明白正则表达式是什么,并对它有一些基本的了解(二)

测试正则表达式 如果你不觉得正则表达式很难读写的话&#xff0c;要么你是一个搞笑的天才&#xff0c;要么&#xff0c;你不是地球人。正则表达式的语法很令人头疼&#xff0c;即使对经常使用它的人来说也是如此。由于难于读写&#xff0c;容易出错&#xff0c;所以找一种工具对…

(区间dp 或 记忆化搜素 )Brackets -- POJ -- 2955

http://poj.org/problem?id2955 Description We give the following inductive definition of a “regular brackets” sequence: the empty sequence is a regular brackets sequence,if s is a regular brackets sequence, then (s) and [s] are regular brackets sequences…

[初级]深入理解乐观锁与悲观锁

2019独角兽企业重金招聘Python工程师标准>>> 在数据库的锁机制中介绍过&#xff0c;数据库管理系统&#xff08;DBMS&#xff09;中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。 乐观并发控制(乐观锁…

Umbra 3:次世代的遮挡裁剪

原文链接&#xff1a;http://www.gamasutra.com/view/feature/164660/sponsored_feature_next_generation_.php?print1 来自 Umbra Software [在这个主办方特辑中&#xff0c;Umbra Software讨论了当前使用的大量裁剪遮挡方法的优缺点&#xff0c;并解释了它自己的自动化遮挡…

在64位机上PLSQL连oracle11g问题:SQL*Net not properly installed和ORA-12154:TNS:无法处理服务名...

今天有同事在给客户安装我们的系统时&#xff0c;出现了问题。 背景&#xff1a;同事安装如下&#xff1a; 服务器是小机&#xff0c;在小机上做的虚拟机。WIN&#xff12;&#xff10;&#xff10;&#xff13;操作系统&#xff0c;装的是&#xff16;&#xff14;位的。 数据…

ios 应用和电脑共享文件夹_堪比AirDrop,苹果 iPhone与Windows电脑互传文件的三种方式...

如果你是苹果全家桶用户&#xff0c;一定会对 「AirDrop(隔空投送)」 功能赞誉有加&#xff0c;使用 AirDrop 可以在 iPhone 与 MacBook、iPad 等设备之间快速传递照片、视频或文件。遗憾的是&#xff0c;「AirDrop 仅限苹果设备之间使用」&#xff0c;而很多小伙伴应该和小兽一…

Swift----函数 、 闭包 、 枚举 、 类和结构体 、 属性

1 数组排序 1.1 问题 本案例实现一个整型数组排序的函数&#xff0c;数组排序的规则由传递的规则函数决定。 1.2 方案 首先定义一个整型数组排序函数sortInts&#xff0c;该函数有一个整型数组类型的参数&#xff0c;该参数必须是输入输出参数inout&#xff0c;否则并不能修改数…

shell命令之---Linux文件权限

本章内容  理解Linux的安全性 解读文件权限 使用Linux组 1、Linux的安全性---/etc/passwd文件 # cat /etc/passwdroot:x:0:0:root:/root:/bin/bash/etc/passwd文件的字段包含了如下信息&#xff1a; 登录用户名 用户密码 用户账户的UID&#xff08;数字形式&#x…

失败原因_解析干洗店失败原因

在市面上我们其实也知道有的店面开张时间不长或者最终没有存活下来&#xff0c;干洗店也不例外。我们在看到各地干洗店的高额利润的同时&#xff0c;也会发现一些失败的干洗店。他们的干洗店为何难以运营下去呢?下面伊斯曼小编来在多个方面剖析一下其中的蹊跷和缘由&#xff1…

seg:NLP之正向最大匹配分词

已迁移到我新博客,阅读体验更佳seg:NLP之正向最大匹配分词 完整代码实现放在我的github上:click me 一、任务要求 实现一个基于词典与规则的汉语自动分词系统。二、技术路线 采用正向最大匹配(FMM)方法对输入的中文语句进行分词&#xff0c;具体的实现可以分为下面几个步骤&…

喷涂机器人保养应该注意的七个事项

喷涂机器人又叫喷漆机器人(spray painting robot)&#xff0c; 是可进行自动喷漆或喷涂其他涂料的工业机器人。目前市面上采用比较多的品牌有ABB、库卡、发那科等等&#xff0c;长时间的使用能加速工业机器人的老化&#xff0c;保养是延缓机器人老化的一大关键&#xff0c;那么…

K均值与C均值区别

k均值聚类&#xff1a;---------一种硬聚类算法&#xff0c;隶属度只有两个取值0或1&#xff0c;提出的基本根据是“类内误差平方和最小化”准则&#xff1b;  模糊的c均值聚类算法&#xff1a;-------- 一种模糊聚类算法&#xff0c;是k均值聚类算法的推广形式&#xff0c;隶…

中超赛程来100wan点in_不干了:中超球队改名“硬重启”,球迷组织绝望解散

聚焦中超和CBA&#xff0c;独一无二球迷媒体点击右上角关注&#xff0c;你不会后悔的...2021赛季中超注定会与众不同&#xff0c;足协的新规将陆续实施&#xff0c;如果降薪还在外界意料之中的话&#xff0c;那么更改中性化名字的要求则让多数俱乐部较为头疼&#xff0c;尤其是…

微博polg什么意思_贾磊:广东发微博给CBA造成了负面影响 方硕的意思可能没表达清楚...

直播吧11月5日讯 近日做客一档节目时&#xff0c;著名篮球记者贾磊谈到了前天晚上的京粤大战。贾磊谈到了王骁辉伸腿绊倒威姆斯一事&#xff1a;“我觉得这场比赛&#xff0c;王骁辉的这个动作&#xff0c;大家都看的非常清楚&#xff0c;确实是一个犯规&#xff0c;也给威姆斯…

iOS 中的网络请求 (同步请求、异步请求、GET请求、POST请求)

1、同步请求可以从因特网请求数据&#xff0c;一旦发送同步请求&#xff0c;程序将停止用户交互&#xff0c;直至服务器返回数据完成&#xff0c;才可以进行下一步操作&#xff0c; 2、异步请求不会阻塞主线程&#xff0c;而会建立一个新的线程来操作&#xff0c;用户发出异步请…

springboot 头像上传 文件流保存 文件流返回浏览器查看 区分操作系统 windows 7 or linux...

1 //我的会员中心 头像上传接口2 /*windows 调试*/3 Value("${appImg.location}")4 private String winPathPic;5 /*linux 使用*/6 Value("${img.location}")7 private String linuxPathPic;8 9 PostMapping(value "/file")10 public String f…

个人所得税计算器2016 by Jacksile

个人所得税计算器2016 个人所得税计算器2016 税前薪资&#xff1a;元各项社会保险费&#xff1a;元起征点&#xff1a;35004800元应缴税款&#xff1a;元实发薪资&#xff1a;元个人所得税计算公式 应纳税额 应纳税所得额 x 税率 &#xff0d; 速算扣除数 应纳税所得额 工资收…

interface IEngineControl封装引擎通用操作

using System; using System.Collections.Generic; using System.Text; using System.Linq; namespace SIAT {namespace Engine{/******************************************************************** 引擎控制接口&#xff0c;该类封装一些引擎中通用的操作* * ***********…

iOS 导航栏遮挡问题 --- iOS开发系列 ---项目中成长的知识七

不知大家有没有遇见过自己写的tableview被导航栏遮挡住的问题,反正我是遇见过! 因为在ios7以后所有的UIViewController创建后默认就是full Screen的&#xff0c;因此如果带导航栏的应用界面中的部分控件会被导航栏覆盖掉。 解决方案&#xff1a;可以使用ios7中的UIViewControll…

程序员笔记|如何编写优雅的Dockerfile

导读 Kubernetes要从容器化开始&#xff0c;而容器又需要从Dockerfile开始&#xff0c;本文将介绍如何写出一个优雅的Dockerfile文件。 文章主要内容包括&#xff1a; Docker容器 Dockerfile 使用多阶构建感谢公司提供大量机器资源及时间让我们可以实践&#xff0c;感谢在此专…

Oracle面试问题汇总

1:SqL 优化 1&#xff1a;尽量避免使用 select * 查询方式 因为oracle 在解析过程中 会将*依次转化成所以的列名。 2&#xff1a;减小访问数据库的次数 因为每执行一条sql语句的时候&#xff0c;oracle内部会做许多的事情 如&#xff1a;解析sql &#xff0c;估算索引的利用效率…