1. 程式人生 > >iOS之UICollectionView自定義佈局

iOS之UICollectionView自定義佈局

UICollectionView基礎

  • UICollectionViewFlowLayout:檢視佈局物件(流水佈局:一行排滿,自動排到下行),繼承自UICollectionViewLayout。UICollectionViewLayout內有一個collectionView屬性,所有的檢視佈局物件都繼承自UICollectionViewLayout。
  • 若我們要自定義佈局物件,我們一般繼承UICollectionViewFlowLayout,然後重寫裡面的一些方法就可以了。
  • 需要實現三個協議;UICollectionViewDataSource(資料來源)、UICollectionViewDelegateFlowLayout(檢視佈局),自定義佈局需要實現UICollectionViewDataSource、UICollectionViewDelegate兩個協議即可。

一、自定義線性佈局

  • 首先要繼承與流水佈局UICollectionViewFlowLayout
#import <UIKit/UIKit.h>

@interface LineCollectionViewLayout : UICollectionViewFlowLayout

@end
  • 重寫相應的方法
#import "LineCollectionViewLayout.h"

@implementation LineCollectionViewLayout

- (instancetype)init{
    if (self = [super init]) {
    }
    return
self; } /** * 用來做佈局的初始化操作(不建議在init方法中進行佈局的初始化操作) - 注意:一定要呼叫[super prepareLayout] */ - (void)prepareLayout{ [super prepareLayout]; // 水平滾動 self.scrollDirection = UICollectionViewScrollDirectionHorizontal; // 設定內邊距 CGFloat inset = (self.collectionView.frame.size.width - self.itemSize.width) * 0.5
; self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset); } /** * 這個方法的返回值是一個數組(數組裡面存放著rect範圍內所有元素的佈局屬性) * 這個陣列中存放的都是UICollectionViewLayoutAttributes物件 * 這個方法的返回值決定了rect範圍內所有元素的排布(frame)*/ /** UICollectionViewLayoutAttributes *attrs; 1.一個cell對應一個UICollectionViewLayoutAttributes物件 2.UICollectionViewLayoutAttributes物件決定了cell的frame */ - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{ // 獲得super已經計算好的佈局屬性 NSArray *array = [super layoutAttributesForElementsInRect:rect]; // 計算collectionView最中心點的x值 CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5; // 在原有佈局屬性的基礎上,進行微調 for (UICollectionViewLayoutAttributes *attrs in array) { // cell的中心點x 和 collectionView最中心點的x值 的間距 CGFloat delta = ABS(attrs.center.x - centerX); // 根據間距值 計算 cell的縮放比例 CGFloat scale = 1 - delta / self.collectionView.frame.size.width; // 設定縮放比例 attrs.transform = CGAffineTransformMakeScale(scale, scale); } return array; } /** * 當collectionView的顯示範圍發生改變的時候,是否需要重新重新整理佈局 * 一旦重新重新整理佈局,就會重新呼叫下面的方法: 1.prepareLayout 2.layoutAttributesForElementsInRect:方法 */ - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{ return YES; } /** * 這個方法的返回值,就決定了collectionView停止滾動時的偏移量 * proposedContentOffset:原本情況下,collectionView停止滾動時最終的偏移量 * velocity:滾動速率,通過這個引數可以瞭解滾動的方向 */ - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity{ // 計算出最終顯示的矩形框 CGRect rect; rect.origin.y = 0; rect.origin.x = proposedContentOffset.x; rect.size = self.collectionView.frame.size; // 獲得super已經計算好的佈局屬性 NSArray *array = [super layoutAttributesForElementsInRect:rect]; // 計算collectionView最中心點的x值 CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5; // 存放最小的間距值 CGFloat minDelta = MAXFLOAT; for (UICollectionViewLayoutAttributes *attrs in array) { if (ABS(minDelta) > ABS(attrs.center.x - centerX)) { minDelta = attrs.center.x - centerX; } } // 修改原有的偏移量 proposedContentOffset.x += minDelta; return proposedContentOffset; } @end

自定義環形佈局

  • 同樣要繼承與流水佈局UICollectionViewFlowLayout
#import <UIKit/UIKit.h>

@interface CircleCollectionViewLayout : UICollectionViewFlowLayout

@end
  • 重寫相應的方法
#import "CircleCollectionViewLayout.h"

@interface CircleCollectionViewLayout()
/** 佈局屬性 */
@property (nonatomic, strong) NSMutableArray *attrsArray;
@end

@implementation CircleCollectionViewLayout

/** 懶載入 */
- (NSMutableArray *)attrsArray
{
    if (!_attrsArray) {
        _attrsArray = [NSMutableArray array];
    }
    return _attrsArray;
}

- (void)prepareLayout
{
    [super prepareLayout];

    [self.attrsArray removeAllObjects];

    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    for (int i = 0; i < count; i++) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];
        [self.attrsArray addObject:attrs];
    }
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    return self.attrsArray;
}

/**
 * 這個方法需要返回indexPath位置對應cell的佈局屬性
 */
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    CGFloat radius = 70;
    // 圓心的位置
    CGFloat oX = self.collectionView.frame.size.width * 0.5;
    CGFloat oY = self.collectionView.frame.size.height * 0.5;

    UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

    attrs.size = CGSizeMake(50, 50);
    if (count == 1) {
        attrs.center = CGPointMake(oX, oY);
    } else {
        CGFloat angle = (2 * M_PI / count) * indexPath.item;
        CGFloat centerX = oX + radius * sin(angle);
        CGFloat centerY = oY + radius * cos(angle);
        attrs.center = CGPointMake(centerX, centerY);
    }

    return attrs;
}

@end

對自定義佈局的使用

 // 建立佈局
    CircleCollectionViewLayout *layout = [[CircleCollectionViewLayout alloc] init];

    // 建立CollectionView
    CGFloat collectionW = self.view.frame.size.width;
    CGFloat collectionH = 200;
    CGRect frame = CGRectMake(0, 150, collectionW, collectionH);
    UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:frame collectionViewLayout:layout];
    collectionView.dataSource = self;
    collectionView.delegate = self;
    [self.view addSubview:collectionView];
    self.collectionView = collectionView;

    // 註冊
    [collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([PhotoCell class]) bundle:nil] forCellWithReuseIdentifier:photoId];
 ```   
- ****增加 touchesBegan:方法,通過點選讓兩種佈局相互轉換****

```objc
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if ([self.collectionView.collectionViewLayout isKindOfClass:[LineCollectionViewLayout class]]) {
        [self.collectionView setCollectionViewLayout:[[CircleCollectionViewLayout alloc] init] animated:YES];
    } else {
        LineCollectionViewLayout *layout = [[LineCollectionViewLayout alloc] init];
        layout.itemSize = CGSizeMake(100, 100);
        [self.collectionView setCollectionViewLayout:layout animated:YES];
    }
}

相關推薦

iOSUICollectionView定義佈局

UICollectionView基礎 UICollectionViewFlowLayout:檢視佈局物件(流水佈局:一行排滿,自動排到下行),繼承自UICollectionViewLayout。UICollectionViewLayout內有一個collec

iOS開發窺探UICollectionViewController(三) :使用UICollectionView定義瀑布流

上篇部落格的例項是自帶的UICollectionViewDelegateFlowLayout佈局基礎上來做的Demo, 詳情請看《iOS開發之窺探UICollectionViewController(二) –詳解CollectionView各種回撥》。UICollectionV

iOSUICollectionView自己定義Layout蜂窩布局

with top http reserve src 布局 step object .com 網上的UICollectionView的Layout布局,其cell的形狀多為矩形和圓形。 本篇博文將正六邊形作為cell的基本形狀,為您展現獨特的蜂窩布局效果及實現源代碼。 幫

Android學習筆記為Dialog定義佈局,並說明空指標問題

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Android 定義佈局(繼承控制元件)

就是繼承已有的控制元件,建立新控制元件,保留繼承的父控制元件的特性,並且還可以引入新特性。下面就以支援橫向滑動刪除列表項的自定義ListView的實現來介紹。 1、建立刪除按鈕佈局delete_btn.xml,這個佈局是在橫向滑動列表項後顯示的: <?xml version="1.0" en

定義ViewGroup定義佈局的實現

圖片預覽 1. 分析 1. 自定義簡易FrameLayout 分別左上,右上,左下,右下4個子View 2. 自定義簡易LinearLayout,實現橫向和縱向佈局 3. 自定義簡易RelativeLayout,實現layout_alignParen

iOS開發Xcode定義程式碼塊遷移

本文介紹了程式碼塊遷移的過程. 背景:由於最近換了新的mac,所以,要做自定義程式碼塊的遷移. 一.Xcode中的程式碼塊. 二.開啟 Finder,快捷鍵Command +

iOS開發UITableView定義Header檢視和定義Footer檢視

//自定義Header檢視 - (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInte

UICollectionView定義佈局

UICollectionView控制元件的使用一般會在特殊的介面處理上,但是也有比較規矩的應用軟體會用UICollectionView。例如效果如下的介面; 下面開始講述我的介面是如何做的。 1.首先我會把介面分成5個section,這就需要上篇文章講述

JEPLUSAPP定義插件——JEPLUS軟件快速開發平臺

otto fff 使用 jid editor style img circle ckeditor JEPLUS之APP自定義插件 在JEPLUS中我們可以創建APP,但是創建的APP都是依賴於平臺功能在我們業務中有些需求並不是都要按照平臺

數據庫系列mysql 定義函數function,函數和存儲過程的區別

0.11 必須 def cte fec return語句 cit 新的 too mysql 自定義函數function,函數和存儲過程的區別 https://blog.csdn.net/u010365819/article/details/80470448 1.MySQL自

Log4Net 定義屬性記錄到文件中 (三)

hive days bsp 文本 處理 message homepage layout backup 即解決了將自定義屬性記錄到數據庫之後。一個新的想法冒了出來,自定義屬性同樣也能記錄到文件中嗎?答案是肯定的,因為Log4Net既然已經考慮到了數據庫記錄方式,當然也一定考慮

小程式學習旅----定義元件toast例項

components目錄下新建資料夾toast,新建component,之後修改toast.js和toast.wxml <!--components/toast/toast.wxml--> <view class='wx_toast_container' hidden="{{!

非常實用的定義佈局定義顯示時長的頂部toast

最近在工作中需要彈出頂部toast且顯示時間不固定。從而寫了下面的一個模擬toast的動畫: 先看動畫: public void isShowToast(final boolean isShow,View mToastV) { final int marinTop = 0;//距離頂

009-Ambari二次開發新增定義元件Redis(二)

上一篇我們主要介紹了Ambari新增元件的答題流程並以REDIS為例說明了流程,本篇在上一篇的基礎上,進一步完善說明流程並介紹如何給元件新增metric 掃描二維碼,關注BearData,獲取最新文章 上篇中,我們已經制作出了redis的rpm包,並重新編譯了我們修改後的Ambar

008-Ambari二次開發新增定義元件Redis(一)

Ambari目前支援的元件有HDFS、YARN、HBase、Hive、Pig、ZooKeeper、Sqoop、Storm、Flume、Tez、Oozie、Falcon、Storm、Altas、Knox、Spark、Ranger、Mahout、Kerberos等,已經涵蓋了從大資料應用的

車機開發新增定義

S700平臺即安卓5.1.1系統新增額外的自定義鍵值按鍵: 在Android的原生系統中鍵值預設情況下是92個,從0-91;一般情況下,這些鍵值是夠用的,但是如果想擴充的話,還是需要新增新的鍵值的;像我們做車機專案的,新增新按鍵鍵值太易見了,比如將倒車檢測做成新自定義鍵值按鍵,我們需要到多個

javawebEL定義函式

1.什麼是EL自定義函式 EL自定義函式是在EL表示式中呼叫的某個java類的靜態方法,這個靜態方法需在web應用程式中進行配置才可以被EL表示式呼叫。EL自定義函式可以擴充套件EL表示式的功能,讓EL表示式完成普通java程式程式碼所能完成的功能。 2.EL自定義函式開發步驟 編寫EL自定義函式

Xamarin定義佈局系列——瀑布流佈局

原文: Xamarin自定義佈局系列——瀑布流佈局 Xamarin.Forms以Xamarin.Android和Xamarin.iOS等為基礎,自己實現了一整套比較完整的UI框架,包含了絕大多數常用的控制元件,如下圖 雖然XF(Xamarin.Forms簡稱XF,下同)為我們提供大這麼多的控制元件,但在

Xamarin定義佈局系列——ListView的一個定義實現ItemsControl(橫向列表)

原文: Xamarin自定義佈局系列——ListView的一個自定義實現ItemsControl(橫向列表) 在以前寫UWP程式的時候,瞭解到在ListView或者ListBox這類的列表空間中,有一個叫做ItemsPannel的屬性,它是所有列表中子元素實際的容器,如果要讓列表進行橫向排列,只需要在Xam