自定义流布局

一、自定义布局【相册】

需求:

1.横向滚动

2.照片离中心点越近图片越大,即图片的放大和缩小

3.滚动停止时候总有一张照片居中显示

1、自定义布局 - 继承自UICollectionViewFlowLayout

重写prepareLayout方法

作用:在这个方法中做一些初始化的操作

注意:一定要调用[super prepareLayout]方法

2、重写layoutAttributesForElementsInRect:方法

作用 :

这个方法的返回值是个数组

这个数组中存放着的都是UICollectionViewLayoutAttribute对象

  (1)一个cell对应一个UICollectionViewLayoutAttributes对象

  (2)UICollectionViewLayoutAttribute对象决定了Cell的排布方式(frame)

3、重写shouldInvalidateLayoutForBoundsChange方法

作用 如果返回YES,那么CollectionView显示的范围发生改变的时候,就会重新刷新布局

一旦重新刷新布局,就会按顺序调用下面的方法:

prepareLayout

layoutAttributesForElementsInRect:

4、重写targetContentOffsetForProposedContentOffset:withScrollingVelocity:方法

-作用 返回值决定了collectionView停止滚动时最终的偏移量(contentOffset)

-参数:

-proposedContentOffset:原本情况下,collectionView停止滚动时最终的偏移量

-velocity:滚动速率,通过这个参数可以了解滚动的方向

#import "ViewController.h"
#import "WXPhotoCell.h"
#import "WXLineLayout.h"

@interface ViewController ()<UICollectionViewDelegate,UICollectionViewDataSource>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    //创建布局
    WXLineLayout *layout = [[WXLineLayout alloc]init];
    layout.itemSize = CGSizeMake(150, 150);

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

    //注册
    [WXCollectionView registerNib:[UINib nibWithNibName:NSStringFromClass([WXPhotoCell class]) bundle:nil] forCellWithReuseIdentifier:@"photoCell"];

}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
    return 5;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    WXPhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"photoCell" forIndexPath:indexPath];
    if (!cell) {
        cell = [[WXPhotoCell alloc]init];
    }
    cell.imageName = [NSString stringWithFormat:@"%zd",indexPath.item+1];
    return cell;
}

自定义布局WXLineLayout继承自UICollectionViewFlowLayout

缩放计算

算出collectionView和cell 中心点的间距

ABS(a-b)//取绝对值

//
//  WXLineLayout.m
//  自定义流布局
//
//  Created by wangxu on 16/7/9.
//  Copyright © 2016年 Somebody. All rights reserved.
//

#import "WXLineLayout.h"

@implementation WXLineLayout

- (instancetype)init{
    if (self = [super init]) {

    }
    return self;
}
/*
 当collectionView的显示范围发生改变的时候,是否需要重新刷新布局
 一旦重新刷新布局,就会调用下面两个方法
 1.prepareLayout
 2.layoutAttributesForElementsInRect:方法
 */
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{

    return YES;
}
//用来做布局的初始化操作(不建议在init方法中进行布局的初始化操作)
- (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);
}
/*
 UICollectionViewLayoutAttributes *attrs;
 1.一个cell对应一个UICollectionViewLayoutAttributes对象
 2.UICollectionViewLayoutAttributes对象决定了Cell的frame
 */
/*
 这个方法的返回值是一个数组,(数组里存放着rect范围内所有元素的布局属性)
 这个方法的返回值决定了rect范围内所有元素的排布(frame)
 */
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{

    NSLog(@"=======");
    //获取super已经计算好的布局属性
    NSArray * array = [super layoutAttributesForElementsInRect:rect];

    //计算collectionView最中心的X值
    CGFloat collectionCenterX = self.collectionView.contentOffset.x+self.collectionView.frame.size.width * 0.5;
    //在原有布局的基础上,进行微调
    for (UICollectionViewLayoutAttributes *attrs in array) {
        //计算cell中心点X值
        CGFloat cellX = attrs.center.x;
        //计算collectionView中心点X值和Cell中心点X值间的距离
        CGFloat delta = ABS(cellX-collectionCenterX);

        //根据间距计算 cell的缩放比例
        CGFloat scale = 1 - delta/self.collectionView.frame.size.width;
        //设置缩放比例
        attrs.transform = CGAffineTransformMakeScale(scale, scale);
    }
    return array;
}
/*
 这个方法的返回值,决定了colletionView停止滚动时的偏移量
 */
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity{

    //计算出最终显示的矩形框
    CGRect rect;
    rect.origin.x = proposedContentOffset.x;
    rect.origin.y = 0;
    rect.size = self.collectionView.frame.size;

    //获取滚动结束后super已经计算好的布局属性
    NSArray *array = [super layoutAttributesForElementsInRect:rect];
    //计算collectionView最中心点的X值
    CGFloat collectionCenterX = self.collectionView.frame.size.width*0.5 + proposedContentOffset.x;
    //存放最小的间距
    CGFloat minDelta = MAXFLOAT;
    for (UICollectionViewLayoutAttributes *attrs in array) {
        if (ABS(minDelta)>ABS(attrs.center.x-collectionCenterX)) {
            minDelta = attrs.center.x-collectionCenterX;
        }
    }
    //修改原有的偏移量
    proposedContentOffset.x+=minDelta;
    return proposedContentOffset;
}

@end

自定义UICollectionViewCell

//
//  WXPhotoCell.h
//  自定义流布局
//
//  Created by wangxu on 16/7/9.
//  Copyright © 2016年 Somebody. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface WXPhotoCell : UICollectionViewCell
/** 图片名*/
@property (nonatomic, copy) NSString *imageName;
@end
//
//  WXPhotoCell.m
//  自定义流布局
//
//  Created by wangxu on 16/7/9.
//  Copyright © 2016年 Somebody. All rights reserved.
//

#import "WXPhotoCell.h"
@interface WXPhotoCell ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;

@end
@implementation WXPhotoCell

- (void)awakeFromNib {
    [super awakeFromNib];
    //设置照片的白色边框
    self.imageView.layer.borderWidth = 5;
    self.imageView.layer.borderColor = [UIColor whiteColor].CGColor;
}
- (void)setImageName:(NSString *)imageName{

    //设置cell的图片
    _imageName = [imageName copy];
    self.imageView.image = [UIImage imageNamed:imageName];
}

@end

          

新手上路,还请大神们多多指教。

致谢MJ老师。

时间: 2024-11-05 20:46:47

自定义流布局的相关文章

android 自定义流布局。实现热门标签。开源库SimpleFlowLayout

前言 实际项目中需要实现一个 热门搜索 的栏目,类似下图: 由于 子项(子view) 中的文字是可变的,一行能显示的 子项 的个数也无法确定.需要支持自动换行和计算位置. 开源类库 我自己写了个 自定义view ,继承自viewGroup, 来实现它,托管到github开源平台. 名称:SimpleFlowLayout 地址:https://github.com/vir56k/SimpleFlowLayout 特点:可以不断添加多个子view,计算位置,自动换行. 类似html中的div标签 适

Subclass UICollectionViewFlowLayout,自定义流布局

需求:为实现第一行显示一个,第二行以后显示两个 方案1:用系统自带的流布局,实现的效果是,若第二行只有一个,则系统默认会居中显示,不是左对齐(如下图),不符合项目要求. 方案2:自定义系统的UICollectionViewFLowLayout,主要代码如下, 只要设置了cell的LayoutAttribute之后,supplementaryView的,用super的 subclass of UICollectionViewFlowLayout - (BOOL)shouldInvalidateLa

自定义流布局(UICollectionViewFlowLayout的基本使用)

最终显示的效果图 思路: 1.UICollection的基本设置,并且创建一个继承自UICollectionViewFlowLayout的类.(不能是UICollectionViewLayout,否则全部都需要自定义) 2.在UICollectionViewFlowLayout类中完成四步 - 1)调用prepareLayout方法进行基本的布局(cell在最左面的时候是在正中间),不能在init中布局,因为设置collectionView尺寸是在viewDidLoad中,而 init在它之前调

iOS流布局UICollectionView系列四——自定义FlowLayout进行瀑布流布局

iOS流布局UICollectionView系列四--自定义FlowLayout进行瀑布流布局 一.引言 前几篇博客从UICollectionView的基础应用到设置UICollectionViewFlowLayout更加灵活的进行布局,但都限制在系统为我们准备好的布局框架中,还是有一些局限性,例如,如果我要进行瀑布流似的不定高布局,前面的方法就很难满足我们的需求了,如下: 这种布局无疑在app的应用中更加广泛,商品的展示,书架书目的展示,都会倾向于采用这样的布局方式,当然,通过自定义FlowL

iOS:UICollectionView纯自定义的布局:瀑布流布局

创建瀑布流有三种方式: 第一种方式:在一个ScrollView里面放入三个单元格高度一样的tableView,禁止tableView滚动,只需让tableView随着ScrollView滚动即可.这种方式太奇葩,不太推荐使用... 第二种方式:在一个ScrollView里面从左到右依次放入三个UIView,当ScrollView滚动时,如果之前的三个view消失就将它们存入自定义的缓冲池,即数组中,下拉时再从数组中取出这三个view放到之前三个view位置的下面.但是,切记,每次要依次计算补全最

在流布局里面动态添加自定义控件,通过简单的按钮分页技术

由于最近没什么事情,一直在看java基础,前几天接到上级的任务,得作出一个门禁系统的cs界面出来,能够实现分页,数据绑定需求如下图 看到这里,因为我基本没接触过cs的东西,一时间只有两三个思路,第一个思路是:自定义控件+panle控件(最终感觉行不通没有去做) 第二个思路是:自定义控件+DataGridView控件,尝试了几天,感觉方法有点繁琐,而且不一定能实现这种效果: 第三个思路是:自定义控件+流布局+自动生成.最终我通过第三种方法做出来了: 第四个思路是:wcf 只是有这个思路,还没有去实

iOS流布局UICollectionView系列六——将布局从平面应用到空间

iOS流布局UICollectionView系列六--将布局从平面应用到空间 一.引言 前面,我们将布局由线性的瀑布流布局扩展到了圆环布局,这使我们使用UICollectionView的布局思路大大迈进了一步,这次,我们玩的更加炫一些,想办法将布局应用的空间,你是否还记得,在管理布局的item的具体属性的类UICollectionViewLayoutAttributrs类中,有transform3D这个属性,通过这个属性的设置,我们真的可以在空间的坐标系中进行布局设计.iOS系统的控件中,也并非

iOS开发之窥探UICollectionViewController(四) --一款功能强大的自定义瀑布流

在上一篇博客中<iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流>,自定义瀑布流的列数,Cell的外边距,Cell的最大以及最小高度是在我们的布局文件中是写死的,换句话说也就是不可配置的.为了循序渐进,由浅入深呢,上篇博客暂且那么写.不过那样写太过死板,本来使用起来比较灵活的自定义布局,如果把其配置参数给写死了,就相当于在笼中的猛兽,再厉害不也白扯蛮. 在今天这篇博客中我们要接着上篇博客中的Demo,使其自定义布局

ANDROID自定义视图——仿瀑布布局(附源码)

简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量--onMeasure():决定View的大小 2.布局--onLayout():决定View在ViewGroup中的位置 3.绘制--onDraw():如何绘制这个View. 第3步的onDraw系统已经封装的很好了,基本不用我们来操心,只需要专注到1,2两个步骤就中好了. 第一步的测量,可以参考:(ANDROID自定义视图--onMeasure,MeasureSpec源码 流程 思路详解) 第二步的布局,可以参考:(AN