国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

瀑布流-02-手把手教你封裝自定義布局

2019-11-14 18:22:58
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

概述


  • 對(duì)于經(jīng)常使用的控件或類(lèi),通常將其分裝為一個(gè)單獨(dú)的類(lèi)來(lái)供外界使用,以此達(dá)到事半功倍的效果
  • 由于分裝的類(lèi)不依賴于其他的類(lèi),所以若要使用該類(lèi),可直接將該類(lèi)拖進(jìn)項(xiàng)目文件即可
  • 在進(jìn)行分裝的時(shí)候,通常需要用到代理設(shè)計(jì)模式

代理設(shè)計(jì)模式


  • 代理設(shè)計(jì)模式的組成

    • 客戶類(lèi)(通常作為代理)

      • 通常委托這是角色來(lái)完成業(yè)務(wù)邏輯
    • 真實(shí)角色

      • 將客戶類(lèi)的業(yè)務(wù)邏輯轉(zhuǎn)化為方法列表,即代理協(xié)議
    • 代理協(xié)議

      • 定義了需要實(shí)現(xiàn)的業(yè)務(wù)邏輯
      • 定義了一組方法列表,包括必須實(shí)現(xiàn)的方法或選擇實(shí)現(xiàn)的方法
      • 代理協(xié)議是代理對(duì)象所要遵循一組規(guī)則
    • 代理角色

      • 若要作為代理,需要遵守代理協(xié)議,并且實(shí)現(xiàn)必須實(shí)現(xiàn)的代理方法
      • 代理角色可以通過(guò)調(diào)用代理協(xié)議中的方法完成業(yè)務(wù)邏輯,也可以附加自己的操作
  • 文字描述通常是抽象的,一下通過(guò)圖示來(lái)闡述代理設(shè)計(jì)模式

自定義布局類(lèi)的封裝


  • 業(yè)務(wù)邏輯

    • 如圖

  • 布局每個(gè)cell的業(yè)務(wù)邏輯

    • 由于設(shè)置每個(gè)cell的布局屬性的業(yè)務(wù)邏輯較復(fù)雜,特附上如下思維導(dǎo)圖

  • 封裝思路封裝需要根據(jù)客戶類(lèi)業(yè)務(wù)邏輯需求來(lái)提供接口

    • 通過(guò)代理協(xié)議的可選實(shí)現(xiàn)的方法獲取的屬性值的屬性,需要設(shè)置默認(rèn)值
    • 未提供默認(rèn)值的且必須使用的屬性,需要通過(guò)必須實(shí)現(xiàn)的方法來(lái)獲得
    • 自定義布局提供的接口可選

      • 列數(shù)
      • 列之間的間距
      • 行之間的間距
      • 內(nèi)邊距
    • 自定義布局提供的接口必選

      • 每個(gè)元素的高度,寬度可以通過(guò)列數(shù)和列間距計(jì)算得到

封裝步驟


  • 設(shè)置代理協(xié)議,提供接口

    //聲明LYPWaterFlowLayout為一個(gè)類(lèi)@class LYPWaterFlowLayout;@PRotocol LYPWaterFlowLayoutDelegate <NSObject>//必須實(shí)現(xiàn)的方法@required/**獲取瀑布流每個(gè)元素的高度*/- (CGFloat)waterFlowLayout:(LYPWaterFlowLayout *)waterFlowLayout heightForItemAtIndex:(NSInteger)index itemWith:(CGFloat)itemWith;//可選實(shí)現(xiàn)的方法@optional/**獲取瀑布流的列數(shù)*/- (NSInteger)columnCountInWaterFlowLayout:(LYPWaterFlowLayout *)waterFlowLayout;/**獲取瀑布流列間距*/- (CGFloat)columnMarginInWaterFlowLayout:(LYPWaterFlowLayout *)waterFlowLayout;/**獲取瀑布流的行間距*/- (CGFloat)rowMarginInWaterFlowLayout:(LYPWaterFlowLayout *)waterFlowLayout;/**獲取瀑布流的內(nèi)邊距*/- (UIEdgeInsets)edgeInsetsInWaterFlowLayout:(LYPWaterFlowLayout *)waterFlowLayout;@end
  • 設(shè)置代理屬性

    @interface LYPWaterFlowLayout : UICollectionViewLayout/**代理*/@property (nonatomic, weak) id<LYPWaterFlowLayoutDelegate> delegate;@end
  • 設(shè)置通過(guò)可選代理方法獲取屬性值的屬性的默認(rèn)值

    /**默認(rèn)的列數(shù)*/static const NSInteger LYPDefaultColumnCount = 3;/**默認(rèn)每一列之間的間距*/static const CGFloat LYPDefaultColumMargin = 10;/**默認(rèn)每一行之間的間距*/static const CGFloat LYPDefaultRowMargin = 10;/**默認(rèn)邊緣間距*/static const UIEdgeInsets LYPDefaultEdgeInsets = {10, 10, 10, 10};
  • 設(shè)置通過(guò)可選代理方法獲取屬性值的屬性的訪問(wèn)方式若代理提供屬性值,則忽略默認(rèn)值

    - (NSInteger)columnCount{    //判斷代理是否實(shí)現(xiàn)了獲取列數(shù)的可選方法    if ([self.delegate respondsToSelector:@selector(columnCountInWaterFlowLayout:)])    {        //實(shí)現(xiàn),返回通過(guò)代理設(shè)置的列數(shù)        return [self.delegate columnCountInWaterFlowLayout:self];    }    else    {        //為實(shí)現(xiàn),返回默認(rèn)的列數(shù)        return LYPDefaultColumnCount;    }}
    • 注:其他屬性值的獲取與上述方法幾乎完全相同,不再贅述
  • 設(shè)置布局

    • 設(shè)置需要的成員屬性

      /**所有cell的布局屬性*/@property (nonatomic, strong) NSMutableArray *attrsArray;/**所有列的當(dāng)前高度*/@property (nonatomic, strong) NSMutableArray *columnHeights;
    • 通過(guò)懶加載的方式初始化成員屬性

      /**--attrsArray--懶加載*/- (NSMutableArray *)attrsArray{    if (_attrsArray == nil)    {        _attrsArray = [NSMutableArray array];    }    return _attrsArray;}/**--columnHeights--懶加載*/- (NSMutableArray *)columnHeights{    if (_columnHeights == nil)    {        _columnHeights = [NSMutableArray array];    }    return _columnHeights;}
    • 初始化布局

      - (void)prepareLayout{    [super prepareLayout];    /**清除之前跟布局相關(guān)的所有屬性,重新設(shè)置新的布局*/    //清除之前計(jì)算的所有列的高度    [self.columnHeights removeAllObjects];    //設(shè)置所有列的初始高度    for (NSInteger i = 0; i<self.columnCount; i++)    {        self.columnHeights[i] = @(self.edgeInsets.top);    }    //清除之前所有的布局屬性    [self.attrsArray removeAllObjects];    /**開(kāi)始創(chuàng)建每一個(gè)cell對(duì)應(yīng)的布局屬性*/    NSInteger count = [self.collectionView numberOfItemsInSection:0];    for (NSInteger i = 0; i<count; i++)    {        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];        //獲取indexPath位置cell對(duì)應(yīng)的布局屬性        UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];        //將indexPath位置的cell的布局屬性添加到所有cell的布局屬性數(shù)組中        [self.attrsArray addObject:attrs];    }}
    • 返回包含所有cell的布局屬性的數(shù)組

      - (nullable NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{    return self.attrsArray;}
    • 設(shè)置每一個(gè)cell的布局屬性

      - (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(nonnull NSIndexPath *)indexPath{    //獲取indexPath位置的布局屬性    UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];    /**設(shè)置cell布局屬性的frame*/    /***確定cell的尺寸***/    //獲取collectionView的寬度    CGFloat collectionViewWidth = self.collectionView.frame.size.width;    //cell寬度    CGFloat width = ((collectionViewWidth - self.edgeInsets.left - self.edgeInsets.right - (self.columnCount - 1) * self.columMargin)) / self.columnCount;    //cell高度    CGFloat height = [self.delegate waterFlowLayout:self heightForItemAtIndex:indexPath.item itemWith:width];    /***設(shè)置cell的位置***/    NSInteger destColumn = 0;    CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];    for (NSInteger i = 1; i<self.columnCount; i++)    {        CGFloat columnHeight = [self.columnHeights[i] doubleValue];        if (minColumnHeight > columnHeight)        {            minColumnHeight = columnHeight;            destColumn = i;        }    }    //計(jì)算cell的位置    CGFloat x = self.edgeInsets.left + destColumn * (width + self.columMargin);    CGFloat y = minColumnHeight;    //判斷是不是第一行    if (y != self.edgeInsets.top)    {        //若不是第一行,需要加上行間距        y += self.rowMargin;    }    /**給cell的布局屬性的frame賦值*/    attrs.frame = CGRectMake(x, y, width, height);    //更新最短那列的高度    self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame));    /**返回indexPath位置的cell的布局屬性*/    return attrs;}
    • 設(shè)置collectionView內(nèi)容的尺寸

      - (CGSize)collectionViewContentSize{    //獲取最高的那一列的高度    CGFloat maxColumnHeight = [self.columnHeights[0] doubleValue];    for (NSInteger i = 1; i<self.columnCount; i++)    {        CGFloat columnHeight = [self.columnHeights[i] doubleValue];        if (maxColumnHeight < columnHeight)        {            maxColumnHeight = columnHeight;        }    }    //返回collectionView的contentSize,高度為最高的高度加上一個(gè)行間距    return CGSizeMake(0, maxColumnHeight + self.rowMargin);}

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 宜春市| 科技| 诸暨市| 莱芜市| 班玛县| 洞头县| 昌平区| 日喀则市| 政和县| 永仁县| 田林县| 西安市| 北京市| 永宁县| 铜鼓县| 芷江| 安吉县| 丰镇市| 特克斯县| 施秉县| 淮阳县| 河池市| 来凤县| 莱芜市| 浦北县| 泾源县| 鄂托克前旗| 尖扎县| 科技| 高唐县| 拉孜县| 大渡口区| 玉溪市| 公安县| 沽源县| 隆回县| 浪卡子县| 富平县| 双江| 曲阳县| 兰考县|