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 ...
随机推荐
- [转]SQL Server编程:SMO介绍
转自:周公 最近在项目中用到了有关SQL Server管理任务方面的编程实现,有了一些自己的心得体会,想在此跟大家分享一下,在工作中用到了SMO/SQL CLR/SSIS等方面的知识,在国内这方面的文 ...
- Linux: Start and Enable firewall
enable firewall systemctl enable firewalld start firewall systemctl start firewalld check firewall s ...
- open redis port for remote connections
edit /etc/redis.conf Add below line after bind 127.0.0.1, then try redis-cli -h xxx.xxx.xxx.xxx ping ...
- CUDA编程(二) CUDA初始化与核函数
CUDA编程(二) CUDA初始化与核函数 CUDA初始化 在上一次中已经说过了,CUDA成功安装之后,新建一个project还是十分简单的,直接在新建项目的时候选择NVIDIA CUDA项目就能够了 ...
- Android中apk动态载入技术研究(2)android插件化及实现
了解了android中类载入的前期知识点后,来看看android中DexClassLoader详细的实现 详细载入流程例如以下: 宿主程序会到文件系统比方SD卡中去载入APK[1],然 ...
- Android 自己定义UI圆角button
Android实际开发中我们一般须要圆角的button,普通情况下我们能够让美工做出来对应的button图片.然后放上去就可以,另外我们能够在布局文件里直接设置,也能够达到一样的效果. 以下解说在布局 ...
- hdu 5325 Crazy Bobo dfs
// hdu 5325 Crazy Bobo // // 题目大意: // // 给你一棵树,树上每一个节点都有一个权值w,选择尽可能多的节点, // 这些节点相互联通,而且依照权值升序排序之后得到节 ...
- Quartz.net使用入门(三)
Windows服务,自定义安装,卸载服务+Quartz.net app.config配置文件 <?xml version="1.0"?> <configurati ...
- Codeforces--633D--Fibonacci-ish (map+去重)(twice)
Fibonacci-ish Time Limit: 3000MS Memory Limit: 524288KB 64bit IO Format: %I64d & %I64u Su ...
- MySQL之自定义函数实例讲解
转自:https://www.2cto.com/database/201804/740205.html MySQL中已经有很多函数,如时间函数等,但是有时这些函数不能满足自己的设计需求,此时需要自定义 ...