ios中常用的小技巧(总有你不知道的和你会用到的)
一、父视图设置的透明度影响到子视图的透明度问题
UIView *darkView = [[UIView alloc] init];
//[darkView setAlpha:0];//会影响到子时图
[darkView setUserInteractionEnabled:NO];
[darkView setFrame:(CGRect){0, 0, SCREEN_SIZE}];
//[darkView setBackgroundColor:LCColor(46, 49, 50)];
darkView.backgroundColor = [[UIColor colorWithRed:46/255.0f green:49/255.0f blue:50/255.0f alpha:1.0f] colorWithAlphaComponent:LC_DEFAULT_BACKGROUND_OPACITY];//这样父视图透明不影响子时图
你是不是也遇到过这样的问题,一个button或者label,只要右边的两个角圆角,或者只要一个圆角。该怎么办呢。这就需要图层蒙版来帮助我们了。
CGRectrect=CGRectMake(0,0,100,50);
CGSizeradio=CGSizeMake(5,5);//圆角尺寸
UIRectCornercorner=UIRectCornerTopLeft|UIRectCornerTopRight;//这只圆角位置
UIBezierPath*path=[UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:corner cornerRadii:radio];
CAShapeLayer*masklayer=[[CAShapeLayeralloc]init];//创建shapelayer
masklayer.frame=button.bounds;
masklayer.path=path.CGPath;//设置路径
button.layer.mask=masklayer;
举例为button,其它继承自UIView的控件都可以
三、navigationBar的透明问题
<pre name="code" class="objc" style="color: rgb(46, 46, 46); font-size: 15px; line-height: 24px;">//给navigationBar设置一个空的背景图片即可实现透明,而且标题按钮都在
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]forBarMetrics:UIBarMetricsDefault];
细心的你会发现上面有一条线?
首先我们看一下苹果官方给出的解释:
现在让我这个英语半吊子来翻译一下,他的意思就是说如果你不调用这个方法设置一张背景图片的话,那我就给你默认一张,然后同时还有一张阴影图片被默认设置上去,好吧,这就是导航栏上1px黑线的由来,没错,就是这个苹果赠送的shadowImage。
相信看到这个解释即使不继续说下去有些同学也知道解决办法了吧,没错嘛,你就用上面说的那个方法,给设置一张背景图片,然后在设置一张shadowImage就可以了,就像这样:
self.navigationController.navigationBar.shadowImage = [UIImage new];
//其实这个线也是image控制的。设为空即可
根据UI的设计,navigationbar需要跟界面一体化,但是下面这根黑线是比较烦的问题,可能界面一需要隐藏,界面二就要出现,也可能需要改变粗细之类的,又因为navigationbar会影响接下来的推栈,所以需要做一点小改动.
方法2:直接隐藏:
//在页面出现的时候就将黑线隐藏起来
-(void)viewWillAppear:(BOOL)animated
{
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setShadowImage:[UIImage new]];
}
//在页面消失的时候就让navigationbar还原样式
-(void)viewWillDisappear:(BOOL)animated{
[self.navigationController.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setShadowImage:nil];
}
这个方法唯一的不好就是会影响导航栏的translucent(透明)属性
方法3:找出黑线,再做处理:
//通过一个方法来找到这个黑线(findHairlineImageViewUnder):
- (UIImageView *)findHairlineImageViewUnder:(UIView *)view {
if ([view isKindOfClass:UIImageView.class] && view.bounds.size.height <= 1.0) {
return (UIImageView *)view;
}
for (UIView *subview in view.subviews) {
UIImageView *imageView = [self findHairlineImageViewUnder:subview];
if (imageView) {
return imageView;
}
}
return nil;
}
//再定义一个imageview来等同于这个黑线
UIImageView *navBarHairlineImageView;
navBarHairlineImageView = [self findHairlineImageViewUnder:self.navigationController.navigationBar];
同样的在界面出现时候开启隐藏
-(void)viewWillAppear:(BOOL)animated
{
navBarHairlineImageView.hidden = YES;
}
//在页面消失的时候就让出现
-(void)viewWillAppear:(BOOL)animated
{
navBarHairlineImageView.hidden = NO;
}
如果想要做一些更好的处理,比如说改变粗细,颜色之类的也在界面出现的时候写就行了.
推荐使用第二种方法,因为整个项目都在使用导航栏推栈,出栈,很可能因为改变了样式,导致后面的属性混乱起来.
方法4.下一个解决办法,将UINavigationBar的clipsToBounds属性设成YES就好啦,从此黑线去无踪。
方法5.最后一个办法,就是循环遍历一下UINavigationBar的所有子视图,发现有UIImageView类型的视图就remove掉,或者设成隐藏状态(hidden)。虽然也能达到想要的效果,但是感觉这个方法太暴力了,不是很推荐。
//navigationBar是一个复合视图,它是有许多个控件组成的,那么我们就可以从他的内部入手
[[self.navigationController.navigationBar subviews] objectAtIndex:0].alpha = 0;//这里可以根据scrollView的偏移量来设置alpha就实现了渐变透明的效果
四、全局设置navigationBar标题样式和barItem的标题样式
//UIColorWithHexRGB( )这个方法是自己定义的,这里只需要给个颜色就好了
[[UINavigationBar appearance] setBarTintColor:UIColorWithHexRGB(0xfefefe)];
[[UINavigationBar appearance] setTitleTextAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:18],NSForegroundColorAttributeName:UIColorWithHexRGB(0xfe6d27)}];
[[UITabBarItem appearance] setTitleTextAttributes:@{NSFontAttributeName : [UIFont boldSystemFontOfSize:10],NSForegroundColorAttributeName : UIColorWithHexRGB(0x666666)} forState:UIControlStateNormal];
五、navigationBar隐藏和显示的过度
在返回后将要出现的页面实现viewWillAppear方法,需要隐藏就设为YES,需要显示就设为NO
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:NO animated:YES];
}
六、给webView添加头视图
UIView *webBrowserView = self.webView.scrollView.subviews[0];//拿到webView的webBrowserView
self.backHeadImageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenWidth*2/3.0)];
[_backHeadImageView sd_setImageWithURL:[NSURL URLWithString:self.imageUrl] placeholderImage:[UIImage imageNamed:@"placeholderImage"]];
[self.webView insertSubview:_backHeadImageView belowSubview:self.webView.scrollView];
//把backHeadImageView插入到webView的scrollView下面
CGRect frame = self.webBrowserView.frame;
frame.origin.y = CGRectGetMaxY(_backHeadImageView.frame);
self.webBrowserView.frame = frame;
//更改webBrowserView的frame向下移backHeadImageView的高度,使其可见
七、模态跳转的动画设置
DetailViewController *detailVC = [[DetailViewController alloc]init];
//UIModalTransitionStyleFlipHorizontal 翻转
//UIModalTransitionStyleCoverVertical 底部滑出
//UIModalTransitionStyleCrossDissolve 渐显
//UIModalTransitionStylePartialCurl 翻页
detailVC.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentViewController:detailVC animated:YES completion:nil];
八、图片处理:只拿图片的一部分
UIImage *image = [UIImage imageNamed:filename];
CGImageRef imageRef = image.CGImage;
CGRect rect = CGRectMake(origin.x, origin.y ,size.width, size.height);
//这里的宽高是相对于图片的真实大小
//比如你的图片是400x400的那么(0,0,400,400)就是图片的全尺寸,想取哪一部分就设置相应坐标即可
CGImageRef imageRefRect = CGImageCreateWithImageInRect(imageRef, rect);
UIImage *imageRect = [[UIImage alloc] initWithCGImage:imageRefRect];
九、给TableView或者CollectionView的cell添加简单的动画,像这样
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
NSArray *array = tableView.indexPathsForVisibleRows;
NSIndexPath *firstIndexPath = array[0];
//设置anchorPoint
cell.layer.anchorPoint = CGPointMake(0, 0.5);
//为了防止cell视图移动,重新把cell放回原来的位置
cell.layer.position = CGPointMake(0, cell.layer.position.y);
//设置cell 按照z轴旋转90度,注意是弧度
if (firstIndexPath.row < indexPath.row) {
cell.layer.transform = CATransform3DMakeRotation(M_PI_2, 0, 0, 1.0);
}else{
cell.layer.transform = CATransform3DMakeRotation(- M_PI_2, 0, 0, 1.0);
}
cell.alpha = 0.0;
[UIView animateWithDuration:1 animations:^{
cell.layer.transform = CATransform3DIdentity;
cell.alpha = 1.0;
}];
}
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row % 2 != 0) {
cell.transform = CGAffineTransformTranslate(cell.transform, kScreenWidth/2, 0);
}else{
cell.transform = CGAffineTransformTranslate(cell.transform, -kScreenWidth/2, 0);
}
cell.alpha = 0.0;
[UIView animateWithDuration:0.7 animations:^{
cell.transform = CGAffineTransformIdentity;
cell.alpha = 1.0;
} completion:^(BOOL finished) {
}];
}
十、点击屏幕隐藏键盘
(1)在ViewController的viewDidload方法中增加一个点击手势,
UITapGestureRecognizer *tap =
[[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
(2)实现dissmissKeyboard方法 在方法内隐藏键盘
[textField resignFirstResponder];//textField是需要监听的UITextField对象
十一、隐藏UITabbar
detailViewController *dc = [[detailViewController alloc]init];
dc.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:dc animated:YES];
十二、iOS中字符串过滤掉非法字符
这里简单说两种方法,第一种就是替代法:使用stringByReplacingOccurrencesOfString这个方法将字符串里的非法字符逐个替代/*1*/ tempString = [tempString stringByReplacingOccurrencesOfString:@" " withString:@""];
/*2 */tempString = [tempString stringByReplacingOccurrencesOfString:@"#" withString:@""];
/*3*/ tempString = [tempString stringByReplacingOccurrencesOfString:@"*" withString:@""];
/*4*/ tempString = [tempString stringByReplacingOccurrencesOfString:@"+" withString:@""];
/*5*/ tempString = [tempString stringByReplacingOccurrencesOfString:@"-" withString:@""];
这样做比较烦的一个问题就是,如果要过滤掉的非法字符有很多的话,就得写多行这种替代代码。
另外一种方法比较巧妙,先将字符串按非法字符集进行截断最后再拼接起来。代码看起来很简直,直接了断。
/*1*/ NSCharacterSet *doNotWant = [NSCharacterSet characterSetWithCharactersInString:@"[]{}(#%-*+=_)\\|~(<>$%^&*)_+ "];
/*2*/ tempString = [[tempString componentsSeparatedByCharactersInSet: doNotWant]componentsJoinedByString: @""];
在doNotWant这个字符集里想写几个就写几个。
另外不能用stringByTrimmingCharactersInSet这个方法进行过滤,它能做到的仅仅是把字符串两端的非法字符过滤,但是包含在字符串里非法字符则无能为力。
十三、点击系统的返回按钮,返回到指定视图
举个栗子:我们在开发中,有时会遇到这样的情况,有A、B、C三个视图控制器,A中有一个按钮,点击按钮push到B控制器,B中有个按钮,点击push到C控制器,如果点击C左上角系统自带的返回按钮,会默认的执行下面的代码:
- (nullable UIViewController *)popViewControllerAnimated:(BOOL)animated;
返回到上一个页面B,当然我们可以通过自定义左上角的返回按钮,通过系统的方法:
- (nullable NSArray<__kindof UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;
返回到我们指定的视图控制器,但是此时会有一个问题,如果自定义了返回按钮,可以返回到指定的页面,但是如果通过右划的手势,此时页面返回的还是上一级页面,当然我们也可以通过给视图重新添加手势,在右划的时候,也返回到指定的页面,但是我觉得这样就有点儿工作量了;我想要表达的意思就是:在不自定义返回按钮的前提下,A->B->C,点击C上面的返回按钮(或者通过右划的手势),返回到A页面怎么实现呢;
在B push到C页面之后,在C页面中,把B从视图控制器中删除,此时的控制器中只有A和C了,点击C上面的返回按钮,返回的就是A页面;(哎,哎,别打...)代码如下,这是在C页面中的代码:
- (void)viewDidLoad {
[super viewDidLoad];
//得到当前视图控制器中的所有控制器
NSMutableArray *array = [self.navigationController.viewControllers mutableCopy];
//把B从里面删除
[array removeObjectAtIndex:1];
//把删除后的控制器数组再次赋值
[self.navigationController setViewControllers:[array copy] animated:YES];
}
当然,如果有4个视图控制器的话A/B/C/D,如果想用从D返回到到A,可以把B和C从里面删除了,具体思路根据具体业务分析;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// 让分割线从头开始
if ([_TableViewList respondsToSelector:@selector(setSeparatorInset:)]) {
[_TableViewList setSeparatorInset:UIEdgeInsetsMake(0,0,0,0)];
}
if ([_TableViewList respondsToSelector:@selector(setLayoutMargins:)]) {
[_TableViewList setLayoutMargins:UIEdgeInsetsMake(0,0,0,0)];
}
}
// 让分割线从头开始
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
[cell setSeparatorInset:UIEdgeInsetsZero];
}
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
但是即使在storyboard的tableview上设置如下图:
这问题是不是让你们很头疼呢?
估计有人会说直接使用uiview来当线条就好了
首先,用view当线条我不反对,但是在特殊情况下是不是很繁琐呢?你要在每个地方加这东西。。。
好了,直接进入问题吧。想要解决这个问题,其实很简单。
首先在storyboard上选中你的cell,然后如下图;
十五、iOS 修改导航栏的返回按钮的内容
我大致解释一下,使用pushViewController切换到下一个视图时,navigation controller按照以下3条顺序更改导航栏的左侧按钮。
1、如果B视图有一个自定义的左侧按钮(leftBarButtonItem),则会显示这个自定义按钮;
2、如果B没有自定义按钮,但是A视图的backBarButtonItem属性有自定义项,则显示这个自定义项;
3、如果前2条都没有,则默认显示一个后退按钮,后退按钮的标题是A视图的标题。
按照这个解释,我把UIBarButtonItem *backItem……这段代码放在A视图的pushViewController语句之前。
OK问题解决了,B视图的后退按钮的标题变成back了。
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStyleBordered target:nil action:nil];
[self.navigationItem setBackBarButtonItem:backItem];
}
return self;
}