如何html 自定义元素CollectionView中每个元素的大小和间距

自定义collectionViewFlowLayout让UICollectionView的item始终优先居左-codexiu.cn
自定义collectionViewFlo
自定义collectionViewFlowLayout让UICollectionView的item始终优先居左
#import &UIKit/UIKit.h&
@interface albumHomeCollectionFlowLayout : UICollectionViewFlowLayout
#import "albumHomeCollectionFlowLayout.h"
@implementation albumHomeCollectionFlowLayout
const NSInteger kMaxCellSpacing = 10;
//让item居左
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray* attributesToReturn = [super layoutAttributesForElementsInRect:rect];
NSArray * array = [[NSArray alloc] initWithArray:attributesToReturn copyItems:YES];
for (UICollectionViewLayoutAttributes* attributes in array) {
if (nil == attributes.representedElementKind) {
NSIndexPath* indexPath = attributes.indexP
attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].
return attributesToR
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes* currentItemAttributes =
[super layoutAttributesForItemAtIndexPath:indexPath];
UIEdgeInsets sectionInset = [(UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout sectionInset];
if (indexPath.item == 0) { // first item of section
CGRect frame = currentItemAttributes.
frame.origin.x = sectionInset. // first item of the section should always be left aligned
currentItemAttributes.frame =
return currentItemA
NSIndexPath* previousIndexPath = [NSIndexPath indexPathForItem:indexPath.item-1 inSection:indexPath.section];
CGRect previousFrame = [self layoutAttributesForItemAtIndexPath:previousIndexPath].
CGFloat previousFrameRightPoint = previousFrame.origin.x + previousFrame.size.width + kMaxCellSpacing *[MSUtil getDeviceScaleX];
CGRect currentFrame = currentItemAttributes.
CGRect strecthedCurrentFrame = CGRectMake(0,
currentFrame.origin.y,
self.collectionView.frame.size.width,
currentFrame.size.height);
if (!CGRectIntersectsRect(previousFrame, strecthedCurrentFrame)) { // if current item is the first item on the line
// the approach here is to take the current frame, left align it to the edge of the view
// then stretch it the width of the collection view, if it intersects with the previous frame then that means it
// is on the same line, otherwise it is on it's own new line
CGRect frame = currentItemAttributes.
frame.origin.x = sectionInset. // first item on the line should always be left aligned
currentItemAttributes.frame =
return currentItemA
CGRect frame = currentItemAttributes.
frame.origin.x = previousFrameRightP
currentItemAttributes.frame =
return currentItemA
好心情才会有好风景,好眼光才会有好发现,好思考才会有好主意。安乐给人予舒适,却又给人予早逝;劳作给人予磨砺,却能给人予长久。人可以不美丽,但要健康;人可以不伟大,但要快乐;人可以不完美,但要追求。
1.&&Openstack Restful API 开发框架 Paste + PasteDeploy + Routes + WebOb
2.&&Openstack liberty 云主机迁移源码分析之静态迁移2
3.&&OpenStack之Neutron源码分析
Neutron-server初始化
4.&&手动安装Openstack Mikita. Keystone安装
5.&&Openstack Nova 源码分析 — Create instances (nova-conductor阶段)
6.&&Devstack单节点环境实战配置
7.&&VMware 接入 Openstack — 使用 Openstack 创建 vCenter 虚拟机
1.&&天天24小时时时更新迅雷共享账号:日免费迅雷会员xunlei-vip 18点00分 发布
2.&&MySQL学习笔记4:操作数据表中的记录(增删改查)
3.&&AnimatedPathView实现自定义图片标签
4.&&Swift基础之集成单选按钮横竖两种样式
5.&&【Linux 系统编程】shell 命令和流程控制(二)
6.&&【Linux 系统编程】shell 脚本基础学习(一)
7.&&【Linux 系统编程】shell 流程控制loop和引号(三)怎么让collectionView大小随item数量改变_百度知道
怎么让collectionView大小随item数量改变
我有更好的答案
Step1:在你的视图控制器头文件中实现UICollectionViewFlowLayout协议eg:@interfaceXXViewController:UICollectionViewController
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。今天看啥 热点:
swift详解之二十三------------UICollectionView基础用法和简单自定义,uicollectionview详解
UICollectionView基础用法和简单自定义
注:本文通过几个实例来讲讲UICollectionView基本用法
本次要实现的两个效果。感谢猫神提供的教程 OneV’s Den
第一个界面是一个普通的流布局 UICollectionViewFlowLayout, 第二个界面是自定义的一个圆形布局。加了点手势操作和动画。老规矩。后面会附上源码
首先来看下基本用法 。
1、UICollectionView基础用法
简单的UICollectionView 相当于GridView ,一个多列的UItableView ,然而UICollectionView 跟UItableView 的操作也非常相似 。都是会设置有一个DataSource 和一个delegate 标准的UICollectionView包含三个部分,它们都是UIView的子类:
cells 单元格用来展示内容的,可以设置所有的大小 也可以指定不同尺寸和不同的内容
Supplementary Views 追加视图 如果你对UITableView比较熟悉的话,可以理解为每个Section的Header或者Footer,用来标记每个section的view
Decoration Views 装饰视图 这是每个section的背景
UICollectionView和UITableView最大的不同就是UICollectionViewLayout,UICollectionViewLayout可以说是UICollectionView的大脑和中枢,它负责了将各个cell、Supplementary View和Decoration Views进行组织,为它们设定各自的属性。包括位置、尺寸、层级、形状等等 。。
Layout决定了UICollectionView是如何显示在界面上的。在展示之前,一般需要生成合适的UICollectionViewLayout子类对象,并将其赋予CollectionView的collectionViewLayout属性
下面我们实现一个最简单的Demo
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionViewScrollDirection.Vertical
layout.itemSize = CGSizeMake(60, 75)
layout.minimumLineSpacing = 10.0
layout.minimumInteritemSpacing = 5.0
layout.headerReferenceSize = CGSizeMake(20, 20)
layout.footerReferenceSize = CGSizeMake(20, 20)
这里创建了基本的流布局
设置了一些基本属性。
然后其他的设置和UITableView差不多
let collect:UICollectionView = UICollectionView(frame: self.view.frame,collectionViewLayout:layout)
collect.backgroundColor = UIColor.whiteColor()
collect.delegate = self
collect.dataSource = self
self.view.addSubview(collect)
因为初始的背景色是黑色的,这里指定了背景色
然后实现下面三个基本的方法,就能正常跑了 。最要是cell的显示方法
//设置分区个数
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -& Int {
//设置每个分区元素个数
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -& Int {
//设置元素内容
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -& UICollectionViewCell {
//这里创建cell
return cell
为了得到高效的View,对于cell的重用是必须的,避免了不断生成和销毁对象的操作,在UICollectionView中使用以下方法进行注册:
:forCellWithReuseIdentifier:
:forSupplementaryViewOfKind:withReuseIdentifier:
:forCellWithReuseIdentifier:
:forSupplementaryViewOfKind:withReuseIdentifier:
先注册 ,使用一个Identifier ,加入重用队列。要是在重用队列里没有可用的cell的话,runtime将自动帮我们生成并初始化一个可用的cell。
我们这里是自己用xib 画了个cell
一个很简单的cell ,把它的class 设置成我们自定义的MyCellContent,MyCellContent 继承自UICollectionViewCell ,把这两个拖成它的成员属性
import UIKit
class MyCellContent: UICollectionViewCell {
var contentImage: UIImageView!
var contentLabel: UILabel!
然后,在我们的视图控制器中的viewDidLoad进行注册
let nib = UINib(nibName: "MyCollectionCell", bundle: NSBundle.mainBundle())
collect.registerNib(nib, forCellWithReuseIdentifier: "DesignViewCell")
然后在cellForItemAtIndexPath 里面就能这样取了
let identify:String = "DesignViewCell"
let cell =collectionView.dequeueReusableCellWithReuseIdentifier(identify, forIndexPath: indexPath) as! MyCellContent
我们事先创建了个结构体,用来存放cell的img和name
struct CellContent{
var img:String
var name:String
然后在控制器中声明了一个var dic = Array&CellContent&()
在viewDidLoad中初始化。
for i in 1...9{
dic.append(CellContent(img: "f"+String(i), name: "歪脖子"+String(i)))
我图片存放的名字就是f1-----f9
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -& Int {
self.dic.count
这里返回元素个数就可以这么写了
//设置元素内容
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -& UICollectionViewCell {
let identify:String = "DesignViewCell"
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(identify, forIndexPath: indexPath) as! MyCellContent
cell.contentView.backgroundColor = UIColor.grayColor()
cell.contentView.alpha = 0.2
let img = UIImage(named: (self.dic[indexPath.row] as CellContent).img)
cell.contentImage.image = img
cell.contentLabel.text = (self.dic[indexPath.row] as CellContent).name
return cell
这个就可以很简单的设置了 。现在运行,第一个页面的效果就有了
但让还有向UITableView中样很多的方法去设置别的,比如单个cell的大小
func collectionView(collectionView: UICollectionView!,
layout collectionViewLayout: UICollectionViewLayout!,
sizeForItemAtIndexPath indexPath: NSIndexPath!) -& CGSize {
return CGSizeMake(150, 150)
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath){
print("点击了第\(indexPath.section) 分区 ,第\(indexPath.row) 个元素")
还有很多,自己慢慢玩吧 。下面看看自定义的
2、自定义UICollectionViewLayout
UICollectionViewLayoutAttributes是一个非常重要的类,先来看看property列表:
@property (nonatomic) CGRect frame
@property (nonatomic) CGPoint center
@property (nonatomic) CGSize size
@property (nonatomic) CATransform3D transform3D
@property (nonatomic) CGFloat alpha
@property (nonatomic) NSInteger zIndex
@property (nonatomic, getter=isHidden) BOOL hidden
可以看到,UICollectionViewLayoutAttributes的实例中包含了诸如边框,中心点,大小,形状,透明度,层次关系和是否隐藏等信息。和DataSource的行为十分类似,当UICollectionView在获取布局时将针对每一个indexPath的部件(包括cell,追加视图和装饰视图),向其上的UICollectionViewLayout实例询问该部件的布局信息,这个布局信息,就以UICollectionViewLayoutAttributes的实例的方式给出。
UICollectionViewLayout的功能为向UICollectionView提供布局信息,不仅包括cell的布局信息,也包括追加视图和装饰视图的布局信息。实现一个自定义layout的常规做法是继承UICollectionViewLayout类,然后重载下列方法:
-(CGSize)collectionViewContentSize
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
-(UICollectionViewLayoutAttributes )layoutAttributesForItemAtIndexPath:(NSIndexPath )indexPath
-(UICollectionViewLayoutAttributes )layoutAttributesForSupplementaryViewOfKind:(NSString )kind atIndexPath:(NSIndexPath *)indexPath
-(UICollectionViewLayoutAttributes * )layoutAttributesForDecorationViewOfKind:(NSString)decorationViewKind atIndexPath:(NSIndexPath )indexPath
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
在初始化一个UICollectionViewLayout实例后,会有一系列准备方法被自动调用,以保证layout实例的正确。
首先,-(void)prepareLayout将被调用,默认下该方法什么没做,但是在自己的子类实现中,一般在该方法中设定一些必要的layout的结构和初始需要的参数等。
之后,-(CGSize) collectionViewContentSize将被调用,以确定collection应该占据的尺寸。注意这里的尺寸不是指可视部分的尺寸,而应该是所有内容所占的尺寸。collectionView的本质是一个scrollView,因此需要这个尺寸来配置滚动行为。
接下来-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect被调用,这个没什么值得多说的。初始的layout的外观将由该方法返回的UICollectionViewLayoutAttributes来决定。
另外,在需要更新layout时,需要给当前layout发送 -invalidateLayout,该消息会立即返回,并且预约在下一个loop的时候刷新当前layout,这一点和UIView的setNeedsLayout方法十分类似。在-invalidateLayout后的下一个collectionView的刷新loop中,又会从prepareLayout开始,依次再调用-collectionViewContentSize和-layoutAttributesForElementsInRect来生成更新后的布局。
以上都是猫神的巨作,他写的很好直接拿来用了
下面看下demo
首先创建一个类继承自UICollectionViewLayou 然后声明一些基本的属性
private var _cellCount:Int?
private var _collectSize:CGSize?
private var _center:CGPoint?
private var _radius:CGFloat?
按照上面的步骤
//一般在该方法中设定一些必要的layout的结构和初始需要的参数等
override func prepareLayout() {
super.prepareLayout()
_collectSize = self.collectionView?.frame.size
_cellCount = self.collectionView?.numberOfItemsInSection(0)
_center = CGPointMake(_collectSize!.width / 2.0, _collectSize!.height / 2.0)
_radius = min(_collectSize!.width, _collectSize!.height)/2.5
这个方法初始化了一些基本信息
override func collectionViewContentSize() -& CGSize {
return _collectSize!
override func layoutAttributesForElementsInRect(rect: CGRect) -& [UICollectionViewLayoutAttributes]? {
var attributesArray = [UICollectionViewLayoutAttributes]()
if let count = self._cellCount {
for i in 0 ..& count{
//这里利用了-layoutAttributesForItemAtIndexPath:来获取attributes
let indexPath = NSIndexPath(forItem: i, inSection: 0)
let attributes =
self.layoutAttributesForItemAtIndexPath(indexPath)
attributesArray.append(attributes!)
return attributesArray
override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -& UICollectionViewLayoutAttributes? {
let attrs = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
attrs.size = CGSizeMake(ITEM_SIZE, ITEM_SIZE)
let x = Double(_center!.x) + Double(_radius!) * cos(Double(2 * indexPath.item) * M_PI/Double(_cellCount!))
let y = Double(_center!.y) + Double(_radius!) * sin(Double(2 * indexPath.item) * M_PI/Double(_cellCount!))
attrs.center = CGPointMake( CGFloat(x) , CGFloat(y));
return attrs
这个方法layoutAttributesForItemAtIndexPath 对UICollectionViewLayoutAttributes 的一些属性进行设置 ,前面列出过 ,然后layoutAttributesForElementsInRect 方法返回所有UICollectionViewLayoutAttributes
, 以数组的方式
然后再使用的时候把基本用法里的layout换掉
layout = MyCollectionViewLayout()
collect = UICollectionView(frame: self.view.frame,collectionViewLayout:layout)
collect.backgroundColor = UIColor.whiteColor()
collect.delegate = self
collect.dataSource = self
这样运行 , 圆就出现了
if(layout is MyCollectionViewLayout){
layout = UICollectionViewFlowLayout()
(layout as! UICollectionViewFlowLayout).scrollDirection = UICollectionViewScrollDirection.Vertical
(layout as! UICollectionViewFlowLayout).itemSize = CGSizeMake(60, 75)
layout = MyCollectionViewLayout()
self.collect.setCollectionViewLayout(layout, animated: true)
可以通过setCollectionViewLayout 方法来切换layout
然后给这个界面添加手势
let tapRecognizer = UITapGestureRecognizer(target: self, action: "handleTap:")
collect.addGestureRecognizer(tapRecognizer)
func handleTap(sender:UITapGestureRecognizer){
if sender.state == UIGestureRecognizerState.Ended{
let tapPoint = sender.locationInView(self.collect)
indexPath = self.collect.indexPathForItemAtPoint(tapPoint)
//点击了cell
//这个方法可以用来对collectionView中的元素进行批量的插入,删除,移动等操作,同时将触发collectionView所对应的layout的对应的动画。
print("------")
self.collect.performBatchUpdates({ () -& Void in
self.collect.deleteItemsAtIndexPaths([indexPath])
self.dic.removeAtIndex(indexPath.row)
}, completion: nil)
arc4random_uniform(8)+1
self.dic.append(CellContent(img: "f"+String(val), name: "歪脖子"+String(val)))
self.collect.insertItemsAtIndexPaths([NSIndexPath(forItem: Int(val) , inSection: 0)])
dispatch_async(dispatch_get_global_queue(0, 0), { () -& Void in
arc4random_uniform(9)
self.dic.append(CellContent(img: "f"+String(val), name: "歪脖子"+String(val)))
dispatch_async(dispatch_get_main_queue()) {
self.collect.reloadData()
//点击了不是cell的区域
print("+++++++")
我注释掉这段GCD的代码也是可以执行的 ,就是没有动画 。
这个方法performBatchUpdates:completion 可以用来对collectionView中的元素进行批量的插入,删除,移动等操作,同时将触发collectionView所对应的layout的对应的动画。相应的动画由layout中的下列四个方法来定义:
initialLayoutAttributesForAppearingItemAtIndexPath:
initialLayoutAttributesForAppearingDecorationElementOfKind:atIndexPath:
finalLayoutAttributesForDisappearingItemAtIndexPath:
finalLayoutAttributesForDisappearingDecorationElementOfKind:atIndexPath:
默认的动画是这样的
我们可以自定义动画
每次重新给出layout时都会调用prepareLayout,这样在以后如果有collectionView大小变化的需求时也可以自动适应变化。
override func initialLayoutAttributesForAppearingItemAtIndexPath(itemIndexPath: NSIndexPath) -& UICollectionViewLayoutAttributes? {
// Must call super
var attributes = super.initialLayoutAttributesForAppearingItemAtIndexPath(itemIndexPath)
if self.insertIndexPaths.contains(itemIndexPath) {
if let _ = attributes{
attributes = self.layoutAttributesForItemAtIndexPath(itemIndexPath)
// Configure attributes ...
attributes!.alpha = 0.0
attributes!.center =
CGPointMake(_center!.x, _center!.y)
//attributes?.size = CGSizeMake(1000, 1000)
return attributes
override func prepareForCollectionViewUpdates(updateItems: [UICollectionViewUpdateItem]) {
super.prepareForCollectionViewUpdates(updateItems)
self.insertIndexPaths = [NSIndexPath]()
for update in updateItems{
if update.updateAction == UICollectionUpdateAction.Insert{
self.insertIndexPaths.append(update.indexPathAfterUpdate)
首先会调用prepareForCollectionViewUpdates,我们在这里拿到那个新增的NSIndexPath ,然后initialLayoutAttributesForAppearingItemAtIndexPath 在这个方法中设置一些初始位置。
这个是从中间散出去的 ,同理也可以搞一些别的效果 。大概就这些吧。当然UICollectionView可以玩的还很多,期待大家一起探索。多分享哦!
(本实例使用xcode 7 bate , swift 2.0)
最后附上源码:https://github.com/smalldu/SwiftStudy
版权声明:本文为博主原创文章,未经博主允许不得转载。
相关搜索:
相关阅读:
相关频道:
Android教程最近更新所有回答(2)
可以查看下这篇文档
这个问题解决了没阿?
清除回答草稿
&&&您需要以后才能回答,未注册用户请先。如何自定义CollectionView中每个元素的大小和间距_百度知道
如何自定义CollectionView中每个元素的大小和间距
我有更好的答案
在你的视图控制器头文件中实现UICollectionViewFlowLayout协议设置每个单元格的大小设置单元格间的横向间距设置纵向的行间距通过调整inset使单元格顶部和底部都有间距(inset次序: 上,左,下,右边)
采纳率:85%
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。

我要回帖

更多关于 jq获取元素自定义属性 的文章

 

随机推荐