UICollectionView框架总结
一、UIcollectionView介绍
1.1、简介
首先看苹果官方文档 UICollectionView Class Reference 的介绍:
The UICollectionView class manages an ordered collection of data items and presents them using customizable layouts. Collection views provide the same general function as table views except that a collection view is able to support more than just single-column layouts. Collection views support customizable layouts that can be used to implement multi-column grids, tiled layouts, circular layouts, and many more. You can even change the layout of a collection view dynamically if you want.
在WWDC2012中的Introducing Collection Views,苹果首次介绍了UICollectionView,类似UITableView的用法使人很容易接受,但强大的自定义布局,又使其相较于UITableView有了选择它的更多理由,UITableView中的表格只支持单排列表,没有办法支持网格列表模式。
一句话总结就是:UICollectionView与UITableView相似,却提供了可自定义多列网格(Grild)的功能。
下面通过一张图片来了解UICollectionView的构成:
1.2、UICollectionView用来做什么
UICollectionView 类用于管理有序的数据单元,并且可以定制化的显示他们。UICollectionView 除了提供和tableview相同的一般的方法外,还支持一列以上的布局。UICollectionView 支持的定制化布局能够实现网格或是瓷砖的布局效果。你甚至可以动态的改变Collectionview的布局。
二、UICollectionView与UITableView比较
2.1、UICollectionViewDataSource
UICollectionViewDelegate-负责提供展示的数据,实现下面两个必须的委托方法,其实与UITableView并无二意
- numberOfItemsInsection: 某个Section里面有多少item
- cellForItemAtIndexPath: 对于某个位置应该显示什么样的cell,里面会涉及到cell的复用,可参考UITableView
2.2、UICollectionViewDelegate
UICollectionViewDelegate-负责用户的交互、cell的外形,委托方法和UITableView相似,可以选择性实现以下委托方法。
- collectionView:shouleHighlightItemAtIndexPath:是否支持高亮?
- collectionView:didHighlightItemAtIndexPath:如果支持高亮,那么高亮;
- collectionView:shouldSelectItemAtIndexPath:询问是否可以被选中?
- collectionView:didUnhighlightItemAtIndexPath:如果支持高亮,那么现在取消高亮;
- collectionView:didSelectItemAtIndexPath:如果支持可以被选中,那么选中 cell;
2.3、UICollectionViewLayout
在布局上,与UITableView直接使用系统提供的样式,UICollectionView使用的是UICollectionViewLayout来自定义布局样式。
- UICollectionViewLayout是一个抽象基类,需要继承它来为CollectionView生成Layout信息。Layout对象的作用是决定Cells,Supplementary Views和Decoration Views在CollectionView中的布局位置。系统也提供了UICollectionViewFlowLayout-l流水式布局效果
- UICollectionView的显示效果几乎全部由UICollectionViewLayout负责,而真正存储着每一个cell的位置、大小等属性的是UICollectionViewLayoutAttributes。每一个cell对应着一个属于自己的UICollectionViewLayoutAttributes,而UICollectionViewLayout正是利用UICollectionViewLayoutAttributes里存在的信息对每一个cell进行布局。
三、UICollectionView层次结构
UICollectionView类负责管理数据的有序集合以及以自定义布局的模式来呈现这些数据,它提供了一些常用的表格功能,此外还增加了许多单栏布局。UICollectionView支持可以用于实现多列网格、平铺的布局、圆形的布局和更多的自定义布局,甚至可以动态的改变它的布局。
3.1、UICollectionView基本使用
我们要使用UICollectionView得实现UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout这三个协议。UICollectionViewDataSource是它的数据源,UICollectionDelegate是它的呈现样式,UICollectionViewDelegateFlowLayout是它的布局样式。
3.1.1 初始化
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
UICollectionView *colView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
3.1.2 注册UICollectionView使用的cell类型
[colView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"myCell"];
3.1.3 设置代理
colView.delegate = self;
colView.dataSource = self;
3.1.4 实现协议UICollectionViewDataSource
//配置UICollectionView的每个section的item数
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [[self loadData] count];
}
//配置section数
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
//呈现数据
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = @"myCell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
cell.backgroundColor = [UIColor redColor];
return cell;
}
3.1.5 UICollectionViewDelegateFlowLayout
//配置每个item的size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(100, 60);
}
//配置item的边距
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(20, 20, 0, 20);
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(200, 60);
}
3.1.6 UICollectionViewDelegate
复制代码
//点击item时触发
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"您点击了item:%@", [[self loadData] objectAtIndex:indexPath.row]);
[collectionView cellForItemAtIndexPath:indexPath].backgroundColor = [UIColor redColor];
}
//当前item是否可以点击
- (BOOL) collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
if (indexPath.row % 2)
{
return YES;
}
return NO;
}
//cell点击时是否高亮,点击cell时的样式和点击后cell的样式
- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
cell.backgroundColor = [UIColor redColor];
}
- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
cell.backgroundColor = [UIColor grayColor];
}
3.2、自定义UICollectionViewFlowLayout
使用UICollectionViewFlowLayout之前,我们来了解它内部常用的属性
//同一组当中,垂直方向:行与行之间的间距;水平方向:列与列之间的间距
@property (nonatomic) CGFloat minimumLineSpacing;
//垂直方向:同一行中的cell之间的间距;水平方向:同一列中,cell与cell之间的间距
@property (nonatomic) CGFloat minimumInteritemSpacing;
//每个cell统一尺寸
@property (nonatomic) CGSize itemSize;
//滑动反向,默认滑动方向是垂直方向滑动
@property (nonatomic) UICollectionViewScrollDirection scrollDirection;
//每一组头视图的尺寸。如果是垂直方向滑动,则只有高起作用;如果是水平方向滑动,则只有宽起作用。
@property (nonatomic) CGSize headerReferenceSize;
//每一组尾部视图的尺寸。如果是垂直方向滑动,则只有高起作用;如果是水平方向滑动,则只有宽起作用。
@property (nonatomic) CGSize footerReferenceSize;
//每一组的内容缩进
@property (nonatomic) UIEdgeInsets sectionInset;
3.2.1 NYWaterflowLayout(瀑布流样式)
NYWaterflowLayout继承与UICollectionViewLayout 重写部分方法
核心代码
- (void)prepareLayout
{
[super prepareLayout];
// 清楚以前计算的所有高度
[self.columnHeights removeAllObjects];
for (NSInteger i = 0; i < self.columnCount; i++) {
[self.columnHeights addObject:@(self.edgeInsets.top)];
}
// 清楚之前所有的布局属性
[self.attrsArray removeAllObjects];
// 开始创建每一个cell对应的布局属性
NSInteger count = [self.collectionView numberOfItemsInSection:0];
for (NSInteger i = 0; i < count; i++) {
//创建位置
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
[self.attrsArray addObject:attributes];
}
}
// 决定cell的排布
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
return self.attrsArray;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
// 创建布局属性
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
// collectionView的宽度
CGFloat collectionViewWidth = self.collectionView.frame.size.width;
// 设置布局属性的frame
CGFloat width = (collectionViewWidth - self.edgeInsets.left - self.edgeInsets.right - (self.columnCount - 1) * self.columnMargin) / self.columnCount;
CGFloat h = [self.delegate waterflowLayout:self heightForItemAtIndex:indexPath.item itemWidth:width];
// CGFloat h = 50 + arc4random_uniform(100);
// 找出高度最短的那一列
__block NSInteger destColumn = 0;
__block CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];
[self.columnHeights enumerateObjectsUsingBlock:^(NSNumber *columnHeightNumber, NSUInteger idx, BOOL * _Nonnull stop) {
CGFloat columnHeight = columnHeightNumber.doubleValue;
if (minColumnHeight > columnHeight) {
minColumnHeight = columnHeight;
destColumn = idx;
}
}];
// 获取最短列的xy
CGFloat x = self.edgeInsets.left + destColumn * (width + self.columnMargin);
CGFloat y = minColumnHeight;
if (y != self.edgeInsets.top) {
y += self.rowMargin;
}
attributes.frame = CGRectMake(x, y, width, h);
//更新最短那列的高度
self.columnHeights[destColumn] = @(CGRectGetMaxY(attributes.frame));
return attributes;
}
// 设置CollectionViewContentSize
- (CGSize)collectionViewContentSize
{
__block CGFloat maxColumnHeight = [self.columnHeights[0] doubleValue];
[self.columnHeights enumerateObjectsUsingBlock:^(NSNumber *columnHeightNumber, NSUInteger idx, BOOL * _Nonnull stop) {
CGFloat columnHeight = columnHeightNumber.doubleValue;
if (maxColumnHeight < columnHeight) {
maxColumnHeight = columnHeight;
}
}];
return CGSizeMake(0, maxColumnHeight + self.edgeInsets.bottom);
}
NYWaterflowLayoutDelegate
@required
- (CGFloat)waterflowLayout:(NYWaterflowLayout *)waterflowLayout heightForItemAtIndex:(NSUInteger)index itemWidth:(CGFloat)itemWidth;
@optional
// 瀑布流布局的列数
- (NSInteger)columnCountInWaterflowLayout:(NYWaterflowLayout *)waterflowLayout;
// 列间距
- (CGFloat)columnMarginInWaterflowLayout:(NYWaterflowLayout *)wateflowLayout;
// 行间距
- (CGFloat)rowMarginInWaterflowLayout:(NYWaterflowLayout *)waterflowLayout;
// 边沿间距
- (UIEdgeInsets)edgeInsetsInWaterflowLayout:(NYWaterflowLayout *)waterflowLayout;
效果图
3.2.2 NYCircularLayout(环形布局)
核心代码
- (void)prepareLayout
{
[super prepareLayout];
// 获取item的个数
_itemCount = (int)[self.collectionView numberOfItemsInSection:0];
_attributeArray = [[NSMutableArray alloc] init];
// 先设定大圆的半径取长和宽最短的
CGFloat radius = MIN(self.collectionView.frame.size.width, self.collectionView.frame.size.height)/2;
// 计算圆心的位置
CGPoint center = CGPointMake(self.collectionView.frame.size.width/2, self.collectionView.frame.size.height/2);
// 设置每个item的大小为50*50 则半径为25
for (int i = 0; i < _itemCount; i++) {
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
// 设置item的大小
attributes.size = CGSizeMake(50, 50);
// 计算每个item中心的坐标 算出的x,y值还要减去item自身的半径大小
float x = center.x + cosf(2*M_PI/_itemCount * i)*(radius - 25);
float y = center.y + sinf(2*M_PI/_itemCount * i)*(radius - 25);
attributes.center = CGPointMake(x, y);
[_attributeArray addObject:attributes];
}
}
// 设定区域大小
- (CGSize)collectionViewContentSize
{
return self.collectionView.frame.size;
}
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
return _attributeArray;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
// 创建布局属性
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
return attributes;
}
效果图
3.2.3 CarouselViewLayout(旋转布局)
核心代码
- (void)prepareLayout {
[super prepareLayout];
if (self.visibleCount < 1) {
self.visibleCount = 3;
}
if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
_viewHeight = CGRectGetHeight(self.collectionView.frame);
_itemHeight = self.itemSize.height;
self.collectionView.contentInset = UIEdgeInsetsMake((_viewHeight - _itemHeight) / 2, 0, (_viewHeight - _itemHeight) / 2, 0);
} else {
_viewHeight = CGRectGetWidth(self.collectionView.frame);
_itemHeight = self.itemSize.width;
self.collectionView.contentInset = UIEdgeInsetsMake(0, (_viewHeight - _itemHeight) / 2, 0, (_viewHeight - _itemHeight) / 2);
}
}
- (CGSize)collectionViewContentSize {
NSInteger cellCount = [self.collectionView numberOfItemsInSection:0];
if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
return CGSizeMake(CGRectGetWidth(self.collectionView.frame), cellCount * _itemHeight);
}
return CGSizeMake(cellCount * _itemHeight, CGRectGetHeight(self.collectionView.frame));
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSInteger cellCount = [self.collectionView numberOfItemsInSection:0];
CGFloat centerY = (self.scrollDirection == UICollectionViewScrollDirectionVertical ? self.collectionView.contentOffset.y : self.collectionView.contentOffset.x) + _viewHeight / 2;
NSInteger index = centerY / _itemHeight;
NSLog(@"第几个-----%ld",(long)index);
NSInteger count = (self.visibleCount - 1) / 2;
// 取第一个和当前位置减1的最大值
NSInteger minIndex = MAX(0, (index - count));
// 取最后一个和当前位置加1的最小值
NSInteger maxIndex = MIN((cellCount - 1), (index + count));
NSMutableArray *array = [NSMutableArray array];
//更新可视范围内的布局
for (NSInteger i = minIndex; i <= maxIndex; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
[array addObject:attributes];
}
return array;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attributes.size = self.itemSize;
CGFloat cY = (self.scrollDirection == UICollectionViewScrollDirectionVertical ? self.collectionView.contentOffset.y : self.collectionView.contentOffset.x) + _viewHeight / 2;
CGFloat attributesY = _itemHeight * indexPath.row + _itemHeight / 2;
attributes.zIndex = -ABS(attributesY - cY);
CGFloat delta = cY - attributesY;
CGFloat ratio = - delta / (_itemHeight * 2);
CGFloat scale = 1 - ABS(delta) / (_itemHeight * 6.0) * cos(ratio * M_PI_4);
// attributes.transform = CGAffineTransformMakeScale(scale, scale);
CGFloat centerY = attributesY;
switch (self.carouselAnim) {
case HJCarouselAnimRotary:
attributes.transform = CGAffineTransformRotate(attributes.transform, - ratio * M_PI_4);
centerY += sin(ratio * M_PI_2) * _itemHeight / 2;
break;
case HJCarouselAnimCarousel:
centerY = cY + sin(ratio * M_PI_2) * _itemHeight * INTERSPACEPARAM;
break;
case HJCarouselAnimCarousel1:
centerY = cY + sin(ratio * M_PI_2) * _itemHeight * INTERSPACEPARAM;
if (delta > 0 && delta <= _itemHeight / 2) {
attributes.transform = CGAffineTransformIdentity;
CGRect rect = attributes.frame;
if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
rect.origin.x = CGRectGetWidth(self.collectionView.frame) / 2 - _itemSize.width * scale / 2;
rect.origin.y = centerY - _itemHeight * scale / 2;
rect.size.width = _itemSize.width * scale;
CGFloat param = delta / (_itemHeight / 2);
rect.size.height = _itemHeight * scale * (1 - param) + sin(0.25 * M_PI_2) * _itemHeight * INTERSPACEPARAM * 2 * param;
} else {
rect.origin.x = centerY - _itemHeight * scale / 2;
rect.origin.y = CGRectGetHeight(self.collectionView.frame) / 2 - _itemSize.height * scale / 2;
rect.size.height = _itemSize.height * scale;
CGFloat param = delta / (_itemHeight / 2);
rect.size.width = _itemHeight * scale * (1 - param) + sin(0.25 * M_PI_2) * _itemHeight * INTERSPACEPARAM * 2 * param;
}
attributes.frame = rect;
return attributes;
}
break;
case HJCarouselAnimCoverFlow: {
CATransform3D transform = CATransform3DIdentity;
transform.m34 = -1.0/400.0f;
transform = CATransform3DRotate(transform, ratio * M_PI_4, 1, 0, 0);
attributes.transform3D = transform;
}
break;
default:
break;
}
if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
attributes.center = CGPointMake(CGRectGetWidth(self.collectionView.frame) / 2, centerY);
} else {
attributes.center = CGPointMake(centerY, CGRectGetHeight(self.collectionView.frame) / 2);
}
return attributes;
}
//当滑动停止时使得item的位置位于中心
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
CGFloat index = roundf(((self.scrollDirection == UICollectionViewScrollDirectionVertical ? proposedContentOffset.y : proposedContentOffset.x) + _viewHeight / 2 - _itemHeight / 2) / _itemHeight);
if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
proposedContentOffset.y = _itemHeight * index + _itemHeight / 2 - _viewHeight / 2;
} else {
proposedContentOffset.x = _itemHeight * index + _itemHeight / 2 - _viewHeight / 2;
}
return proposedContentOffset;
}
效果图
3.2.4 banner轮播器
3.2.4.1 UIScrollView实现
核心代码
//初始化ImageView
- (void)initLayoutSubview
{
[self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self);
}];
CGSize size = self.scrollView.bounds.size;
_preImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
[_scrollView addSubview:_preImageView];
_currentImageView = [[UIImageView alloc] initWithFrame:CGRectMake(size.width, 0, size.width, size.height)];
[_scrollView addSubview:_currentImageView];
_nextImageView = [[UIImageView alloc] initWithFrame:CGRectMake(size.width * 2, 0, size.width, size.height)];
[_scrollView addSubview:_nextImageView];
self.scrollView.contentSize = CGSizeMake(3 * self.scrollView.bounds.size.width, 0);
WS(weakSelf);
[self.pageControl mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(weakSelf.mas_bottom).offset(-10);
make.width.equalTo(weakSelf.mas_width);
make.height.equalTo(@(60));
}];
self.currentPage = 0;
self.pageControl.numberOfPages = self.bannersArray.count;
self.pageControl.currentPage = _currentPage;
[self startTimer];
}
//准备加载页
- (void)pageLoad
{
_preImageView.image = nil;
_currentImageView.image = nil;
_nextImageView.image = nil;
_pageControl.currentPage = _currentPage;
#pragma mark -设置图片
NSString *str = self.bannersArray[_currentPage == 0 ? self.bannersArray.count - 1 : _currentPage - 1];
_preImageView.image = [UIImage imageNamed:str];
str = self.bannersArray[_currentPage];
_currentImageView.image = [UIImage imageNamed:str];
str = self.bannersArray[_currentPage == self.bannersArray.count-1 ? 0 : _currentPage + 1];
_nextImageView.image = [UIImage imageNamed:str];
_scrollView.contentOffset = CGPointMake(self.frame.size.width, 0);
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self scrollViewDidEnd];
[self startTimer];
}
- (void)scrollViewDidEnd
{
int index = _scrollView.contentOffset.x / self.window.bounds.size.width;
if (index == 0) {
_currentPage = _currentPage == 0 ? self.bannersArray.count - 1 : _currentPage - 1;
} else if (index == 2)
{
_currentPage = _currentPage + 1 == self.bannersArray.count ? 0 : _currentPage + 1;
}
[self pageLoad];
}
SDCycleScrollViewhttp://www.oschina.net/p/sdcyclescrollview
效果图
附录
作者:方向_4d0d
链接:https://www.jianshu.com/p/7ffa012f34a4
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
UICollectionView框架总结的更多相关文章
- Instagram/IGListKit 实践谈(UICollectionView框架)
简单介绍 IGListKit是Instagram推出的新的UICollectionView框架,使用数据驱动,旨在创造一个更快更灵活的列表控件. github地址:https://github.com ...
- fir.im Weekly - Swift 3.0 的迁移适配指南
无论你是移动开发者,还是桌面端开发者,或者正在IoT领域探索的技术人员,那么应该更加关注 iDev 全平台开发者大会,也许是后半年 iOS 开发者最盛大的技术盛宴.既有知名公司带来专业视野,又有从 S ...
- 【转】33 个 2017 年必须了解的 iOS 开源库
1.IGListKit,作者是Instagram Engineering Instagram 程序员做的,IGListKit 是数据驱动的 UICollectionView 框架,为了构建快速和可扩展 ...
- 2017 33 款iOS开源库
IGListKit https://github.com/Instagram/IGListKit 由 Instagram 开发人员制作,IGListKit 是用于构建快速灵活列表的数据驱动型的 UIC ...
- 33 个 2017 年必须了解的 iOS 开源库
本文翻译自Medium,原作者为Pawe? Bia?ecki 照片版权:(Unsplash/Markus Pe) 你好,iOS 开发者们!我的名字叫 Pawe?,我是一个独立 iOS 开发者,并且是 ...
- Swift 学习指引
以下指引是基于最新的 Swift 4.0 为基础为而言. 如你在参考3.0以下版本, 那你就不要说你会 Swift, 3.0 之前是 Objective-C 的搬迁(80%),是不成熟的语言, 看着很 ...
- 33 个 2017 年必须了解的 iOS/swift 开源库第三方库
本文翻译自Medium,原作者为 Paweł Białecki<img src="https://pic3.zhimg.com/v2-c786777447261347b0d97 ...
- 开源月刊《HelloGitHub》第 62 期
兴趣是最好的老师,HelloGitHub 让你对编程感兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这里有实战项目.入门教程.黑科技.开源书籍.大厂开源项目等,涵盖多种编程语言 Pyt ...
- UIKit 框架之UICollectionView
1.自定义UICollectionViewCell 在myCollectionViewCell.h中声明两个属性 // // myCollectionViewCell.h // UICollectio ...
随机推荐
- ajax多文件上传,js原生ajax请求(转)
function uploadImageFile(){ var xhr = new XMLHttpRequest(); //定义表单变量 var file = document.getElementB ...
- LVS中文站点
http://blog.csdn.net/turkeyzhou/article/details/16980161 http://zh.linuxvirtualserver.org/
- 基于FFI模块CAPI与JavaScript的各种类型匹配总结
0.写在前面: 1)涉及的关键词定义: 传入:JavaScript向CAPI传值 传出:CAPI向JavaScript传值 2)关于类和结构体的封装,需要严格执行内存对齐,以防止读取越界,但是避免不了 ...
- Java Map 怎样实现Key 的唯一性?
大家都知道.在Map和Set不可存在反复元素? 可是对于内部的细节我们并不了解.今天我们就一块来 探讨一下! 1 对于 HashMap HashSet 他们的底层数据结构的实现是:维护了一张 Ha ...
- C++学习之命名空间
在C++中,命名空间(namespace)的目的是为了防止名字冲突.每个命名空间是一个作用域,在所有命名空间之外,还存在一个全局命名空间(global namespace),全局命名空间以隐式的方式声 ...
- swift 2.0 语法 循环
//: Playground - noun: a place where people can play import UIKit /*: for循环 * 基本用法和OC一致 * 条件表达式必须是bo ...
- Eclipse导入外部项目问题总结
此次在项目开发过程中导入从oksvn下载的共享项目时出现几个项目在不同的IDE导入导出时的问题,为免忘记做例如以下笔记: 1 类路径问题 在Java开发中大多数的开发人员使用的IDE是MyEcl ...
- 怎么让frameset出现整体滚动条
a.html<!DOCTYPE html> <html> <head> <title></title> </head> < ...
- bzoj 1822 冷冻波
题目大意: 在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵 我们认为,巫妖和小精灵都可以看成是平面上的点. 当巫妖和小精灵之间的直线距离不超过R,且巫妖和小精灵的 ...
- JSP-Runoob:JSP 国际化
ylbtech-JSP-Runoob:JSP 国际化 1.返回顶部 1. JSP 国际化 在开始前,需要解释几个重要的概念: 国际化(i18n):表明一个页面根据访问者的语言或国家来呈现不同的翻译版本 ...