07_UI基礎_UITableView實戰- 支付寶口碑

来源:http://www.cnblogs.com/ljx-xinge/archive/2017/05/11/07UI-ji-chuUITableView-shi-zhan-zhi-fu-bao-kou-bei.html
-Advertisement-
Play Games

此篇為針對ios中的UI基礎知識,為了能讓大家更清楚的理解,此整理中編寫了採用知識點+案例的方式,配有非常詳細的截圖和代碼註釋,添加了許多大白話進行解釋,如有錯誤之處,望指正,願與您相互交流學習,共同進步!---"會飛的猴子_阿新"本篇案例修改圖為(後面會逐步優化細節問題)主要內容從支付寶案例開始,... ...


此篇為針對ios中的UI基礎知識,為了能讓大家更清楚的理解,此整理中編寫了採用知識點+案例的方式,配有非常詳細的截圖和代碼註釋,添加了許多大白話進行解釋,如有錯誤之處,望指正,願與您相互交流學習,共同進步!---"會飛的猴子_阿新"

本篇案例修改圖為(後面會逐步優化細節問題)

主要內容從支付寶案例開始,重點在後面哦!

使用UITableViewControler控制器實現支付寶口碑案例
UITableViewControler 缺陷: 現階段只適合全屏的..

01-UITableViewController體驗

  • 相當於一個控制器自帶tableView
  • viewController管理的是view
  • tableViewController管理的是tableView
  • 也就是在tableViewController下,self.view = self.tableView

02-tableView的HeaderView和FooterView

  • tableView的header - (x, y, width) 可以隨便指定,(height) 實際數值
  • tableView的footer - (y, width) 可以隨便指定,(x, height) 實際數值

創建一個demo體驗一下:
1.準備:新建文件-->把預設的的viewController刪掉-->新建LJXTableViewController-->把Main.storyboard中預設的控制器刪掉-->重寫拖拽一個UITableViewController-->指定初始箭頭,指定class.
2.添加頭部視圖

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIView *headerView = [[UIView alloc]init];
    headerView.backgroundColor =[UIColor redColor];
    //把某個控制項設置到tableHeaderView上時,只有高度需要我們自己設置,前面 X , Y ,Width都可以直接給個0
    headerView.frame = CGRectMake(0, 0, 0, 100);
    
    //設置tableView的最頂部視圖  
    self.tableView.tableHeaderView  = headerView;
    //-->這裡只需要headerView賦值給tableHeaderView 這個屬性,內部就在添加到父控制項上我們就不用addSubview:

}

3.添加數據驗證一下頭部視圖跟 "一組和多組" 沒有關係

//
//  LJXTableViewController.m
//  LJX_tableView的頭部和尾部視圖

#import "LJXTableViewController.h"

@interface LJXTableViewController ()

@end

//重用標識
static NSString *ID = @"cell";

@implementation LJXTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIView *headerView = [[UIView alloc]init];
    headerView.backgroundColor =[UIColor redColor];
    //把某個控制項設置到tableHeaderView上時,只有高度需要我們自己設置,前面 X , Y ,Width都可以直接給個0
    headerView.frame = CGRectMake(0, 0, 0, 100);
    
    
    //設置tableView的最頂部視圖    註意:跟一組和多組沒有關係
    self.tableView.tableHeaderView  = headerView;
    //-->這裡只需要headerView賦值給tableHeaderView 這個屬性,內部就在添加到父控制項上我們就不用addSubview:
    
    //註冊cell
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:ID];
}
//2組
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return  2;
}
//每組4行
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 4;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID forIndexPath:indexPath];
    
    cell.textLabel.text =@(indexPath.row).description;//簡單設置數據,每個cell顯示一個行數
    
    return cell;
}
@end

4.添加底部視圖

UIButton *footerBtn = [[UIButton alloc]init];
    footerBtn.backgroundColor = [UIColor purpleColor]; //紫色背景
    //把某個控制項設置到tableHeaderView上時,只有高度需要我們自己設置,前面 X , Y ,Width都可以直接給個0,但是x是可以改的,改了會有影響但不建議去改
    footerBtn.frame = CGRectMake(0, 0, 0, 100);
    //設置tableView的最底部視圖
    self.tableView.tableFooterView = footerBtn;

03-星級評價-需求分析

1.滿星個數 "分數強轉成整形,如4.5轉成整形是4 那就表示有4顆滿星"
2.半星個數 "分數 - 整星個數如果不為0那說明就有一個半星"
3.空心個數  "for(NSInteger i = 已添加星星個數; i < 5; i++)"

每一個商家的評分不一樣,所以分值要動態傳入,去動態設置星星樣子

04-星級評價

4.1星級評價實現

創建實體文件夾,方便日後移植
為了方便最後整合代碼時的移植,不直接在控制器中實現,而是單獨創建繼承UIView的類,

//
//  ZFBLeverStar.h
//  LJX_星級評價

#import <UIKit/UIKit.h>

@interface ZFBLeverStar : UIView
///接收評分
@property (nonatomic, assign) CGFloat lever;

@end

//
//  ZFBLeverStar.m
//  LJX_星級評價

#import "ZFBLeverStar.h"

@implementation ZFBLeverStar

//重寫set方法在裡面處理顯示星星圖片的細節
-(void)setLever:(CGFloat)lever{
    _lever = lever;
    
    //1.滿星
    //把傳過來的分數強轉為整型,整數值就是滿星的個數
    NSInteger fullStartCount = (NSInteger)lever;
    for(NSInteger i = 0 ; i < fullStartCount ; i++){
        [self makeLeverStarWithImageName:@"full_star" andPosition:i];
    }
    //2.半星
    // (取傳過來的個數) - (強轉後的整數),如果 > 0   就表示有半星
    if((lever - fullStartCount)>0){
        [self makeLeverStarWithImageName:@"half_star" andPosition:fullStartCount];
        //如果添加了一個半星那把滿星個數的值做加1 用它當做 目前已經添加星星的總個數了
        fullStartCount++;
    }

    //3.空星 "如果到這來還不夠5顆星 那剩下的就是空星的個數了"
    for (NSInteger i = fullStartCount; i < 5; i++) {
        [self makeLeverStarWithImageName:@"empty_star" andPosition:i];
    }
}

/**
 創建星星imageView

 @param imageName 星星圖片
 @param position 星星位置 從0開始
 */
-(void)makeLeverStarWithImageName:(NSString *)imageName andPosition:(NSInteger)position{
    //1.創建imageView設置圖片,那麼imageView創建出來的就有尺寸
    UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:imageName]];
    //2.設置圖片的x
    CGFloat imageViewX = position * imageView.image.size.width;
    imageView.frame = CGRectMake(imageViewX, 0, imageView.image.size.width, imageView.image.size.height);
    [self addSubview:imageView];    
}

@end

//
//  ViewController.m
//  LJX_星級評價


#import "ViewController.h"
#import "ZFBLeverStar.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
   
    ZFBLeverStar *leverStar = [[ZFBLeverStar alloc]init];
    leverStar.frame = CGRectMake(100, 100, 60, 12);//素材中圖片2X的是大小24*24,高24/2=12, 寬為5顆*12=60
    leverStar.backgroundColor = [UIColor purpleColor];
    
    leverStar.lever = 2.5;//先傳一個2.5分驗證一下
    [self.view addSubview:leverStar];
}

@end

4.2解決星星重覆創建問題

我們只創建添加,沒有管過移除啥的,顧導致傳一次分,創建一次....

解決重覆創建的問題
重寫初始化方法(初始化方法它只會調一次),那樣一創建leverStar這個控制項,裡面就自帶5顆星星imageView,

即對ZFBLeverStar.m做了修改

//
//  ZFBLeverStar.m
//  LJX_星級評價

#import "ZFBLeverStar.h"

@implementation ZFBLeverStar

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        //來了 直接把5個imageView創建添加好
        for (NSInteger i = 0; i < 5; i++) {
            UIImageView *imageView =[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"full_star"]];//這個目的不是拿圖片,目的是隨便拿一張圖片,圖片就有了大小了
        //設置圖片的x
         CGFloat imageViewX = i * imageView.image.size.width;
            imageView.frame = CGRectMake(imageViewX, 0, imageView.image.size.width, imageView.image.size.height);
         
             [self addSubview:imageView];
           
        }
    }
    return self;
}

//重寫set方法在裡面處理顯示星星圖片的細節
-(void)setLever:(CGFloat)lever{
    _lever = lever;
    
    //1.滿星
    //把傳過來的分數強轉為整型,整數值就是滿星的個數
    NSInteger fullStartCount = (NSInteger)lever;
    for(NSInteger i = 0 ; i < fullStartCount ; i++){
        [self makeLeverStarWithImageName:@"full_star" andPosition:i];
    }
    //2.半星
    // (取傳過來的個數) - (強轉後的整數),如果 > 0   就表示有半星
    if((lever - fullStartCount)>0){
        [self makeLeverStarWithImageName:@"half_star" andPosition:fullStartCount];
        //如果添加了一個半星那把滿星個數的值做加1 用它當做 目前已經添加星星的總個數了
        fullStartCount++;
    }

    //3.空星 "如果到這來還不夠5顆星 那剩下的就是空星的個數了"
    for (NSInteger i = fullStartCount; i < 5; i++) {
        [self makeLeverStarWithImageName:@"empty_star" andPosition:i];
    }
}

/**
 創建星星imageView

 @param imageName 星星圖片
 @param position 星星位置 從0開始
 */
-(void)makeLeverStarWithImageName:(NSString *)imageName andPosition:(NSInteger)position{
    //獲取相應位置的子控制項
    UIImageView *imageView = self.subviews[position];
    //設置圖片
    imageView.image = [UIImage imageNamed:imageName];
}

@end

4.3 最後深入的優化

這次優化的目的是:日後星級評價更加的方便.--->外部不管用純代碼還有用xib還是用storyboard都比較方便.

如何不想使用代碼方式

使用storyboard


運行ok


支付寶口碑案例開始

自定義cell有3種方式,分別是storyboard,xib,手寫代碼.
我們都使用一遍.這裡我們先使用第一種方式使用-->storyboard方式

需求分析

1.頂部是一個TableViewHeaderView
2.組的頭部標題可以停留,說明tableView是plain樣式
3.cell中的數據比較多,系統無法滿足,自定義cell

1.項目準備:
指定類首碼(例如ZFB),分文件夾(目的是為了後面集成到一個項目中),刪除原有Main.storyboard 自己創建一個storyboard(指定class進行關聯,設置為啟動界面),並別忘指定 Main interface



創建控制器: 註意繼承UITableViewController(因為storyboard中我們拖拽的UITableViewControler,所以創建的類也要繼承UITableViewControler)

如果運行後,是白色面板. 排錯方法:打斷點
------>給數據源方法打斷點------->(沒執到時)-往上打斷點
------->[super viewDidLoad]----->(也沒有執行到時)
------>查看有沒有指定控制器class;

把準備好的plist文件和圖片素材拖入案例中

使用了UITableViewController後,指定數據源和遵守協議都不用我們管了.下一步我們來實現相應的數據源方法

2.實現相應的數據源方法

需要的數據,通過第4步會得到.

3.有多少行應該根據數據來

4.載入plist字典轉換模型

去modal文件夾中,創建模型類

//--------------------ZFBBusinessModel.h------------------------
#import <Foundation/Foundation.h>

@interface ZFBBusinessModel : NSObject
///頭像
@property (nonatomic, copy) NSString *icon;
///優惠信息
@property (nonatomic, copy) NSString *discount;
///人均消費
@property (nonatomic, strong)  NSNumber *averagePrice;
///距離
@property (nonatomic, strong)  NSNumber *distance;
///打折
@property (nonatomic, strong)  NSNumber *offNum;
///評分
@property (nonatomic, strong)  NSNumber *level;
///店名
@property (nonatomic, copy) NSString *name;

+ (instancetype)businessWithDict:(NSDictionary *)dict;

@end
//--------------------ZFBBusinessModel.m------------------------
#import "ZFBBusinessModel.h"

@implementation ZFBBusinessModel

+(instancetype)businessWithDict:(NSDictionary *)dict{
    id obj = [[self alloc]init];
    
    [obj setValuesForKeysWithDictionary:dict];
    //--->註意使用KVC編碼,屬性名和字典中的key的名字一定要相同.
    return obj;
}

@end

5.在storyboard中給自帶的UITableViewCell指定重用標識 一定要和返回cell的數據源方法是的標識要一樣

UITableView *cell = [tableView dequeueReusableCellWithIdentifier:@"business" forIndexPath:indexPath];

6.在storyboard中給cell添加拖拽相應的控制項,並添加約束

6.1拖拽imageView
(plus是3X的在這除以3
工作中一般都2x的,到時候除以2)

因為各個商家圖片不一樣大,顧為了統一

Scale:拉伸圖片
Aspect:圖片長寬的比例,保持圖形的長寬比,保持圖片不變形。

Aspect Fill:在保持長寬比的前提下,縮放圖片,使圖片充滿容器。
Aspect Fit:在保持長寬比的前提下,縮放圖片,使得圖片在容器內完整顯示出來。
Scale to Fill: 縮放圖片,使圖片充滿容器。圖片未必保持長寬比例協調,有可能會拉伸至變形。

6.1拖拽lable設置店名

6.3 先拖個view給星星占個位,後面再處理


6.4拖拽lable設置評分


設置約束

6.4拖拽lable設置人均消費
設置字體大小,設置約束

運行一下看效果,然後再繼續

6.5拖拽lable設置折扣


設置約束


6.6拖拽lable設置距離
設置約束 x和Y


6.7拖拽lable設置減字

設置約束(上邊距8,與上面左邊對齊,)略
減字外面的是正方形,我們設置一下寬高比為1:1,文字居中就ok了


6.8拖拽lable設置隨機立減...
(設置字體及顏色,設置約束,略..)
6.9 修改一下cell的高度

上面修改了business中的高度,只是修改了模型的大小,運行起來還得看 table View的高度大小,所以還得修改table View的高度

6.10 把背景顏色去掉運行一下看看

7.創建一個繼承至UITableViewCell的類,並且指定SB中的UITableViewCell的class為自己創建出來的這個類

8.把SB中Cell內部的子控制項連線到指定class的.m中的延展中

8.1增加一個延展

8.2指定class

8.3 子控制項連線

9.把模型變成屬性定義在自定義cell類的.h中,在.m重寫模型屬性的set方法在此方法設置數據

9.1 把模型變成屬性定義在自定義cell類的.h中

//  ZFBBusinessCell.h

#import <UIKit/UIKit.h>
@class ZFBBusinessModel;
@interface ZFBBusinessCell : UITableViewCell
///模型屬性    註意模型是個對象 用strong
@property (nonatomic , strong) ZFBBusinessModel *businessModel;

@end

9.2 在.m重寫模型屬性的set方法在此方法設置數據

//
//  ZFBBusinessCell.m


#import "ZFBBusinessCell.h"
#import "ZFBBusinessModel.h"//註意導入頭文件
@interface ZFBBusinessCell ()
///商店的頭像
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
///店名
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
///評分
@property (weak, nonatomic) IBOutlet UILabel *levelLabel;
///人均消費
@property (weak, nonatomic) IBOutlet UILabel *averagePriceLabel;
///打折
@property (weak, nonatomic) IBOutlet UILabel *offNumLabel;
///距離
@property (weak, nonatomic) IBOutlet UILabel *distanceLabel;
///優惠信息 
@property (weak, nonatomic) IBOutlet UILabel *discountLabel;

@end

@implementation ZFBBusinessCell

//重寫模型屬性的set方法在此方法中給子控制項設置數據
-(void)setBusinessModel:(ZFBBusinessModel *)businessModel{
    _businessModel =businessModel;
    
    _iconView.image = [UIImage imageNamed:businessModel.icon];
    _nameLabel.text = businessModel.name;
    _levelLabel.text = businessModel.level.description;//level是NSNumber類型的,轉字元串掉description方法
    _averagePriceLabel.text = [NSString stringWithFormat:@"人均消費 %@ 元",businessModel.averagePrice];  //plist中只存了個數字,要顯示人均消費**元,顧要拼接字元串
    _offNumLabel.text = [NSString stringWithFormat:@"%@ 折",businessModel.offNum];
    _distanceLabel.text = [NSString stringWithFormat:@"距離北京石油化工學院 %@ m",businessModel.distance];
    _discountLabel.text = businessModel.discount;
}


@end

回到ZFBBusinessController.m中
修改創建的cell類型

設置數據

 //2.設置數據        (傳遞模型,這裡是單組數據展示, 當只有一組數據的時候用row,多組的時候才先用section再用row)
    cell.businessModel = self.businessData[indexPath.row];

運行看現階段效果

數據類型有點小問題,8.8折和9.8折後面都一大串,接下來修改

10.打折 把模型中的offNum 改float類型,前提要改一下引入系統框架 UIKit

10.1修改ZFBBusinessModel.h文件

10.2修改ZFBBusinessCell.m文件

運行看效果

11.集成星星,把星星的文件拖拽出來後,指定Storyboard中代表星星的那個View的Class

12.把用來表示星星view連線在自定義cell.m中,引入星星類的頭文件


13.在模型屬性的set方法中,給星星view傳level

 _leverView.lever = businessModel.level;


上面報錯是因為我們傳的是CGFloat類型導致的



顧改一下

這是這裡又報錯

還要改一下

把星星後面黃色背景顏色去掉,運行看效果

14.創建了一個xib 把xib中的view 寬361 高960

15.在裡面拖入一個imageView並且設置好圖片, 註意先 com + = 自適應下 為了後面使用Aspect ratio後圖片不會變形
16. 第一個imageView 上 左 右 8間距 + 寬高比

先使用 com + = 自適應 ,後面再設置寬高比,這樣他會根據真實的尺寸算比例,圖片不會變形

17.再複製3個imageView 但註意它身上約束

即複製完後,clear複製的約束

18.全部選中(com+a) 左對齊 等寬等高 上下間距8

左對齊

等寬等高

上下間距8:

註意在設置上下間距前,要保證兩個圖片之間不要有重合

19.創建一個繼承 至UIView的類,並且給xib指定class

繼承關係是跟最頂層有關係的,最頂層是UIView,就繼續UIView,最頂層是UIButton,那就繼續UIButton. 這裡是頂層是UIView.

給xib指定class(其實不指定也可以,因為之間沒有連線,但最好指定一下,說明它們之間是同一類型)

20.把載入xib細節封裝在剛纔創建的類中,提供一個可以讓外部調用的類方法,目的降低耦合度.

//#########################
//  ZFBBusinessPictureView.h
#import <UIKit/UIKit.h>

@interface ZFBBusinessPictureView : UIView

/**
 載入xib創建頭部視圖
 */
+(instancetype)businessPictureView;

@end


//#########################
//  ZFBBusinessPictureView.m
#import "ZFBBusinessPictureView.h"

@implementation ZFBBusinessPictureView


/*
 
 知識點回顧--兩種載入xib的方式
 1.NSBundle載入XIB  iOS 2.0 的方法
 2.使用UINib載入XIB  iOS 4.0 的方法   做了記憶體優化"如果記憶體緊張"記憶體警告,可以自動釋放,如果有需要會重新自動載入""
 */

+(instancetype)businessPictureView{

    UINib *nib = [UINib nibWithNibName:@"ZFBBusinessPicture" bundle:nil];
    return [[nib instantiateWithOwner:nil options:nil]firstObject];
}

@end

21.給tableView設置tableHeaderView 註意要計算它將來真實的高度

回到ZFBBusinessController.m
回到控制器中,導入剛纔創建類的頭文件ZFBBusinessPictureView.h

在控制器設置tableView的頭部 視圖.

 //2.設置tableView的頭部視圖
    ZFBBusinessPictureView *pictureView = [ZFBBusinessPictureView businessPictureView];
    //375 * 960 / 361
    CGFloat pictureViewHeight = self.tableView.bounds.size.width * pictureView.bounds.size.height / pictureView.bounds.size.width;  //根據比例計算真實高度
        pictureView.frame = CGRectMake(0, 0, self.tableView.bounds.size.width, pictureViewHeight); //寬度最好不要給了,以防有問題
  
    self.tableView.tableHeaderView = pictureView;  //設置為頭部視圖

22.給tableView設置tableFooterView

 //3.設置tableView的尾部視圖
    UIButton *footerBtn = [[UIButton alloc]init];
    [footerBtn setTitle:@"點擊載入更多" forState:UIControlStateNormal];
    
    [footerBtn setTitleColor:[UIColor colorWithWhite:0.3 alpha:1] forState:UIControlStateNormal];
    [footerBtn setTitleColor:[UIColor colorWithWhite:0.7 alpha:1] forState:UIControlStateHighlighted];
    
    footerBtn.backgroundColor = [UIColor colorWithWhite:0.5 alpha:1];
    footerBtn.frame = CGRectMake(0, 0, 0, 30);
    
    
    self.tableView.tableFooterView = footerBtn;//設置為尾部視圖

23.實現沒點擊載入更多一次,多輸出一個cell

把之前定義是不可變數組,修改為可變數組,不然就會報警告



24.優化讓其自動滾動

1.atScrollPosition: 的參數為UITableViewScrollPositionMiddle時

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.businessData.count-1 inSection:0];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];


2.atScrollPosition: 的參數為UITableViewScrollPositionBottom時

25.細節處理 讓cell的分割線從最左邊開始

self.tableView.separatorInset = UIEdgeInsetsZero;

後面還沒會慢慢對細節進行處理

檢測自己


看看哪些沒掌握:

1、能夠說出tableViewController的view屬性和tableView是一樣的

2、能夠使用xib佈局口碑的頭部視圖

3、能夠說出使用代碼重新設置nib高度的含義是為了適配不同寬度的屏幕

4、能夠使用代碼設置尾部的按鈕

5、能夠說出代碼會調用view的initWithFrame方法

6、能夠說出sb/xib會調用view的aweakFromNib方法

7、能夠將星級評價小框架移植到口碑控制器中

8、能夠解決浮點數轉字元串精度的問題

9、能夠使用代碼解析plist數據

10、能夠使用代碼將字典轉化成模型

11、能夠使用代碼設置tableView的headerView和footerView

簡單回顧過程


1.口碑-數據分析

2.口碑-創建模型

  • 類首碼
  • 分文件夾
  • 素材

3.口碑-解析數據

4.口碑-通過sb載入cell

  • 通過sb載入cell,需要設置cell的Identifier,給sb中的cell設置重用標識即完成註冊單元格

5.口碑-cell的佈局

1.商家配圖圖片大小不一樣,所以最好給imageView設置寬高約束,達到配圖尺寸統一
2.label如果只有一行時,只用設置位置即可,尺寸讓它自適應
3.評分view,它的大小不能自適應,所以必須設置寬高約束"60,12"
4.減是個方形的,所以最好設置個寬高比


店名字體:14字體
其它是12號字體
到cell邊距15
內部邊距11

6.口碑-自定義cell控制項連線

1.cell中的子控制項不能連線到控制器,因為當前控制器只有一個,但是將來cell有很多個,所以會報重覆連接"連線"錯誤
2.正確作法,應該創建一個繼承至UITableViewCell的類,來管理"描述/表示",設置cell的customClass
3.把cell中子控制項的連線,連入到管理cell類的.m的延展中

7.口碑-設置cell數據

引入模型屬性"strong"
重寫模型屬性set方法給cell內部子控制項設置數據

8.口碑-移植星級評價

  • 拖拽文件,設置sb中的view為自定義view,連線併在set數據的方法中把數據放在控制項上
  • 用自定義星星的類來描述cell中的星星view,載入sb中的小星星view創建出來的對象,就是他指定類創建來出的對象"他們是同一個東西了"
  • 再給level傳入分值即可

9.口碑-頭部視圖-佈局

  • 第一個視圖分別設置 上,左,右,寬高比
  • 後面的視圖與前一個等寬,等高,垂直間距,水平居中

10.口碑-頭部視圖-代碼設置縮放比例

- 在xib中調整好位置高度,併在視圖載入完成之後根據'寬度'和'屏幕的寬度'和'屏幕的高度'設置**高度**
- tableView的寬 / xib中HeaderView的寬 * xib中HeaderView的高 得到按比例縮放後的realHeaderView的高
- xib中的高 * tableView的寬 / xib中的寬
- xib的高 / xib的寬  * tableView的寬
2: 3 == 4: 6?

11.口碑-尾部視圖

  • 灰度,R=G=B
  • 1為白色 0為黑色

12.口碑-組頭

  • tableview兩種樣式組頭的區別?
    • grouped跟著tableView滾動出去
    • plain可以懸停在上方

13.口碑-添加導航控制器

Editor -> Embedin -> Navgation Contorller

20-MarkMan測量截圖位置

21-KVC

        // 方法1 傳統寫法
        _name = dict[@"name"];
        // 字典不能保存基本數據類型
        _age = [dict[@"age"] integerValue];

        // 方法2 KVC - `間接`通過 key 設置數值
        // 註意:基本數據類型,不需要轉換,KVC 可以自動實現轉換!
        [self setValue:dict[@"name"] forKey:@"name"];
        [self setValue:dict[@"age"] forKey:@"age"];

        // 方法3 KVC - 進階,迴圈遍歷字典
        for (NSString *key in dict) {
            // 1. 通過 key 取值
            id value = dict[key];

            // 2. 通過 KVC 方法設置數值
            // -key 對應對象的 `屬性`,如果屬性不存在就崩潰
            [self setValue:value forKey:key];
        }

        // 方法4 KVC 字典轉模型大招 -> 內部實際上就是方法3的實現
        [self setValuesForKeysWithDictionary:dict];

  • 在保證模型的屬性和字典中的key相同的情況下,字典轉模型使用setValuesForKeysWithDictionary:方法
  • keys value coding 鍵值編碼

附整體代碼

/**總步驟:
 1.指定類首碼,分文件夾'刪除原有Main.sb' 自己創建一個,並別忘指定 Main interface
 2.實現相應的數據源方法
 3.有多少行應該根據數據來
 4.載入plist字典轉換模型
 5.在sb中給自帶的UITableViewCell指定重用標識 一定要和返回cell的數據源方法是的標識要一樣
 6.在SB中給cell添加拖拽相應的控制項,並添加約束
 7.創建一個繼承至UITableViewCell的類,並且指定SB中的UITableViewCell的class為自己創建出來的這個類
 8.把SB中Cell內部的子控制項連線到指定class的.m中的延展中
 9.把模型變成屬性定義在自定義cell類的.h中,在.m重寫模型屬性的set方法在此方法設置數據
 10.打折 把模型中的offNum 改float類型,前提要改一下引入系統框架 UIKit
 11.集成星星,把星星的文件拖拽出來後,指定SB中代表星星的那個View的Class 
 12.把用來表示星星view連線在自定義cell.m中,引入星星類的頭文件
 13.在模型屬性的set方法中,給星星view傳level
 14.創建了一個xib 把xib中的view 寬361 高960
 15.在裡面拖入一個imageView並且設置好圖片, com + = 自適應下 為了不用改寬高比約束值
 16. 第一個imageView  上  左 右  8間距  + 寬高比
 17. 複製3個imageView 但註意它身上約束
 18. 全部選中左對齊 等寬等高  上下間距8
 19. 創建一個繼承 至UIView的類,並且指定class
 20. 把載入xib細節封裝在此類中,提供一個可以讓外部調用的類方法
 21.給tableView設置tableHeaderView  註意要計算它將來真實的高度
 22.給tableView設置tableFooterView
 23.實現沒點擊載入更多一次,多輸出一個cell
 24.優化讓其自動滾動
 25.細節處理  讓cell的分割線從最左邊開始
*/

//********************ZFBBusinessController.h*****************************
//  ZFBBusinessController.h
#import <UIKit/UIKit.h>

@interface ZFBBusinessController : UITableViewController

@end

//**********************ZFBBusinessController.m***************************
//
//  ZFBBusinessController.m
//  LJX_支付寶口碑(stroyboard搭建)

#import "ZFBBusinessController.h"
#import "ZFBBusinessModel.h"
#import "ZFBBusinessCell.h"
#import "ZFBBusinessPictureView.h"

@interface ZFBBusinessController ()
//數據在多個數據源方法中使用,顧聲明一個屬性
@property (nonatomic ,strong)NSMutableArray *businessData;
@end

@implementation ZFBBusinessController

- (void)viewDidLoad {
    [super viewDidLoad];
    //1.載入數據
    self.businessData = [self loadBusinessData];
    //-->使用方式2時,直接調用方法就行[self loadBusinessData];

    //2.設置tableView的頭部視圖
    ZFBBusinessPictureView *pictureView = [ZFBBusinessPictureView businessPictureView];
    
    //如果不設置,因為xib中設置的寬度是361,如果在375的手機屏幕上顯示,因為xib中的圖片的寬度沒有寫死,當到了寬屏幕下,變寬,高也會變高,導致圖片會超出父控制項, 出了頭部視圖的邊界.
    //375 * 960 / 361
    CGFloat pictureViewHeight = self.tableView.bounds.size.width * pictureView.bounds.size.height / pictureView.bounds.size.width;  //計算真實高度
        pictureView.frame = CGRectMake(0, 0, self.tableView.bounds.size.width, pictureViewHeight); //寬度最好不要給了,以防有問題
  
    self.tableView.tableHeaderView = pictureView;  //設置為頭部視圖
    
    
    //3.設置tableView的尾部視圖
    UIButton *footerBtn = [[UIButton alloc]init];
    [footerBtn setTitle:@"點擊載入更多" forState:UIControlStateNormal];
    
    // colorWithWhite:0.3 alpha:1  通過灰度來設置顏色 第一個參數如果 傳0就是黑色  如果傳1就表示白色
    [footerBtn setTitleColor:[UIColor colorWithWhite:0.3 alpha:1] forState:UIControlStateNormal];
    [footerBtn setTitleColor:[UIColor colorWithWhite:0.7 alpha:1] forState:UIControlStateHighlighted];
    
    footerBtn.backgroundColor = [UIColor colorWithWhite:0.5 alpha:1];
    footerBtn.frame = CGRectMake(0, 0, 0, 30);
    
    [footerBtn addTarget:self action:@selector(loadMoreData) forControlEvents:UIControlEventTouchUpInside]; //添加點擊事件
    
    self.tableView.tableFooterView = footerBtn;//設置為尾部視圖
    
    
    //小細節處理 :讓分割線從最左邊開始
    self.tableView.separatorInset = UIEdgeInsetsZero;

 }

#pragma mark -尾部按鈕點擊後會調用此方法
//1.載入更多數據
-(void)loadMoreData{
    //1.創建一個新的模型
    ZFBBusinessModel *businessModel = [[ZFBBusinessModel alloc]init];
    businessModel.icon = @"ss";
    
    businessModel.discount = @"全場大派送,2元一件,快來買!";
    businessModel.averagePrice = @2;
    businessModel.distance = @20;
    businessModel.offNum = 2;
    businessModel.level = 5;
    businessModel.name = @"西單大悅城!";
    
    //2.把新模型添加到保存所以數據的數組中
    [self.businessData addObject:businessModel];
    
    //3.讓數據源方法重新執行
    [self.tableView reloadData];
    
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.businessData.count-1 inSection:0];
    [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
    
}


#pragma mark -數據源方法
// 應該口碑案例表格就1組,預設就1組,所以不用再寫
//- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
//    return 1;
//}

// 行數
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.businessData.count;
   //--->使用方式2時: return _businessList.count;
}

//
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    //1.創建cell
    ZFBBusinessCell *cell = [tableView dequeueReusableCellWithIdentifier:@"business" forIndexPath:indexPath];
    //-->這裡在storyboard中進行註冊cell
    
    //2.設置數據        (傳遞模型,這裡是單組數據展示, 當只有一組數據的時候用row,多組的時候才先用section再用row)
    cell.businessModel = self.businessData[indexPath.row];
    
    //3.返回cell
    return cell;
}


#pragma mark -載入數據

- (NSMutableArray *)loadBusinessData{
    //1.載入plist
    NSMutableArray *dictArr = [NSMutableArray arrayWithContentsOfURL:[[NSBundle mainBundle]URLForResource:@"business.plist" withExtension:nil]];
    
    //2. 創建可變數組保存模型     /kə'pæsɪtɪ/ 容量
    NSMutableArray *arryM = [NSMutableArray arrayWithCapacity:dictArr.count];
    
    //3.字典轉模型
    for(NSDictionary *dict in dictArr){
        
        [arryM addObject:[ZFBBusinessModel businessWithDict:dict]];

        /* 分步寫
        //3.1 把字典傳遞給模型,讓模型設置自己的屬性
        ZFBBusinessModel *groupModel = [ZFBBusinessModel businessWithDict:dict];
        //3.2 把創建好的模型添加到可變數組中.
         [arryM addObject: groupModel];
        */
     }

    return arryM;
}

/*
 
 方式2. 載入數據方法的返回值設置為空 ,聲明一個成員變數(給成員變數設置泛型),把可變數組賦值給成員變數
 
 1.  NSArray<ZFBBusinessModel *> *_businessList; //聲明成員變數,設置泛型
 2.
 - (void)loadBusinessData{
    ...code略....
   _businessList = arryM;
 }
 
 */

@end

//
//  ZFBBusinessModel.h
#import <UIKit/UIKit.h>

@interface ZFBBusinessModel : NSObject
///頭像
@property (nonatomic, copy) NSString *icon;
///優惠信息
@property (nonatomic, copy) NSString *discount;
///人均消費
@property (nonatomic, strong)  NSNumber *averagePrice;
///距離
@property (nonatomic, strong)  NSNumber *distance;
///打折
//浮點數字轉出成字元串時,可能會出現問題,把它轉換成float 
@property (nonatomic, assign)  float offNum;
///評分
@property (nonatomic, assign)  CGFloat level;
///店名
@property (nonatomic, copy) NSString *name;

+ (instancetype)businessWithDict:(NSDictionary *)dict;

@end

#import "ZFBBusinessModel.h"

@implementation ZFBBusinessModel

+(instancetype)businessWithDict:(NSDictionary *)dict{
    id obj = [[self alloc]init];
    
    [obj setValuesForKeysWithDictionary:dict];
    //--->註意使用KVC編碼,屬性名和字典中的key的名字一定要相同.
    return obj;
}


@end

//
//  ZFBLeverStar.h
//  LJX_星級評價

#import <UIKit/UIKit.h>

@interface ZFBLeverStar : UIView
///接收評分
@property (nonatomic, assign) CGFloat lever;

@end

//
//  ZFBLeverStar.m
//  LJX_星級評價

#import "ZFBLeverStar.h"

@implementation ZFBLeverStar

//當一個視圖從xib或storyboard中創建完成之後就會調用此方法
-(void)awakeFromNib{
    [super awakeFromNib];
   
    //來了 直接把5個imageView創建添加好
    for (NSInteger i = 0; i < 5; i++) {
        UIImageView *imageView =[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"full_star"]];//這個目的不是拿圖片,目的是隨便拿一張圖片,圖片就有了大小了
        //設置圖片的x
        CGFloat imageViewX = i * imageView.image.size.width;
        imageView.frame = CGRectMake(imageViewX, 0, imageView.image.size.width, imageView.image.size.height);

        [self addSubview:imageView];
    }
}

//此方法只有用代碼創建時才會調用
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        //來了 直接把5個imageView創建添加好
        for (NSInteger i = 0; i < 5; i++) {
            UIImageView *imageView =[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"full_star"]];//這個目的不是拿圖片,目的是隨便拿一張圖片,圖片就有了大小了
        //設置圖片的x
         CGFloat imageViewX = i * imageView.image.size.width;
            imageView.frame = CGRectMake(imageViewX, 0, imageView.image.size.width, imageView.image.size.height);
         
             [self addSubview:imageView];
           
        }
    }
    return self;
}


//重寫set方法在裡面處理顯示星星圖片的細節
-(void)setLever:(CGFloat)lever{
    _lever = lever;
    
    //1.滿星
    //把傳過來的分數強轉為整型,整數值就是滿星的個數
    NSInteger fullStartCount = (NSInteger)lever;
    for(NSInteger i = 0 ; i < fullStartCount ; i++){
        [self makeLeverStarWithImageName:@"full_star" andPosition:i];
    }
    //2.半星
    // (取傳過來的個數) - (強轉後的整數),如果 > 0   就表示有半星
    if((lever - fullStartCount)>0){
        [self makeLeverStarWithImageName:@"half_star" andPosition:fullStartCount];
        //如果添加了一個半星那把滿星個數的值做加1 用它當做 目前已經添加星星的總個數了
        fullStartCount++;
    }

    //3.空星 "如果到這來還不夠5顆星 那剩下的就是空星的個數了"
    for (NSInteger i = fullStartCount; i < 5; i++) {
        [self makeLeverStarWithImageName:@"empty_star" andPosition:i];
    }
}

/**
 創建星星imageView

 @param imageName 星星圖片
 @param position 星星位置 從0開始
 */
-(void)makeLeverStarWithImageName:(NSString *)imageName andPosition:(NSInteger)position{
    //獲取相應位置的子控制項
    UIImageView *imageView = self.subviews[position];
    //設置圖片
    imageView.image = [UIImage imageNamed:imageName];
}

@end

/*
 //1.創建imageView設置圖片,那麼imageView創建出來的就有尺寸
 UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:imageName]];
 //2.設置圖片的x
 CGFloat imageViewX = position * imageView.image.size.width;
 imageView.frame = CGRectMake(imageViewX, 0, imageView.image.size.width, imageView.image.size.height);
 [self addSubview:imageView];
 
 */

//
//  ZFBBusinessCell.h

#import <UIKit/UIKit.h>
@class ZFBBusinessModel;
@interface ZFBBusinessCell : UITableViewCell
///模型屬性    註意模型是個對象 用strong
@property (nonatomic , strong) ZFBBusinessModel *businessModel;

@end

//
//  ZFBBusinessCell.m

#import "ZFBBusinessCell.h"
#import "ZFBBusinessModel.h"//註意導入頭文件
#import "ZFBLeverStar.h"
@interface ZFBBusinessCell ()
///商店的頭像
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
///店名
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
///評分
@property (weak, nonatomic) IBOutlet UILabel *levelLabel;
///人均消費
@property (weak, nonatomic) IBOutlet UILabel *averagePriceLabel;
///打折
@property (weak, nonatomic) IBOutlet UILabel *offNumLabel;
///距離
@property (weak, nonatomic) IBOutlet UILabel *distanceLabel;
///優惠信息 
@property (weak, nonatomic) IBOutlet UILabel *discountLabel;
///星級評價
@property (weak, nonatomic) IBOutlet ZFBLeverStar *leverView;


@end

@implementation ZFBBusinessCell

//重寫模型屬性的set方法在此方法中給子控制項設置數據
-(void)setBusinessModel:(ZFBBusinessModel *)businessModel{
    _businessModel =businessModel;
    
    _iconView.image = [UIImage imageNamed:businessModel.icon];
    _nameLabel.text = businessModel.name;
    _levelLabel.text = @(businessModel.level).description;//level是NSNumber類型的,轉字元串掉description方法
    _averagePriceLabel.text = [NSString stringWithFormat:@"人均消費 %@ 元",businessModel.averagePrice];  //plist中只存了個數字,要顯示人均消費**元,顧要拼接字元串
    _offNumLabel.text = [NSString stringWithFormat:@"%@ 折",@(businessModel.offNum).description];
    _distanceLabel.text = [NSString stringWithFormat:@"距離北京石油化工學院 %@ m",businessModel.distance];
    _discountLabel.text = businessModel.discount;
    
     //傳分
    _leverView.lever = businessModel.level;
}

- (void)awakeFromNib {
    [super awakeFromNib];
    // Initialization code
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

@end

//
//  ZFBBusinessPictureView.h

#import <UIKit/UIKit.h>

@interface ZFBBusinessPictureView : UIView

/**
 載入xib創建頭部視圖
 */
+(instancetype)businessPictureView;

@end
//
//  ZFBBusinessPictureView.m

#import "ZFBBusinessPictureView.h"

@implementation ZFBBusinessPictureView


/*
 
 知識點回顧--兩種載入xib的方式
 1.NSBundle載入XIB  iOS 2.0 的方法
 2.使用UINib載入XIB  iOS 4.0 的方法   做了記憶體優化"如果記憶體緊張"記憶體警告,可以自動釋放,如果有需要會重新自動載入""
 */

+(instancetype)businessPictureView{

    UINib *nib = [UINib nibWithNibName:@"ZFBBusinessPicture" bundle:nil];
    return [[nib instantiateWithOwner:nil options:nil]firstObject];
}

@end




您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 以下代碼解決了在IE8及以下瀏覽器中不支持placeholder屬性。 原理:將placeholder的值作為內容寫入控制項,並添加控制項事件來進行模擬。 ...
  • 在上一篇文章中,我們使用 js+css 實現了模態框效果,在理解了模態框的基本實現方法和實現效果後,我們就要尋找更快捷的方法,又快又好的來完成模態框開發需求,從而節約時間,提高效率。一個好的輪子,不僅能大幅減輕工作量,而且能讓我們的代碼更簡明和優雅。 今天我們選擇使用著名的 bootstrap 庫的 ...
  • 1.水平居中 1.1已知寬度塊元素寬度 : 1.2文本內容居中: 1.3通過表格: 1.4已知寬度,通過設置position:absolute,margin-left為寬度的負一半 1.5未知寬度,通過設置position:absolute 1.6使用flex佈局實現(相容性不好,感覺有點變成浮動的 ...
  • 之前自己就學了點AnjularJS,都是在菜鳥教程裡面將基礎的只是大致過了一遍,沒怎麼自己動手做什麼東西練練手,但還是覺得紙上得來終覺淺,得知此事要躬行啊,今天就做了個猜數字的小游戲,覺得效果還不錯,心情也大好,看來還是得多練啊。好了,廢話少說,還是說說效果怎麼實現的吧。 既然是AnjularLS項 ...
  • 【原】解決 "安裝xmapp後Apache不能正常啟動" 問題 小伙伴們安裝xmapp後發現Apache不能正常開啟,下麵給出了不同情況的解決辦法,可以分為以下幾種情況分析問題: (一)是否在本次安裝之前已經安裝過xmapp(沒有請跳過) 在本次安裝之前已經安裝過xmapp,雖然卸載了,但是會有卸載 ...
  • history.go(-n) 返回上一頁(n 為返回前幾頁) window.location.reload(); 刷新當前頁面 history.go(-1);window.locatoin.reload(); 等效於 self.location = document.referrer 返回上一頁並刷 ...
  • 摘錄自 "《CSS核心技術詳解》" 1.1 CSS中你可能會疑問的幾個問題 1.1.1 在CSS中為什麼要有層疊 在CSS中可能會有多個樣式表同時影響同一個元素的某個屬性,設計這個功能的主要原因有兩個,解決模塊化和作者、用戶、用戶代理樣式衝突。 模塊化 一個頁面中的樣式可以拆分成多個樣式表,代碼如下 ...
  • 前言 Promise的重要性我認為我沒有必要多講,概括起來說就是必須得掌握,而且還要掌握透徹。這篇文章的開頭,主要跟大家分析一下,為什麼會有Promise出現。 在實際的使用當中,有非常多的應用場景我們不能立即知道應該如何繼續往下執行。最重要也是最主要的一個場景就是ajax請求。通俗來說,由於網速的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...