iOS踩坑系列-1

iOS踩坑系列记录自己编码过程中遇到的坑,然后给出相应的解决办法。记录自己技术成长之路。

在这篇博文中记录了如下问题:

  • 定制UISearchBar
  • 设置navigationBar为透明
  • iOS7 图片毛玻璃效果
  • 正确设置UITableView的sectionHeader的高度
  • 获取按钮所在的cell所在行号
  • xib创建UITableview的header导致首行cell被遮盖

1、定制UISearchBar

1.1、定制取消按钮的文字

默认情况searchBar的取消按钮字样是cancel,如果项目中需要改变取消按钮的文字为其他字样。可以使用下面的方法

id barButtonAppearanceInSearchBar = [UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil];

[barButtonAppearanceInSearchBar setBackgroundImage:grayBackgroundImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[barButtonAppearanceInSearchBar setTitleTextAttributes:@{
                                      NSFontAttributeName : [UIFont fontWithName:@"HelveticaNeue-CondensedBold" size:20],
                                 NSForegroundColorAttributeName : [UIColor blackColor]
     } forState:UIControlStateNormal];
[barButtonAppearanceInSearchBar setTitle:@"XXXXX"];


或者
NSMutableDictionary *attr = [NSMutableDictionary dictionary];  
attr[NSFontAttributeName] = [UIFont systemFontOfSize:13];  
attr[NSForegroundColorAttributeName] = [UIColor redColor];  
[[UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class] , nil] setTitle:@"XXXXX"];
[[UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil] setTitleTextAttributes:attr forState:UIControlStateNormal];
[self.searchBar setShowsCancelButton:YES animated:YES];
1.2、修改cancel文字为中文"取消"

如果仅仅只需要改变取消按钮的文字从英文cancel到中文取消字样,只需要设置本地化为China即可,如下所示:

1.3、修改searchBar输入框背景色
self.searchBar.barTintColor = [UIColor clearColor];  
    UITextField *searchTextField = [[[[self.searchBar subviews ]firstObject] subviews] lastObject];
    searchTextField.backgroundColor = [UIColor lightGrayColor];

参考文章:http://www.jianshu.com/p/84af53995789


2、设置navigationBar为透明

很多时候我们需要设置navigationBar为透明,按时又要保证上面的按钮不是透明的。可以使用下面的方法

//进入视图的时候设置alpha为0
- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
//设置背景颜色,不设置就是默认白色毛玻璃,和下面的方法结合可以设置半透明带色彩的navigationBar
self.navigationController.navigationBar.barTintColor = BACKGROUND_COLOR  
        [[[self.navigationController.navigationBar subviews]objectAtIndex:0] setAlpha:0.0];
     }

//视图消失的时候还原alpha为1
- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    [[[self.navigationController.navigationBar subviews]objectAtIndex:0] setAlpha:1.0];
}

上面的方法其实是取出了navigationBar的背景view然后设置透明度,如下图红框所示: 这个背景UiView在公开navigationBar的API没有提供访问属性,我们需要自己取出来。我们在做navigationBar背景透明和背景透明度渐变,还有设置背景图片,都可以通过这个UIView来实现。 也可以通过下面的代码取出这个View

UIView *backgroundView =  [self.navigationController valueForKeyPath:@"navigationBar.backgroundView"]  

3、iOS 7 实现图片毛玻璃效果

iOS 8系统自带了毛玻璃效果,使用UIVisualEffectView即可。但是iOS 7就没这么好的事了,我们需要自己实现。
找了很多文档,苹果给出过一个demo,实现iOS7上的毛玻璃效果。但是感觉效果不太好。

下面是一个第三方库,经过试验,发现完全可以媲美iOS 8系统的UIVisualEffectView毛玻璃效果。关键兼容iOS 7哦。使用方法很简单。直接去作者的github看吧:

地址: https://github.com/Adrian2112/UIImage-BlurredFrame

但是如果你不满意作者提供的几种毛玻璃效果,你可以自己尝试修改参数定制自己想要的效果。

比如下面是轻度毛玻璃效果的代码:

- (UIImage *)applyLightEffectAtFrame:(CGRect)frame
{
    UIImage *blurredFrame = [[self croppedImageAtFrame:frame] applyLightEffect];
    return [self addImageToImage:blurredFrame atRect:frame];
}

影响效果的是方法applyLightEffect,我们看看这个方法的实现

- (UIImage *)applyLightEffect
{
    UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3];
    return [self applyBlurWithRadius:30 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
}

这个模糊效果和iOS8的蒙板效果类似,tintColor是设置蒙板灰度的,从最白到最黑,还可以设置alpha。

关键是第二句,我们可以调整很多参数,我们一个个的来看看吧。

  • applyBlurWithRadius:模糊后图像的清晰度,越小越清晰,越大越模糊
  • tintColor:类似于iOS8的蒙板效果,这里设置的蒙板的颜色。
  • saturationDeltaFactor:颜色饱和度,越大颜色越鲜艳
  • maskImage:在原来要被模糊的image上面再盖上一个image

4、正确设置UITableView的sectionHeader的高度

我们在使用group样式的tableview的时候,希望第一个section的第一个cell和导航栏无缝隙的紧挨着,如是我们作如下设置:

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:UITableViewStyleGrouped];
    return self;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    if (section == 0) {
        return 0;
    }else{
        return 32;
    }
}

但是设置完了效果如下: 如红框部分所示,我们虽然这是了section = 0的时候sectionHeader的高度为0,但是系统并没有按照我们设置的去做。 这是因为如果设置为0,系统并不会设置高度为0 ,而是设置为默认值。这个时候我们需要作如下设置才可以。

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    if (section == 0) {
        //CGFLOAT_MIN表示最小浮点值,无限接近于0
        return  CGFLOAT_MIN;
    }else{
        return 32;
    }
}

还有一种情况是,我们想设置section=0和其他情况时,sectionHeader的高度是不同的。 我们先做如下设置:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    if (section == 0) {
        return 16;
    }else{
        return 32;
    }
}

完成后效果图如下: 可以发现第一个section的头部高度只有第二个section头部高度的1/4。

原因如下: 如上代码,表示默认就设置sectionfooter的高度等于sectionheader的高度,所以第二个section的顶部高度是第一个section的footer高度32+第二个section的header高度32=64。

要想正确显示需要做如下设置:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    if (section == 0) {
        return 16;
    }else{
        return 32;
    }
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
    return CGFLOAT_MIN;;
}

5、获取按钮所在的cell的行号

我在项目中总是会遇到这样的情况:在UITableViewCell中添加了一个UIButton,UIButton点击后触发buttonPress:方法,在方法被调用后需要知道用户点击的是哪一个Cell。

实现代码如下:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    SGPushManagerCell *cell = [tableView dequeueReusableCellWithIdentifier:SGCellId];
        [cell.button  addTarget:self action:@selector(buttonClick:)  forControlEvents:UIControlEventTouchUpInside];
        return cell;
 }

- (void)buttonClick:(UIButton *)sender{
    UITableViewCell *cell = (UITableViewCell *)sender.superview.superview;
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
//获取被点击的button所在的row
    NSInteger row = indexPath.row;

6、xib创建UITableview的header导致首行cell被遮盖

项目中我们可能会结合xib和代码的方式来构建界面,因为有时候界面的元素较多,使用代码构建费时费力。这个时候我选择使用xib构建,然后添加到代码中即可。

前阵子写项目的时候,我使用xib创建一个UIView(名字为headerView),然后设置好控件布局。然后在tableviewcontroller里面使用self.tableView.tableHeaderView = headerView设置刚才使用xib创建的UIView为tableview的headerView。

但是发现一个问题,headerView会遮挡住下面的cell,最后发现这是因为使用上面的方法创建的headerView和下面的cell不在同一个层次上面导致的。解决办法有两种:

方案一、修改tableviewController的代码
//我是手动创建一个View ,设置这个view为tableHeaderVIew,再把XIB的headerView放在这个view上面。

    UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0,ScreenWidth , 348)];
    self.headerView = [SGMeHeaderView createView];
    self.headerView.frame = CGRectMake(0, 0, ScreenWidth, 348);
    [headerView addSubview:self.headerView];
    self.tableView.tableHeaderView = headerView;

------------------------------

SGMeHeaderView.m文件  
======================
+ (instancetype)createView
{
    return [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil] firstObject];
}
方案二、改变xib为UITableViewCell

因为使用UIView的xib设置的headerView和tableview本身的cell不是同一层级,所以把本来继承自UIView的xib改为继承自UITbaleViewCell即可。 在tableViewController里面设置self.headerView = [SGMeHeaderView createView]; 即可。


comments powered by Disqus