在这一篇了我将继续讲解UIGridPanel。

在iphone的app里面可以经常看到一些九宫格布局的应用,做过html开发的对这类布局应该是很熟悉的。在IOS中要实现这样的布局方法还是蛮多的,但是我这次主要是讲解直接通过控件来实现,我直接指定某个subview处于gridpanel的某行某列。甚至我要求该subview跨多行多列来显示。

要实现以上的需求,那么首先就得要求该panel具有行和列的属性,也就是该panel可以被拆分成多少行多少列。用代码表示如下:

@interface UIGridPanel : UIPanel
@property (nonatomic,assign)NSInteger rows;//行数,默认未1
@property (nonatomic,assign)NSInteger colums;//列数,默认未1
@end

而对于subview来说,需要有四个属性,row和colum,rowSpan和columSpan。用代码表示如下:

@interface UIView(UIGridPanelSubView)
//行索引
@property (nonatomic,assign)NSInteger row;
//跨越的行数
@property (nonatomic,assign)NSInteger rowSpan;//默认是1
//列索引
@property (nonatomic,assign)NSInteger colum;
//跨越的列数
@property (nonatomic,assign)NSInteger columSpan;//默认是1
@end

既然所需的属性都有了,那么下面就是具体怎么实现了。

既然要对某个subview指定某行某列(这里假定是第一行第一列,row=colum=1),那么我们就得有个约束,该subview的left距离panel(假定该panel的rows=colums=3)的left是三分之一panel的宽度,该subview的right距离panel的left是三分之二的panel的宽度。但是这样的表述方法没法使用NSLayoutConstraint来实现,为什么?我们先把上面的描述转换成代码试试

 [NSLayoutConstraint constraintWithItem:subView
attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:self.frame.size.width/];

但是我们这里做的panel都是自适应的,也就意味着当父视图的高宽变化的时候,所有的subviews的高宽也应该跟着变化,而前面的表述我们把panel的宽度当做参数来处理了,而事实上这个参数是会改变的,很显然,此路不通。

那么我们换个思路考虑下,这样行不行?

[NSLayoutConstraint constraintWithItem:subView
attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0/ constant:];

NSLayoutAttributeLeft和NSLayoutAttributeWidth两种属性压根就不匹配,这样的方法也不行。

再换一个思路看看,我们能不能把panel的中心点做参考呢?如果以中心点做参考的话,该subview的left距离panel的中心点是多少呢?我先说下我当时找出这个算法的过程。

我们先在草图上画一个长方形,将他3等分,宽度定位90,那么每一列的宽度为30,中心点为45。这样我们得出一个比例,第一列的left跟中心点的比为0/45,

第二列的left跟中心点的比为30/45,第三列的left跟中心点的比为60/45,整理下得出:0/3,2/3,4/3。

继续,我们在草图上画一个长方形,将他4等分,宽度定位100,那么每一列的宽度为25,中心点为50。这样我们得出一个比例,第一列的left跟中心点的比为0/50,第二列的left跟中心点的比为25/50,第三列的left跟中心点的比为50/50,第四列的left跟中心点的比75/50,整理下得出:0/4,2/4,4/4,6/4。

继续,我们在草图上画一个长方形,将他5等分,宽度定位200,那么每一列的宽度为40,中心点为100。这样我们得出一个比例,第一列的left跟中心点的比为0/100,第二列的left跟中心点的比为40/100,第三列的left跟中心点的比为80/100,第四列的left跟中心点的比120/100,第五列的left跟中心点的比160/100,整理下得出:0/5,2/5,4/5,6/5,8/5。

看到规律了没?分母永远是等分的数量,对于列来说,也就是分母永远是colums,而分子是2*colum。这样我们就能用NSLayoutConstraint来表示了。

 [self addConstraint:[NSLayoutConstraint constraintWithItem:subView
attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:((2.0f*subViewColum)/self.colums) constant:margin.left]];

现在算法出来了。那么后续的处理就简单了,包括跨行和跨列的算法也能明白了。直接贴出代码:

@implementation UIView(UIGridPanelSubView)
char* const uiviewRow_str = "UIViewRowIndex";
-(void)setRow:(NSInteger)row{
if(row!=self.row){
objc_setAssociatedObject(self, uiviewRow_str, @(row), OBJC_ASSOCIATION_RETAIN);
[self resetConstraints];
}
} -(NSInteger)row{
return [objc_getAssociatedObject(self, uiviewRow_str) integerValue];
} char* const uiviewColum_str = "UIViewColumIndex";
-(void)setColum:(NSInteger)colum{
if(colum!=self.colum){
objc_setAssociatedObject(self, uiviewColum_str, @(colum), OBJC_ASSOCIATION_RETAIN);
[self resetConstraints];
}
} -(NSInteger)colum{
return [objc_getAssociatedObject(self, uiviewColum_str) integerValue];
} char* const uiviewColumSpan_str = "UIViewColumSpan";
-(void)setColumSpan:(NSInteger)columSpan{
if(columSpan!=self.columSpan){
objc_setAssociatedObject(self, uiviewColumSpan_str, @(columSpan), OBJC_ASSOCIATION_RETAIN);
[self resetConstraints];
}
} -(NSInteger)columSpan{
NSInteger columSpan=[objc_getAssociatedObject(self, uiviewColumSpan_str) integerValue];
if(columSpan<){
return ;
}
return columSpan;
} char* const uiviewRowSpan_str = "UIViewRowSpan";
-(void)setRowSpan:(NSInteger)rowSpan{
if(rowSpan!=self.rowSpan){
objc_setAssociatedObject(self, uiviewRowSpan_str, @(rowSpan), OBJC_ASSOCIATION_RETAIN);
[self resetConstraints];
}
} -(NSInteger)rowSpan{
NSInteger rowSpan=[objc_getAssociatedObject(self, uiviewRowSpan_str) integerValue];
if(rowSpan<)
return ;
return rowSpan;
}
@end @implementation UIGridPanel
@synthesize rows=_rows;
@synthesize colums=_colums; -(NSInteger)rows{
if(_rows<){
return ;
}
return _rows;
} -(NSInteger)colums{
if(_colums<){
return ;
}
return _colums;
} -(void)setRows:(NSInteger)rows{
if(_rows!=rows){
_rows=rows;
[self updateConstraints];
}
} -(void)setColums:(NSInteger)colums{
if(_colums!=colums){
_colums=colums;
[self updateConstraints];
}
} -(void)updateSubViewConstraints:(UIView *)subView{
if(subView.row>=self.rows){
NSException *e = [NSException
exceptionWithName: @"UIGridPanel异常"
reason: @"子视图的row索引必须小于父视图的rows"
userInfo: nil];
@throw e;
} if(subView.colum>=self.colums){
NSException *e = [NSException
exceptionWithName: @"UIGridPanel异常"
reason: @"子视图的colum索引必须小于父视图的colums"
userInfo: nil];
@throw e;
} UIEdgeInsets margin=subView.margin; NSInteger columSpan=subView.columSpan;
NSInteger rowSpan=subView.rowSpan;
NSInteger subViewRow=subView.row;
NSInteger subViewColum=subView.colum;
if(columSpan+subViewColum>=self.colums){
columSpan=self.colums-subViewColum;
} if(rowSpan+subViewRow>=self.rows){
rowSpan=self.rows-subViewRow;
} [self addConstraint:[NSLayoutConstraint constraintWithItem:subView
attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:((2.0f*subViewColum)/self.colums) constant:margin.left]]; [self addConstraint:[NSLayoutConstraint constraintWithItem:subView
attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:(2.0f*(subViewColum+columSpan))/self.colums constant:-margin.right]]; [self addConstraint:[NSLayoutConstraint constraintWithItem:subView
attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:((2.0f*subViewRow)/self.rows) constant:margin.top]]; [self addConstraint:[NSLayoutConstraint constraintWithItem:subView
attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:(2.0f*(subViewRow+rowSpan))/self.rows constant:-margin.bottom]]; } -(void)willRemoveSubview:(UIView *)subview{ } -(void)dealloc{
[self removeConstraints:self.constraints];
}
@end

至此,UIGridPanel已经介绍完了。

下一篇会介绍自动布局的难点-UIScrollView

最新文章

  1. 解析C语言结构体对齐(内存对齐问题)
  2. iOS设置分割线从边框顶端开始
  3. Node.js 字体格式转换 ttf2eot ttf2woff ttf2svg
  4. cf
  5. 20145225《Java程序设计》 实验五 Java网络编程及安全
  6. HTTP基础(一):如何使用浏览器network查看请求和响应的信息
  7. 查看博客模板的css代码
  8. 【LeetCode OJ】Triangle
  9. MVC+EF更新数据库
  10. C# 多线程操作样例
  11. chosen 下拉框
  12. VMware下LINUX的虚拟机增加磁盘空间
  13. pageContext.request.contextPath 和 request.getContextPath()
  14. ZUFE 1035 字符宽度编码(字符串)
  15. TF-IDF_MapReduceJava代码实现思路
  16. C语言---字符数组
  17. gitlab6 nginx配置和启动脚本
  18. DES和3DES加密算法C语言实现【转】
  19. HDU 1260
  20. HDU 3746 将字符串的全部字符最少循环2次需要添加的字符数

热门文章

  1. cucumber 文件目录结构和执行顺序
  2. sql server 时间查询
  3. Spring Cloud Config git版
  4. mongodb 上限集合
  5. Java创建对象的过程
  6. IE6下png背景不透明——张鑫旭博客读书笔记
  7. 通过 Azure IoT 中心实现互联网设备数据的可视化分析
  8. ZOJ 3626 Treasure Hunt I (树形DP,常规)
  9. vijos 1524 最小监视代价
  10. Codeforces Round #318 (Div. 2) C Bear and Poker (数学)