xcode8 中使用swift2.3 经验

今天升级xcode8 尝试了项目,发现能支持老版本swift 如图设置
tag -> builld Settings
设置图
然后会有些ios 10 的可选 ? ! 问题,我的项目中不多30 左右,修改很快,又可以愉快的玩耍了

ios 图库的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
UIImagePickerControllerDelegate ,UINavigationControllerDelegate
func actionSheet(actionSheet: UIActionSheet, clickedButtonAtIndex buttonIndex: Int){
PickerController = UIImagePickerController()
if buttonIndex == 0{//图库
PickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
}else if buttonIndex == 2{//相机 取消为1
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera) == false{
return
}
PickerController.sourceType = UIImagePickerControllerSourceType.Camera
}
if buttonIndex==0||buttonIndex == 2{
PickerController.delegate = self
PickerController.allowsEditing = true
//PickerController.mediaTypes = [kUTTypeMovie!]//需要头文件支持 视频文件
//PickerController.videoQuality = UIImagePickerControllerQualityType.Type640x480
self.presentViewController(PickerController, animated: true) { () -> Void in
//println("页面跳转成功回调")
}
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]){
//println("选择")
// println("视频文件地址\(info[UIImagePickerControllerMediaURL])")
println("图片文件\(info[UIImagePickerControllerOriginalImage])")
//编辑后的image
let image = info[UIImagePickerControllerEditedImage] as! UIImage
// info[UIImagePickerControllerReferenceURL] 等等信息
//var url = info[UIImagePickerControllerMediaURL] as! NSURL
// println("url = \(url.URLString)")
// var avAsset = AVURLAsset(URL: url, options: nil)
// println("时间\(avAsset.duration.value) : \(avAsset.duration.timescale)")
var image = info[UIImagePickerControllerOriginalImage] as! UIImage
//self.presentViewController(upload, animated: true, completion: nil)
//self.navigationController?.pushViewController(upload, animated: true)
PickerController.dismissViewControllerAnimated(true, completion: { () -> Void in
})
}

// 保存到本地

1
2
3
4
5
6
7
8
9
10
11
12
UIVideoAtPathIsCompatibleWithSavedPhotosAlbum //拍摄的视频保存到相册
UISaveVideoAtPathToSavedPhotosAlbum(url.path, self, nil, nil)
UIImageWriteToSavedPhotosAlbum 拍摄的图片保存到本地
if picker.sourceType == UIImagePickerControllerSourceType.Camera{
let saveBool = UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(url.path)
if saveBool == true{
UISaveVideoAtPathToSavedPhotosAlbum(url.path, self, nil, nil)
}
}

swift画线

1
2
3
4
5
6
7
8
9
10
11
12
override func drawRect(rect: CGRect) {
super.drawRect(rect)
let context = UIGraphicsGetCurrentContext()
CGContextSetLineCap(context,CGLineCap.Round)//
CGContextSetLineWidth(context, 2)// 线宽
CGContextSetAllowsAntialiasing(context, true)// 锯齿
CGContextSetRGBStrokeColor(context, 231/255, 231/255, 231/255, 1)//颜色
CGContextBeginPath(context)
CGContextMoveToPoint(context, 0, 0)// 起点坐标
CGContextAddLineToPoint(context, self.frame.width, 0)// 终点坐标
CGContextStrokePath(context)
}

oc 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, 3); //线宽
CGContextSetAllowsAntialiasing(context, true);
CGContextSetRGBStrokeColor(context, 0.0 / 255.0, 0.0 / 255.0, 0.0 / 0.0, 1.0); //线的颜色
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0, 0); //起点坐标
CGContextAddLineToPoint(context, self.frame.size.width, self.frame.size.height); //终点坐标
CGContextStrokePath(context);
}

注: UItableView cell 上划线会被 contentView 背景遮住 需要让他得背景透明

有时候觉得这样去画一条线太麻烦不如,add个View 或者layer 啥的, 所以现在扩展UIView 写一个通用的只是添加一个线的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
UIView 扩展画线
- parameter X: X 线的X
- parameter Y: Y 线的X
- parameter width: width 线的width
- parameter height: height 线的height
- parameter coloer: coloer 线的颜色
*/
func cz_AddBorderLine(X:CGFloat , Y:CGFloat ,width:CGFloat,height:CGFloat,coloer:UIColor) {
let border = CALayer()
border.backgroundColor = coloer.CGColor
border.frame = CGRect(x: X, y: Y, width: width, height: height)
layer.addSublayer(border)
}

UIImage图片拉伸

1
2
3
// 做到一个聊天背景图时 发现背景图片需要自动大小, 记录下图片拉伸的使用方法
// 参数的意思是从宽高的位置指向的一个像素的+1像素进行拉伸 (参数宽高 范围 是保护部分不会被拉伸)
image = [image stretchableImageWithLeftCapWidth:image.size.width/2 topCapHeight:image.size.height/2];

iOS中图片(UIImage)拉伸技巧
转: https://my.oschina.net/u/2340880/blog/403996

iOS中图片拉伸技巧与方法总结

一、了解几个图像拉伸的函数和方法

1、直接拉伸法

简单暴力,却是最最常用的方法,直接将图片设置为ImageView的image属性,图片便会随UIImageView对象的大小做自动拉伸。这种拉伸的方法有一个致命的缺陷,它会使图像发生失真与形变。

2、像素点的拉伸

  • (UIImage *)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWidth topCapHeight:(NSInteger)topCapHeight;

这个函数我们可以用来拉伸类似QQ,微信的聊天气泡背景图,它的两个参数分别leftCapWidth和topCapHeight,这两个参数给定一个坐标,比如:

1
2
UIImage * img= [UIImage imageNamed:@"11.png"];
img = [img stretchableImageWithLeftCapWidth:1 topCapHeight:1];

这段代码的意思是将图片从左起第2列,上起第2行,坐标为(2,2)的像素点进行复制。将图片进行拉伸。这个方法和上面的方法比起来似乎灵活性更多了,但其也有它的一些局限,如果被拉伸的图片中间也有需要拉伸的像素,这个方法就无能为力了,例如,如下的一张图片,我们需要将其拉伸放大:

3、区域的拉伸

1
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets;

这个函数需要设置一个UIEdgeInsets参数,UIEdgeInsets结构体如下:

1
2
3
typedef struct UIEdgeInsets {
CGFloat top, left, bottom, right;
} UIEdgeInsets;

它分别对用了图片进行拉伸的区域距离顶部、左部、下部、右部的像素。比如,一个1010像素的图片,将UIEdgeInsets参数全部设置为1,则实际拉伸的部分就是中间的88的区域的像素。有一点需要注意,这个方法默认使用的拉伸模式是区域复制,比如还是上面的图案,如下代码拉伸:

1
2
UIImage * img= [UIImage imageNamed:@"11.png"];
img = [img resizableImageWithCapInsets:UIEdgeInsetsMake(1, 1, 1, 1)];

可以明显的看到中间的虚线,这便是区域复制的杰作。

那么问题又来了,如果某些图片中间有渐变,我们该怎么处理了,来看下一个函数。

4、拉伸模式的设置

1
2
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode;

这个函数和上一个函数相比,唯一的差别是多了一个参数。这个参数是个枚举,如下:

1
2
3
4
typedef NS_ENUM(NSInteger, UIImageResizingMode) {
UIImageResizingModeTile,//进行区域复制模式拉伸
UIImageResizingModeStretch,//进行渐变复制模式拉伸
};

现在就明了了,我们只需要设置一下模式,就可以实现渐变拉伸了:

1
2
UIImage * img= [UIImage imageNamed:@"11.png"];
img = [img resizableImageWithCapInsets:UIEdgeInsetsMake(1, 1, 1, 1) resizingMode:UIImageResizingModeStretch];

二、拉伸的用武之地

圆角按钮,空心按钮,渐变的背景,内容可变的标签,聊天气泡等等这样的素材在APP中很可能会多次出现,并且每次出现的尺寸可能还会略微有些差异,如果仅仅依靠美工的素材,恐怕不仅很难达到要求,也会额外增加软件的内存开销,这时,我们使用恰当的拉伸技巧,能使我们的代码更加健壮,APP更加高效。

三、一点小经验

你是否注意观察过最细的线?

看到上面的问句,你可能有些差异。最细的线不就是一像素么?确实,能绘图画出来的最细的实心线确实是一像素,但在一个项目中,我们优秀的美工察觉到无论她把线做的多么细,无论我怎样控制拉伸方法,绘制出的登录框总是没有QQ的细,QQ的框线看起来更加干脆利索。后来索性用绘图画出登录框,结果很不幸,我依然无法将线做到像QQ登录框那样细致。后来偶然试了一种方法,不知原理是否正确,效果总算达到了,当然这也要归功于我们的美工,她将一个图片做的很大,适配最大的分辨率,然后让我手动缩,如此一来,那线就变得非常细。


如果只拉伸左边和右边,中间不变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- (UIImage *)dc_stretchLeftAndRightWithContainerSize:(CGSize)size
{
CGSize imageSize = self.size;
CGSize bgSize = size;
//1.第一次拉伸右边 保护左边
UIImage *image = [self stretchableImageWithLeftCapWidth:imageSize.width *0.8 topCapHeight:imageSize.height * 0.5];
//第一次拉伸的距离之后图片总宽度
CGFloat tempWidth = (bgSize.width)/2 + imageSize.width/2;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(tempWidth, imageSize.height), NO, [UIScreen mainScreen].scale);
[image drawInRect:CGRectMake(0, 0, tempWidth, bgSize.height)];
//拿到拉伸过的图片
UIImage *firstStrechImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//2.第二次拉伸左边 保护右边
UIImage *secondStrechImage = [firstStrechImage stretchableImageWithLeftCapWidth:firstStrechImage.size.width *0.1 topCapHeight:firstStrechImage.size.height*0.5];
return secondStrechImage;
}

AutoLayout框架Masonry使用心得

转自 :http://www.starming.com/index.php?v=index&view=81

我们组分享会上分享了页面布局的一些写法,中途提到了AutoLayout,会后我决定将很久前挖的一个坑给填起来(还有好多坑就不说了,说了不填更毁形象了)。

可使用的框架首推Masonry,关于为啥选择Masonry看看官方文档就明白了https://github.com/SnapKit/Masonry,官方称AutoLayout所有功能Masonry都支持。这次项目界面方面我就全部使用了Masonry。

AutoLayout的一些基本概念

  • 利用约束来控制视图的大小和位置,系统会在运行时通过设置的约束计算得到frame再绘制屏幕
  • 两个属性Content Compression Resistance(排挤,值越高越固定)和Content Hugging(拥抱),Masonry代码如下
1
2
3
4
5
6
7
//content hugging 为1000
[view setContentHuggingPriority:UILayoutPriorityRequired
forAxis:UILayoutConstraintAxisHorizontal];
// content compression 为250
[view setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
forAxis:UILayoutConstraintAxisHorizontal];
  • multipler属性表示约束值为约束对象的百分比,在Masonry里有对应的multipliedBy函数

    1
    2
    //宽度为superView宽度的20%
    make.width.equalTo(superView.mas_width).multipliedBy(0.2);
  • AutoLayout下UILabel设置多行计算需要设置preferredMaxLayoutWidth

    1
    label.preferredMaxWidth = [UIScreen mainScreen].bounds.size.width - margin - padding;
  • preferredMaxLayoutWidth用来制定最大的宽,一般用在多行的UILabel中

  • systemLayoutSizeFittingSize方法能够获得view的高度
  • iOS7有两个很有用的属性,topLayoutGuide和bottomLayoutGuide,这个两个主要是方便获取UINavigationController和UITabBarController的头部视图区域和底部视图区域。
    1
    2
    //Masonry直接支持这个属性
    make.top.equalTo(self.mas_topLayoutGuide);

AutoLayout关于更新的几个方法的区别

  • setNeedsLayout:告知页面需要更新,但是不会立刻开始更新。执行后会立刻调用layoutSubviews。
  • layoutIfNeeded:告知页面布局立刻更新。所以一般都会和setNeedsLayout一起使用。如果希望立刻生成新的frame需要调用此方法,利用这点一般布局动画可以在更新布局后直接使用这个方法让动画生效。
  • layoutSubviews:系统重写布局
  • setNeedsUpdateConstraints:告知需要更新约束,但是不会立刻开始
  • updateConstraintsIfNeeded:告知立刻更新约束
  • updateConstraints:系统更新约束

Masonry使用注意事项

  • 用mas_makeConstraints的那个view需要在addSubview之后才能用这个方法
  • mas_equalTo适用数值元素,equalTo适合多属性的比如make.left.and.right.equalTo(self.view)
  • 方法and和with只是为了可读性,返回自身,比如make.left.and.right.equalTo(self.view)和make.left.right.equalTo(self.view)是一样的。
  • 因为iOS中原点在左上角所以注意使用offset时注意right和bottom用负数。

Masonry适配iOS6和iOS7时需要注意的问题

开发项目时是先在iOS8上调试完成的,测试时发现低版本的系统会发生奔溃的现象,修复后总结问题主要是在equalTo的对象指到了父视图的父视图或者父视图同级的子视图上造成的,所以做约束时如果出现了奔溃问题百分之九十都是因为这个。

Masonry使用范例

基本写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//相对于父视图边距为10
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[self.avatarView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic filler
make.left.equalTo(superview.mas_left).with.offset(padding.left);
make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom);
make.right.equalTo(superview.mas_right).with.offset(-padding.right);
}];
//相对于父视图边距为10简洁写法
[self.avatarView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(superview).with.insets(padding);
}];
//这两个作用完全一样
[self.avatarView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.greaterThanOrEqualTo(self.view);
make.left.greaterThanOrEqualTo(self.view.mas_left);
}];
//.equalTo .lessThanOrEqualTo .greaterThanOrEqualTo使用NSNumber
[self.avatarView mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.greaterThanOrEqualTo(@200);
make.width.lessThanOrEqualTo(@400);
make.left.lessThanOrEqualTo(@10);
}];
//如果不用NSNumber可以用以前的数据结构,只需用mas_equalTo就行
[self.avatarView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(42);
make.height.mas_equalTo(20);
make.size.mas_equalTo(CGSizeMake(50, 100));
make.edges.mas_equalTo(UIEdgeInsetsMake(10, 0, 10, 0));
make.left.mas_equalTo(self.view).mas_offset(UIEdgeInsetsMake(10, 0, 10, 0));
}];
//也可以使用数组
[self.avatarView mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.equalTo(@[self.view.mas_height, superview.mas_height]);
make.height.equalTo(@[self.view, superview]);
make.left.equalTo(@[self.view, @100, superview.mas_right]);
}];
// priority的使用
[self.avatarView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.greaterThanOrEqualTo(self.view.mas_left).with.priorityLow();
make.top.equalTo(self.view.mas_top).with.priority(600);
}];
//同时创建多个约束
[self.avatarView mas_makeConstraints:^(MASConstraintMaker *make) {
//让top,left,bottom,right都和self.view一样
make.edges.equalTo(self.view);
//edges
make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(5, 10, 15, 20));
//size
make.size.greaterThanOrEqualTo(self.view);
make.size.equalTo(superview).sizeOffset(CGSizeMake(100, -50));
//center
make.center.equalTo(self.view);
make.center.equalTo(self.view).centerOffset(CGPointMake(-5, 10));
//chain
make.left.right.and.bottom.equalTo(self.view);
make.top.equalTo(self.view);
}];

AutoLayout情况如何计算UITableView的变高高度

主要是UILabel的高度会有变化,所以这里主要是说说label变化时如何处理,设置UILabel的时候注意要设置preferredMaxLayoutWidth这个宽度,还有ContentHuggingPriority为UILayoutPriorityRequried

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CGFloat maxWidth = [UIScreen mainScreen].bounds.size.width - 10 * 2;
textLabel = [UILabel new];
textLabel.numberOfLines = 0;
textLabel.preferredMaxLayoutWidth = maxWidth;
[self.contentView addSubview:textLabel];
[textLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(statusView.mas_bottom).with.offset(10);
make.left.equalTo(self.contentView).with.offset(10);
make.right.equalTo(self.contentView).with.offset(-10);
make.bottom.equalTo(self.contentView).with.offset(-10);
}];
[_contentLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];

如果版本支持最低版本为iOS 8以上的话可以直接利用UITableViewAutomaticDimension在tableview的heightForRowAtIndexPath直接返回即可。

1
2
3
4
5
6
7
tableView.rowHeight = UITableViewAutomaticDimension;
tableView.estimatedRowHeight = 80; //减少第一次计算量,iOS7后支持
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// 只用返回这个!
return UITableViewAutomaticDimension;
}

但如果需要兼容iOS 8之前版本的话,就要回到老路子上了,主要是用systemLayoutSizeFittingSize来取高。步骤是先在数据model中添加一个height的属性用来缓存高,然后在table view的heightForRowAtIndexPath代理里static一个只初始化一次的Cell实例,然后根据model内容填充数据,最后根据cell的contentView的systemLayoutSizeFittingSize的方法获取到cell的高。具体代码如下

//在model中添加属性缓存高度
@interface DataModel : NSObject
@property (copy, nonatomic) NSString *text;
@property (assign, nonatomic) CGFloat cellHeight; //缓存高度
@end

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
static CustomCell *cell;
//只初始化一次cell
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([CustomCell class])];
});
DataModel *model = self.dataArray[(NSUInteger) indexPath.row];
[cell makeupData:model];
if (model.cellHeight <= 0) {
//使用systemLayoutSizeFittingSize获取高度
model.cellHeight = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + 1;
}
return model.cellHeight;
}

动画

因为布局约束就是要脱离frame这种表达方式的,可是动画是需要根据这个来执行,这里面就会有些矛盾,不过根据前面说到的布局约束的原理,在某个时刻约束也是会被还原成frame使视图显示,这个时刻可以通过layoutIfNeeded这个方法来进行控制。具体代码如下

1
2
3
4
5
6
7
8
9
10
11
[aniView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.bottom.left.right.equalTo(self.view).offset(10);
}];
[aniView mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.view).offset(30);
}];
[UIView animateWithDuration:3 animations:^{
[self.view layoutIfNeeded];
}];

参考文章

除非注明,均为Starming星光社原创,微信公共号 starming-weixin 发现更多,转载请注明本文地址:http://www.starming.com/index.php?v=index&view=81

寻找上层的ViewController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
extension UIView {
func findController() -> UIViewController! {
return self.findControllerWithClass(UIViewController.self)
}
func findNavigator() -> UINavigationController! {
return self.findControllerWithClass(UINavigationController.self)
}
func findControllerWithClass<T>(clzz: AnyClass) -> T? {
var responder = self.nextResponder()
while(responder != nil) {
if (responder!.isKindOfClass(clzz)) {
return responder as? T
}
responder = responder?.nextResponder()
}
return nil
}
}

还有一种通过rootviewController 寻找的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//获取当前屏幕显示的viewcontroller
- (UIViewController *)getCurrentVC
{
UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
UIViewController *currentVC = [self getCurrentVCFrom:rootViewController];
return currentVC;
}
- (UIViewController *)getCurrentVCFrom:(UIViewController *)rootVC
{
UIViewController *currentVC;
if ([rootVC presentedViewController]) {
// 视图是被presented出来的
rootVC = [rootVC presentedViewController];
}
if ([rootVC isKindOfClass:[UITabBarController class]]) {
// 根视图为UITabBarController
currentVC = [self getCurrentVCFrom:[(UITabBarController *)rootVC selectedViewController]];
} else if ([rootVC isKindOfClass:[UINavigationController class]]){
// 根视图为UINavigationController
currentVC = [self getCurrentVCFrom:[(UINavigationController *)rootVC visibleViewController]];
} else {
// 根视图为非导航类
currentVC = rootVC;
}
return currentVC;
}
//swift
/// 获取当前显示的VC
func getCurrentVC()->UIViewController{
let rootViewController = (UIApplication.shared.delegate as! AppDelegate).window?.rootViewController
// if rootViewController == nil{return nil}
let currentVC = self.getCurrentVCFrom(rootVC: rootViewController!)
return currentVC
}
fileprivate func getCurrentVCFrom(rootVC:UIViewController)->UIViewController{
//var currentVC:UIViewController!;
var currentVC:UIViewController = rootVC; // 这里先赋值处理,不然会崩溃(特定条件下)
var rootVC2 = rootVC
if rootVC.presentedViewController != nil{
rootVC2 = rootVC2.presentedViewController!
}
if (rootVC2.isKind(of: UITabBarController.classForCoder())){
rootVC2 = self.getCurrentVCFrom(rootVC: (rootVC2 as! UITabBarController).selectedViewController!)
}else if rootVC2.isKind(of: UINavigationController.classForCoder()){
currentVC = self.getCurrentVCFrom(rootVC: (rootVC2 as! UINavigationController).visibleViewController!)
}else{
currentVC = rootVC2
}
return currentVC
}

webCookie 设置,自动登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
var param = ""
if self.webUrl.rangeOfString("?") != nil{
param = "&random=\(random)"
}else{
param = "?random=\(random)"
}
let webNSUrl = NSURL(string: (self.webUrl+param))!
if (webNSUrl).host?.rangeOfString("chenzhao.date") != nil{
var is3Gcookie = false
let cookies_1 = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies
if cookies_1 != nil{
for c in cookies_1!{
if c.name == "COOKIE"{
// NSHTTPCookieStorage.sharedHTTPCookieStorage().deleteCookie(c)
if c.value == UserInfo.userInstance.jKey{
is3Gcookie = true
}else{
NSHTTPCookieStorage.sharedHTTPCookieStorage().deleteCookie(c)
}
}
}
}
if UserInfo.userInstance.key != ""{
if is3Gcookie == false{
let cookieProperties = [NSHTTPCookieName:"COOKIE",
NSHTTPCookieValue:UserInfo.userInstance.key,
NSHTTPCookieDomain:".chenzhao.date",
NSHTTPCookiePath:"/", //mark 位置"/"是域名的全网
// NSHTTPCookieVersion:"0",
]
//
let cookie = NSHTTPCookie(properties:cookieProperties)
// Getdevice.println("手动组成的cookie\(cookie) : path = \(webNSUrl.path!) :host = \(webNSUrl.host!)")
if cookie != nil{
NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookie(cookie!)
}
}
}
}
let cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies
let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!)
// Getdevice.println("加载数据设置headers cookies:\(headers)")
let request = NSMutableURLRequest(URL: webNSUrl, cachePolicy: NSURLRequestCachePolicy.UseProtocolCachePolicy, timeoutInterval: 20)
request.HTTPShouldHandleCookies = true
request.allHTTPHeaderFields = headers
// request.addValue("测试", forHTTPHeaderField: "test")
webView.loadRequest(request)

获取APP的Launch Image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Tips:获取APPLaunch Image
+ (UIImage *)getLanchImage
{
CGSize viewSize = CGSizeMake([[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height);
NSString *viewOrientation = @"Portrait"; //横屏请设置成 @"Landscape"
NSString *launchImage = nil;
NSArray* imagesDict = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"UILaunchImages"];
for (NSDictionary* dict in imagesDict)
{
CGSize imageSize = CGSizeFromString(dict[@"UILaunchImageSize"]);
if (CGSizeEqualToSize(imageSize, viewSize) && [viewOrientation isEqualToString:dict[@"UILaunchImageOrientation"]])
{
launchImage = dict[@"UILaunchImageName"];
}
}
// UIImageView *launchView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:launchImage]];
// launchView.frame = [[UIScreen mainScreen] bounds];
// launchView.contentMode = UIViewContentModeScaleAspectFill;
// [self.window addSubview:launchView];
return [UIImage imageNamed:launchImage];
}

UICollectionViewFlowLayout最大间距设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//
// DanceTeamSearchLayout.swift
// boosjdance
//
// Created by boosj on 16/8/29.
// Copyright © 2016年 cz. All rights reserved.
//
//swift3
import UIKit
/// 舞队 搜索记录的layout
class DanceTeamSearchLayout: UICollectionViewFlowLayout {
//我们想设置的最大间距,可根据需要改
//var maximumSpacing:CGFloat = 10
/**
重写当前方法 实现控制item最大间距
- parameter rect: rect 绘图范围
- returns: item属性数组
*/
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElements(in: rect)
if attributes != nil{
for i in 0 ..< attributes!.count{
if i == 0{
let current = attributes![i]
var frame = current.frame
frame.origin.x = 10
current.frame = frame
continue
}
//当前attributes
let current = attributes![i]
//上一个attributes
let prevLayoutAttributes = attributes![ (i - 1)]
//前一个cell的最右边
let origin = prevLayoutAttributes.frame.maxX
// var yOffset = current.frame.origin.y
//如果当前一个cell的最右边加上我们想要的间距加上当前cell的宽度依然在contentSize中,我们改变当前cell的原点位置
//不加这个判断的后果是,UICollectionView只显示一行,原因是下面所有cell的x值都被加到第一行最后一个元素的后面了
// self.minimumInteritemSpacing 列间距
if (origin + self.minimumInteritemSpacing + current.frame.size.width)<self.collectionViewContentSize.width{
var frame = current.frame
frame.origin.x = origin + self.minimumInteritemSpacing
current.frame = frame
}else{
var frame = current.frame
frame.origin.x = self.sectionInset.left // 边缘的预留宽度
// frame.origin.y = yOffset + frame.height + maximumSpacing
current.frame = frame
}
// printLog("cell测试frame: \(current.frame)")
}
}
return attributes
}
/*
如果我们的布局是会时刻变化的, 需要在滚动的过程中重新布局 , 那么我们需要
设置这个方法的返回值为true, 默认为false
* 当返回值为true的时候会将collectionView的layout设置为invalidated,
将会使collectionView重新调用上面的prepareLayout()...方法重新获得布局
* 同时, 当屏幕旋转的时候collectionView的bounds也会调用这个方法
如果设置为false, 那么将不会达到屏幕适配的效果,
* 需要注意的是, 当collectionView执行一些操作(delete insert reload)等的时候,
不会调用这个方法, 会直接重新调用上面的prepareLayout()...方法重新获得布局
*/
// override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
// return true
// }
}

一个左对齐

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//
// UICollectionViewLeftAlignedLayout.swift
// test
//
// Created by boosj on 2017/8/14.
// Copyright © 2017年 boosjcz. All rights reserved.
//
import UIKit
extension UICollectionViewLayoutAttributes {
/** 每行第一个item左对齐 **/
func leftAlignFrame(_ sectionInset:UIEdgeInsets) {
var frame = self.frame
frame.origin.x = sectionInset.left
self.frame = frame
}
}
class UICollectionViewLeftAlignedLayout: UICollectionViewFlowLayout {
//MARK: - 重新UICollectionViewFlowLayout的方法
override init() {
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
/** Collection所有的UICollectionViewLayoutAttributes */
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributesToReturn = super.layoutAttributesForElements(in: rect)!
var attributesCopy = [UICollectionViewLayoutAttributes]()
for attributes in attributesToReturn {
if nil == attributes.representedElementKind {
let itemAttributesCopy = attributes.copy() as! UICollectionViewLayoutAttributes
let indexPath = itemAttributesCopy.indexPath
itemAttributesCopy.frame = self.layoutAttributesForItem(at: indexPath)!.frame
// manipulate itemAttributesCopy
attributesCopy.append(itemAttributesCopy)
}else{
// 忘记把这里app下 所以才没有进 头部代理
attributesCopy.append(attributes)
}
}
return attributesCopy // (copy 版 数据 防止警告 ,但是会无发进入头部代理)
}
//
/** 每个item的UICollectionViewLayoutAttributes */
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
//现在item的UICollectionViewLayoutAttributes
let currentItemAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as! UICollectionViewLayoutAttributes
//现在section的sectionInset
let sectionInset = self.evaluatedSectionInset(indexPath.section)
//是否是section的第一个item
let isFirstItemInSection = indexPath.item == 0
//出去section偏移量的宽度
let layoutWidth: CGFloat = self.collectionView!.frame.width - sectionInset.left - sectionInset.right
//是section的第一个item
if isFirstItemInSection {
//每行第一个item左对齐
currentItemAttributes.leftAlignFrame(sectionInset)
return currentItemAttributes
}
//前一个item的NSIndexPath
let previousIndexPath = IndexPath(item: indexPath.item - 1, section: indexPath.section)
//前一个item的frame
let previousFrame = self.layoutAttributesForItem(at: previousIndexPath)!.frame
//为现在item计算新的left
let previousFrameRightPoint: CGFloat = previousFrame.origin.x + previousFrame.size.width
//现在item的frame
let currentFrame = currentItemAttributes.frame
//现在item所在一行的frame
let strecthedCurrentFrame = CGRect(x: sectionInset.left, y: currentFrame.origin.y, width: layoutWidth, height: currentFrame.size.height)
//previousFrame和strecthedCurrentFrame是否有交集,没有,说明这个item和前一个item在同一行,item是这行的第一个item
let isFirstItemInRow = !previousFrame.intersects(strecthedCurrentFrame)
//item是这行的第一个item
if isFirstItemInRow {
//每行第一个item左对齐
currentItemAttributes.leftAlignFrame(sectionInset)
return currentItemAttributes
}
//不是每行的第一个item
var frame = currentItemAttributes.frame
//为item计算新的left = previousFrameRightPoint + item之间的间距
frame.origin.x = previousFrameRightPoint + self.evaluatedMinimumInteritemSpacing(indexPath.item)
//为item的frame赋新值
currentItemAttributes.frame = frame
return currentItemAttributes
}
//MARK: - System
/** item行间距 **/
fileprivate func evaluatedMinimumInteritemSpacing(_ ItemAtIndex:Int) -> CGFloat {
if let delete = self.collectionView?.delegate {
weak var delegate = (delete as! UICollectionViewDelegateFlowLayout)
if delegate!.responds(to: #selector(UICollectionViewDelegateFlowLayout.collectionView(_:layout:minimumInteritemSpacingForSectionAt:))) {
let mini = delegate?.collectionView!(self.collectionView!, layout: self, minimumInteritemSpacingForSectionAt: ItemAtIndex)
if mini != nil {
return mini!
}
}
}
return self.minimumInteritemSpacing
}
/** section的偏移量 **/
fileprivate func evaluatedSectionInset(_ itemAtIndex:Int) -> UIEdgeInsets {
if let delete = self.collectionView?.delegate {
weak var delegate = (delete as! UICollectionViewDelegateFlowLayout)
if delegate!.responds(to: #selector(UICollectionViewDelegateFlowLayout.collectionView(_:layout:insetForSectionAt:))) {
let sectionInset = delegate?.collectionView!(self.collectionView!, layout: self, insetForSectionAt: itemAtIndex)
if sectionInset != nil {
return sectionInset!
}
}
}
return self.sectionInset
}
}

设置文本的部分文本的颜色NSMutableAttributedString 样式文本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/**
设置需要的文本颜色
:param: text 需要设置颜色的文本
:returns: return NSMutableAttributedString
*/
func setTextColor(number:String)->NSMutableAttributedString{
let testNumber = (number as NSString).length
let titlestr = "共\(number)个视频"
var str = NSMutableAttributedString(string: titlestr)
str.addAttribute(NSForegroundColorAttributeName, value: violetColor, range: NSMakeRange(1,testNumber)) // testNumber 为多少个字有颜色
return str
}
/**
设置第二行文本 和文本颜色设置
:param: title title 第二行标题文本
:param: begin begin 颜色设置开始位置
:param: end end 颜色设置多少个字符
*/
func setTwoTitle(title:String,begin:Int,count:Int)
{
var str = NSMutableAttributedString(string: title)
str.addAttribute(NSForegroundColorAttributeName, value: violetColor, range: NSMakeRange(begin,count))
self.titleLabel_2.attributedText = str
}
以前看到这种字号和颜色不一样的字符串,想出个讨巧的办法就是“¥150”一个UILable,“元/位”一个UILable。今天翻看以前的工程,command点进UITextField中看到[attributedText]这个关键字,以前都没注意过UITextField还有这个属性,其实UITextViewUILable也有这个属性,iOS6就已经有了,说来惭愧,对此罚站1秒钟。
NSAttributedString叫做富文本,是一种带有属性的字符串,通过它可以轻松的在一个字符串中表现出多种字体、字号、字体大小等各不相同的风格,还可以对段落进行格式化。
通过以下代码即可实现上面图示效果,十分方便,从此再也不用设置两个UILable,并且处心积虑的处理它们的长度了。
1 UILabel * aLable = [[UILabel alloc] initWithFrame:CGRectMake(100, 500, 200, 40)];
2 aLable.textAlignment = NSTextAlignmentCenter;
3 [self.view addSubview:aLable];
4
5 NSString * aString = @"¥150 元/位";
6
7 //富文本对象
8 NSMutableAttributedString * aAttributedString = [[NSMutableAttributedString alloc] initWithString:aString];
9
10 //富文本样式
11 [aAttributedString addAttribute:NSForegroundColorAttributeName //文字颜色
12 value:[UIColor redColor]
13 range:NSMakeRange(0, 4)];
14
15 [aAttributedString addAttribute:NSFontAttributeName //文字字体
16 value:[UIFont systemFontOfSize:25]
17 range:NSMakeRange(0, 4)];
18
19 aLable.attributedText = aAttributedString;
常用属性:
NSFontAttributeName           文字字体
NSParagraphStyleAttributeName     段落样式(字符串通过“\n”进行分段,此设置必须在lable.numberOfLines = 0时有效,value通过NSMutableParagraphStyle设置,它有以下属性)
[段落样式-插曲]
1 @property(readwrite) CGFloat lineSpacing; //行间距
2 @property(readwrite) CGFloat paragraphSpacing; //段间距
3 @property(readwrite) NSTextAlignment alignment; //对齐方式
4 @property(readwrite) CGFloat firstLineHeadIndent; //首行缩紧
5 @property(readwrite) CGFloat headIndent; //除首行之外其他行缩进
6 @property(readwrite) CGFloat tailIndent; //每行容纳字符的宽度
7 @property(readwrite) NSLineBreakMode lineBreakMode; //换行方式
8 @property(readwrite) CGFloat minimumLineHeight; //最小行高
9 @property(readwrite) CGFloat maximumLineHeight; //最大行高
10 @property(readwrite) NSWritingDirection baseWritingDirection; //书写方式(NSWritingDirectionNatural,NSWritingDirectionLeftToRight,NSWritingDirectionRightToLeft)
11 @property(readwrite) CGFloat lineHeightMultiple;
12 @property(readwrite) CGFloat paragraphSpacingBefore;
13 @property(readwrite) float hyphenationFactor;
14 @property(readwrite,copy,NS_NONATOMIC_IOSONLY) NSArray *tabStops NS_AVAILABLE_IOS(7_0);
15 @property(readwrite,NS_NONATOMIC_IOSONLY) CGFloat defaultTabInterval NS_AVAILABLE_IOS(7_0);
[段落样式demo]
1 UILabel * lable = [[UILabel alloc] initWithFrame:CGRectMake(50, 100, self.view.frame.size.width-100, 200)];
2 lable.backgroundColor = [UIColor lightGrayColor];
3 lable.numberOfLines = 0;
4 [self.view addSubview:lable];
5
6 NSString * string = @"Always believe that something wonderful is about \nto happen!";
7
8 //富文本
9 NSMutableAttributedString * attributedString = [[NSMutableAttributedString alloc] initWithString:string];
10
11 //段落样式
12 NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
13
14 #warning lable.numberOfLines必须为0,段落样式才生效
15 //行间距
16 paragraphStyle.lineSpacing = 10.0;
17 //段落间距
18 paragraphStyle.paragraphSpacing = 20.0;
19
20 // paragraphStyle.baseWritingDirection = NSWritingDirectionLeftToRight;
21 // paragraphStyle.firstLineHeadIndent = 10.0;
22 // paragraphStyle.headIndent = 50.0;
23 // paragraphStyle.tailIndent = 200.0;
24
25 [attributedString addAttribute:NSParagraphStyleAttributeName
26 value:paragraphStyle
27 range:NSMakeRange(0, string.length)];
28
29 lable.attributedText = attributedString;
NSForegroundColorAttributeName    文字前景色
NSBackgroundColorAttributeName    文字背景色
NSLigatureAttributeName        连体字(NSNumber @0:无连体,@1:默认连体,系统字体不包含对连体的支持)
NSUnderlineStyleAttributeName     下划线
NSStrokeColorAttributeName       只有在NSStrokeWidthAttributeName设置了值之后才有效(默认字体颜色和前景色一致,如果设置的颜色和前景色不一致则前景色无效)
NSStrokeWidthAttributeName      设置该属性之后字体变成空心字体,字体边线宽度为value设定的值
NSBaselineOffsetAttributeName     值为NSNumber类型,表明文字相对于其他文字基准线向上的偏移量
NSUnderlineColorAttributeName     值为UIColor类型,下划线颜色(只有在NSUnderlineStyleAttributeName的value为@1时有效)
NSUnderlineStyleAttributeName     值为NSNumber类型,下划线宽度(默认值为@0:下划线宽度为0——不现实下划线,@1:字符串有下划线)
属性挺多的,有其他需要的话command点进去看一下就ok,如果对他们的功能不了解三根指头点一下关键词,或者按住option点一下看看官方文档的Description相信就会有所了解了,其他的暂时就不介绍了。
如有问题,欢迎指正,小弟在此拜谢。
这里有篇讲解富文本的文章:http://www.2cto.com/kf/201409/334308.html