iOS中如何優(yōu)雅地處理票圈中的九圖

在社交軟件發(fā)達(dá)的今天,朋友圈的出現(xiàn)讓每個(gè)人都能及時(shí)分享自己的生活,分享每時(shí)每刻成為了票圈最吸引人的地方。當(dāng)我們要分享我們的生活時(shí),就需要發(fā)布照片了。

但是,當(dāng)照片的數(shù)量是5張,7張或者8張的時(shí)候,這就會(huì)顯得非常尷尬了(這也是為什么很少有人發(fā)這個(gè)數(shù)量的票圈)。

作為強(qiáng)迫癥,我相信99%的人都不會(huì)選擇發(fā)這么尷尬的數(shù)量,要么寧愿少發(fā)點(diǎn),要么就湊多幾張。

現(xiàn)在,強(qiáng)迫癥的福利來了!你將會(huì)看到這樣的布局!這樣的布局是不是即使遇上了五張或者七張這種尷尬的數(shù)量,也不會(huì)尷尬呢,嘻嘻~

下面來看看這個(gè)功能在iOS端是怎么實(shí)現(xiàn)的吧~

一.設(shè)計(jì)思路

單個(gè)票圈的布局中,一個(gè)Controller包括了很多個(gè)Cell,比如用戶昵稱Cell、圖片Cell、評(píng)論點(diǎn)贊Cell等等,今天最主要設(shè)計(jì)的是圖片的InfoCell。

二.各層設(shè)計(jì)

1. InfoCell

先來講講InfoCell是怎么設(shè)計(jì)的,因?yàn)檫@一層是核心,決定了整個(gè)圖片的大小、位置等等。

首先,InfoCell采用UICollectionView來設(shè)計(jì),這是因?yàn)?code>UICollectionView更易于調(diào)整整個(gè)section的大小、布局等等。

在設(shè)計(jì)思路來說,InfoCell最重要的是需要根據(jù)自身的大小去決定每一個(gè)圖片的大小。

比如說五圖里面,前兩個(gè)和后三個(gè)大小就很不一樣,這時(shí)候就需要將他們分為兩個(gè)part來討論,5=2+3,7=3+4,而其他情況則可以直接按照原來的大小來設(shè)置:

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    if (self.colorArray.count == 5 || self.colorArray.count == 7)
        return 2;
    else
        return 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    if (self.colorArray.count == 5) {
        if (section == 0)
            return 2;
        else
            return 3;
    }
    else if (self.colorArray.count == 7) {
        if (section == 0)
            return 3;
        else
            return 4;
    }
    else
        return self.colorArray.count;
}

設(shè)置完Cell的數(shù)量之后,記得按情況獲得每一個(gè)Cell的內(nèi)容,還是要分情況討論:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    HobenNinePhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier: HobenNinePhotoID forIndexPath: indexPath];
    
    NSInteger currentItem = 0;
    if (self.colorArray.count == 5)
        currentItem = 2 * indexPath.section + indexPath.item;
    else if (self.colorArray.count == 7)
        currentItem = 3 * indexPath.section + indexPath.item;
    else
        currentItem = indexPath.item;
    
    [cell setColor: [self.colorArray objectAtIndex: currentItem]];
    
    return cell;
}

好的,最關(guān)鍵的地方來了,如何獲得Cell的高寬的問題,這里我采用的是根據(jù)自身屏幕的寬度,按照比例、間距等關(guān)系來等比獲取,即:

每個(gè)Cell的高寬 = (屏幕寬度 - 間距寬度 * 間距數(shù)量) / (Cell的數(shù)量)

又由于5張和7張有兩種size,因此,5張的前兩張是一種高度,后三張又是另外一種高度,7張同理,即可得到以下關(guān)系:

(kHobenNinePhotoViewSpacing即每個(gè)Cell之間的間距,這里取了5.f)

+ (CGFloat) getImageWidthWithWidth:(CGFloat)width index:(NSInteger)i count:(NSInteger) cnt {
    CGFloat spacing = kHobenNinePhotoViewSpacing;
    if (cnt == 2) {
        return (width - spacing) / 2;
    } else if (cnt % 3 == 0 || cnt == 4) {
        return (width - 2 * spacing) / 3;
    } else if (cnt == 8) {
        return (width - 3 * spacing) / 4;
    } else if (cnt == 5) {
        if (i <= 1) {
            return (width - spacing) / 2;
        } else {
            return (width - 2 * spacing) / 3;
        }
    } else if (cnt == 7) {
        if (i <= 2) {
            return (width - 2 * spacing) / 3;
        } else {
            return (width - 3 * spacing) / 4;
        }
    } else
        return 200.f;
}

在設(shè)置size的函數(shù)直接調(diào)用這個(gè)函數(shù)獲取高寬就OK了:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    NSInteger currentItem = 0;
    if (self.colorArray.count == 5)
        currentItem = 2 * indexPath.section + indexPath.item;
    else if (self.colorArray.count == 7)
        currentItem = 3 * indexPath.section + indexPath.item;
    else
        currentItem = indexPath.item;

    CGFloat width = [HobenNinePhotoView getImageWidthWithWidth: self.frame.size.width index: currentItem count: self.colorArray.count];
    
    return CGSizeMake(width, width);
}

由于5張和7張的情況是分成了兩個(gè)部分的,因此,還需要調(diào)用UICollectionViewDelegateFlowLayout的委托來設(shè)置兩個(gè)部分之間的間距:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(0, 0, kHobenNinePhotoViewSpacing, 0);
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
    return kHobenNinePhotoViewSpacing;
}

最后,初始化InfoCell中的CollectionView,記得注冊(cè)什么的:

- (UICollectionView *)ninePhotoView {
    if (!_ninePhotoView) {
        _ninePhotoView = ({
            UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
            [layout setMinimumLineSpacing:2.f];
            [layout setMinimumInteritemSpacing:2.f];
            [layout setScrollDirection:UICollectionViewScrollDirectionVertical];
            [layout setSectionInset:UIEdgeInsetsZero];
            UICollectionView *view = [[UICollectionView alloc] initWithFrame: self.bounds
                                                        collectionViewLayout: layout];
            view.dataSource = self;
            view.delegate = self;
            view.alwaysBounceVertical = YES;
            view.scrollEnabled = NO;
            view.backgroundColor = [UIColor clearColor];
            [view registerClass: [HobenNinePhotoCell class] forCellWithReuseIdentifier: HobenNinePhotoID];
            view;
        });
    }
    return _ninePhotoView;
}

2. PhotoCell

PhotoCell即票圈布局里面的每一個(gè)照片,這時(shí)候,其實(shí)只要適配InfoCell給他設(shè)置好的高寬,還有內(nèi)容就OK了:

- (void)layoutSubviews {
    [self.gridView mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.size.equalTo(self);
        make.top.equalTo(self);
        make.left.equalTo(self);
    }];
}

- (void) setColor:(UIColor *)color {
    self.gridView.backgroundColor = color;
}

3.Controller

Controller里面包含InfoCell,是用UITableView來包含的,但是如何獲得每一個(gè)TableView的高度是一個(gè)難題,因?yàn)槊恳环N布局里面的高度都是不固定的,如果計(jì)算高度發(fā)生錯(cuò)誤,就會(huì)導(dǎo)致整個(gè)布局出現(xiàn)bug!

先初始化,設(shè)置委托,注冊(cè)一下:

- (UITableView *)infoView {
    if (!_infoView) {
        _infoView = ({
            UITableView *tableView = [[UITableView alloc] initWithFrame: CGRectMake(0, 0,
                                                                               self.view.frame.size.width,
                                                                               self.view.frame.size.height)];
            [tableView registerClass: [HobenInfoCell class] forCellReuseIdentifier: HobenInfoCellID];
            tableView.delegate = self;
            tableView.dataSource = self;
            tableView;
        });
    }
    return _infoView;
}

這里的TableView就不用像Cell里面的CollectionView一樣要分區(qū)處理了,直接按照數(shù)組數(shù)量來搞定!

#pragma mark - <UITableViewDelegate>
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.colorArrayArray.count;
}

好的,又是一個(gè)關(guān)鍵的地方,怎么獲得高度?這是一個(gè)值得思考的地方,想想之前是怎么獲得的?參考一下,就可以知道,由于:

高度=寬度

每個(gè)Cell的高度 = (屏幕寬度 - 間距寬度 * 間距數(shù)量) / (Cell的數(shù)量)

TableView高度 = 每行Cell的高度之和

因?yàn)?張和7張比較特殊,上面一層的高度和下面一層的高度是不一致的,因此還是要分別加一下,而其他情況則可以直接用行數(shù)來獲得:

+ (CGFloat) heightWithWidth: (CGFloat) width colorArray: (NSArray *) colorArray {
    CGFloat imageHeight = 0.f;
    if(colorArray.count > 1) {
        if (colorArray.count == 2) {
            imageHeight = (width - kHobenNinePhotoViewSpacing) / 2;
        } else if (colorArray.count % 3 == 0) {
            NSInteger imageLine = colorArray.count / 3;
            imageHeight = imageLine * ((width - 2 * kHobenNinePhotoViewSpacing) / 3 + kHobenNinePhotoViewSpacing);
        } else if (colorArray.count == 4) {
            imageHeight = 2 * width / 3;
        } else if (colorArray.count == 5) {
            imageHeight = (width - kHobenNinePhotoViewSpacing) / 2 + (width - 2 * kHobenNinePhotoViewSpacing) / 3 + kHobenNinePhotoViewSpacing;
        } else if (colorArray.count == 7) {
            imageHeight = (width - 2 * kHobenNinePhotoViewSpacing) / 3 + (width - 3 * kHobenNinePhotoViewSpacing) / 4 + kHobenNinePhotoViewSpacing;
        } else if (colorArray.count == 8) {
            imageHeight = 2 * (width - 3 * kHobenNinePhotoViewSpacing) / 4 + kHobenNinePhotoViewSpacing;
        }
    }
    else {
        return 200.f;
    }
    return imageHeight;
}

在TableView高度確定中調(diào)用這個(gè)函數(shù)就OK啦!

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    CGFloat height = [HobenNinePhotoView heightWithWidth: self.view.frame.size.width - 20 colorArray: self.colorArrayArray[indexPath.item]];
    return height + 20.f;
}

4.數(shù)據(jù)的傳遞

最后特別說一下數(shù)據(jù)的傳遞過程,在demo中,數(shù)據(jù)源的產(chǎn)生在Controller層,那么如何精確地傳遞給PhotoCell呢?跟著我的思路,來看看從數(shù)據(jù)的創(chuàng)建到數(shù)據(jù)的傳遞吧!

在Controller層先建立一坨坨顏色:

- (NSMutableArray *)colorArrayArray {
    if (!_colorArrayArray) {
        _colorArrayArray = ({
            NSMutableArray *arrays = [[NSMutableArray alloc] init];
            UIColor *black = [UIColor blackColor];
            UIColor *yellow = [UIColor yellowColor];
            UIColor *red = [UIColor redColor];
            UIColor *green = [UIColor greenColor];
            UIColor *gray = [UIColor grayColor];
            UIColor *orange = [UIColor orangeColor];
            UIColor *darkGray = [UIColor darkGrayColor];
            UIColor *brown = [UIColor brownColor];
            UIColor *blue = [UIColor blueColor];
            
            NSArray *totalColorArray = @[black, yellow, red, green, gray, orange, darkGray, brown, blue];
            
            for (int i = 1; i <= 9; i++) {
                NSArray *array = [totalColorArray subarrayWithRange: NSMakeRange(0, i)];
                [arrays addObject: array];
            }
            arrays;
        });
    };
    return _colorArrayArray;
}

沒錯(cuò),他叫colorArrayArray,因?yàn)樗菙?shù)組的數(shù)組,即[[1], [1,2], [1, 2, 3]...],在TableView里面?zhèn)鬟f給每一個(gè)Cell的時(shí)候,就取出其中一個(gè)數(shù)組,傳遞下去:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    HobenInfoCell *cell = [tableView dequeueReusableCellWithIdentifier: HobenInfoCellID forIndexPath: indexPath];
    [cell setColorArray: self.colorArrayArray[indexPath.item]];
    return cell;
}

好的,數(shù)組的數(shù)組拆成了一個(gè)個(gè)數(shù)組,進(jìn)入了InfoCell層,InfoCell再把得到的數(shù)組傳給自己的CollectionView(記得reload):

- (void)setColorArray:(NSArray *)colorArray {
    if (_colorArray != colorArray) {
        _colorArray = colorArray;
        [self.ninePhotoView reloadData];
    }
}

CollectionView獲得了數(shù)組之后,就可以把它傳給PhotoCell啦!

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    HobenNinePhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier: HobenNinePhotoID forIndexPath: indexPath];
    
    NSInteger currentItem = 0;
    if (self.colorArray.count == 5)
        currentItem = 2 * indexPath.section + indexPath.item;
    else if (self.colorArray.count == 7)
        currentItem = 3 * indexPath.section + indexPath.item;
    else
        currentItem = indexPath.item;
    
    [cell setColor: [self.colorArray objectAtIndex: currentItem]];
    
    return cell;
}

最后在PhotoCell中,根據(jù)獲得的顏色,來設(shè)置自身的背景就大功告成啦!

- (void) setColor:(UIColor *)color {
    self.gridView.backgroundColor = color;
}

5.效果圖

6.Demo地址

我的Demo地址在這里,歡迎各位路過的爺給個(gè)star~ 嘻嘻

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容