触控(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
轉載于:https://www.cnblogs.com/hytx/p/5049478.html
總結
以上是生活随笔為你收集整理的触控(Touch) 、 布局(Layout)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 圣诞老人加8是什么歌呢
- 下一篇: (区间dp 或 记忆化搜素 )Brack