近期学习过程问题整理
近期学习过程问题整理
1.自定义导航栏按钮
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"caidan.png"] style:UIBarButtonItemStylePlain target:self action:@selector(pressLeft)];
self.leftButton.tintColor = [UIColor redColor];
1.导航栏的导航控制栏->导航控制项
2.导航栏的按钮颜色使用tintColor属性
2.自定义分栏菜单按钮
SearchView* vc1 = [[SearchView alloc] init];UIImage* image1 = [[UIImage imageNamed:@"m1.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];UINavigationController* nav1 = [[UINavigationController alloc] initWithRootViewController:vc1];vc1.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"主页" image:image1 tag:101];
/*
UIImageRenderingModeAutomatic:系统自定义
UIImageRenderingModeAlwaysOriginal:图片原始颜色
UIImageRenderingModeAlwaysTemplate:如果设置一个图片,那么只保存形状轮廓,背景颜色使用tintColor渲染
*/
1.imageWithRenderingMode: :控制图像在渲染时的显示方式,决定是否使用tintColor渲染默认的颜色
3.手势识别器
tap.cancelsTouchesInView = NO;
1.当识别到触摸事件后,不取消触摸事件,而是继续向下面的图层传递
4.UISearchBar的协议
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {[searchBar resignFirstResponder];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {[searchBar resignFirstResponder];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {//监听searchBar的键盘录入信息,后面实现模糊搜索用得到
}
5(重要).视图加载时机
- (void)pressLeft {MoreVC* vc = [[MoreVC alloc] init];vc.isnight = self.isNight;vc.modalPresentationStyle = UIModalPresentationCustom;vc.transitioningDelegate = self;vc.image = self.image;[self presentViewController:vc animated:YES completion:nil];
}
在实现这里的深夜模式时,我发现如果在这时候就判断并修改MoreVC的背景色,那么MoreVC中的image并没有被更新,于是我查询了一下资料发现这里其实涉及了一个视图控制器的生命周期的问题,如果我们在这里就使用v c.view.backGroundColor修改背景色,那么就会触发强制加载,提前触发viewDidLoad加载视图,那么此时vc就会访问其的image属性,但是此时image为nil,已经被刷新到其视图上,后面的vc.image = self.image就没有用了,所以为了保留代码的封装性,尽量在视图控制器里对自己操作
6.实现抽屉视图
抽屉视图
实现抽屉视图的步骤1.自定义一个动画类,这个类需要继承自NSObject,这个类必须遵守
UIViewControllerAnimatedTransitioning协议,这个协议中有两个方法需要我们实现@protocol UIViewControllerAnimatedTransitioning <NSObject>
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;
//控制动画持续时间
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
//控制动画的核心逻辑
@end
对于遵守UIViewControllerContextTransitioning协议的transitionContext有如下几个重要的属性与方法
//系统提供的容器视图,是动画发生的舞台,所有的动画视图都必须添加到这里
@property(nonatomic, readonly) UIView *containerView;
//通过两个to和from的枚举量,能在上下文之中获得相应的控制器
- (nullable __kindof UIViewController *)viewControllerForKey:(UITransitionContextViewControllerKey)key;
//获取上下文视图大小
- (CGRect)initialFrameForViewController:(UIViewController *)vc;
- (CGRect)finalFrameForViewController:(UIViewController *)vc;
具体实例如下
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface SliderInAnimator : NSObject<UIViewControllerAnimatedTransitioning>
@property (nonatomic, assign)BOOL isPresenting;
@end
NS_ASSUME_NONNULL_END
#import "SliderInAnimator.h"
#import "MoreVC.h"
@implementation SliderInAnimator
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {return 0.4;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {/*从上下文获取目标页面的视图控制器transitionContext:当前转场的上下文(系统传入)viewControllerForKey:用来获取专场前后的视图控制器,from是前,to是后*/UIView* containerView = [transitionContext containerView];if (self.isPresenting) {//获取即将要呈现的视图控制器UIViewController* vc = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];CGRect finalFrame = CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width * (4.0 / 5.0), [[UIScreen mainScreen] bounds].size.height);//添加模糊效果UIView* dimmingView = [[UIView alloc] initWithFrame:containerView.bounds];dimmingView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];dimmingView.tag = 1001;dimmingView.alpha = 0.0;//添加手势UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:vc action:@selector(dismissViewController)];[dimmingView addGestureRecognizer:tap];[containerView addSubview:dimmingView];CGRect startFrame = finalFrame;startFrame.origin.x = -finalFrame.size.width;vc.view.frame = startFrame;[containerView addSubview:vc.view];/*animatedWithDuartion是一个类方法,用来实现动画参数一:动画时长参数二:目标控制器最终的位置参数三:回调,这里是告诉系统动画完成*/
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{vc.view.frame = finalFrame;dimmingView.alpha = 1.0;} completion:^(BOOL finished) {[transitionContext completeTransition:YES];}];} else {UIViewController* fromVc = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];UIView* dimmingView = [containerView viewWithTag:1001];CGRect endFrame = fromVc.view.frame;endFrame.origin.x = - endFrame.size.width;[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{fromVc.view.frame = endFrame;dimmingView.alpha = 0.0;} completion:^(BOOL finished) {[dimmingView removeFromSuperview];[fromVc.view removeFromSuperview];[transitionContext completeTransition:YES];}];}
}
@end
接下来我们对主控制器进行设置,对于主视图控制器,需要遵守UIViewControllerTransitioningDelegate协议,并实现其中的部分方法,再协议的方法中我们需要告诉编译器我们想要使用自定义的动画效果。
- (void)pressLeft {MoreVC* vc = [[MoreVC alloc] init];vc.modalPresentationStyle = UIModalPresentationCustom;/*设置视图控制器的呈现样式,否则会使用默认的动画*/vc.transitioningDelegate = self;/*设置代理*/[self presentViewController:vc animated:YES completion:nil];
}- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {self.anmitor = [[SliderInAnimator alloc] init];self.anmitor.isPresenting = YES;return self.anmitor;
}-(id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {self.anmitor = [[SliderInAnimator alloc] init];self.anmitor.isPresenting = NO;return self.anmitor;
}
7.导航栏属性修改
- (void)setNavigationBarOpaque {UINavigationBarAppearance* app = [[UINavigationBarAppearance alloc] init];[app configureWithOpaqueBackground];app.shadowColor = [UIColor clearColor];app.backgroundColor = [UIColor whiteColor];self.navigationController.navigationBar.standardAppearance = app;self.navigationController.navigationBar.scrollEdgeAppearance = app;}
/*
- (void)setNavigationBarTransparent {UINavigationBar *navBar = self.navigationController.navigationBar;navBar.barTintColor = [UIColor clearColor];[navBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];navBar.shadowImage = [UIImage new];navBar.translucent = YES;
}- (void)setNavigationBarOpaque {UINavigationBar *navBar = self.navigationController.navigationBar;navBar.barTintColor = [UIColor whiteColor];[navBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];navBar.shadowImage = nil;navBar.translucent = NO;
}
*/
iOS13+建议使用,configureWithTransparentBackground透明 ,configureWithOpaqueBackground半透明,还有一个不透明
8.刷新某个单元格
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
9.单元格点击事件
在设计自定义cell时,由于我的单元格内容是直接在自定义cell里实现的(有的没有用属性定义),于是在添加点击事件的时候我发现按钮的响应事件是在cell中的,没有导航控制器,无法使用push推出新视图,所以这里就面临着一个问题,如何将点击事件传到注册cell的页面中,这里我使用了Block传值,首先,我在自定义cell类中定义了一个Block,如下:
//.h
@property (nonatomic, copy)void(^CountCellBlock)(void);
之后,我在自定义cell的实现文件中为目标控件添加了点击事件,并在点击事件后执行这个回调
UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(pressheader)];tap.numberOfTapsRequired = 1;tap.numberOfTouchesRequired = 1;[self.photoView addGestureRecognizer:tap];//- (void)pressheader {if (self.CountCellBlock) {self.CountCellBlock();}
}
接下来使用tableView的类中调用这个Block
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {if (indexPath.row == 0) {CountTableViewCell* cell01 = [self.tableView dequeueReusableCellWithIdentifier:@"ViewCell01" forIndexPath:indexPath];cell01.selectionStyle = UITableViewCellSelectionStyleNone;if (self.header) {[cell01 changeheader:self.header];}cell01.CountCellBlock = ^{DrawVC* vc = [[DrawVC alloc] init];if (self.isNight) {vc.view.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.9];;} else {vc.view.backgroundColor = [UIColor systemGroupedBackgroundColor];}[self.navigationController pushViewController:vc animated:YES];};return cell01;} else {CountTableViewCell* cell02 = [self.tableView dequeueReusableCellWithIdentifier:@"ViewCell02" forIndexPath:indexPath];cell02.selectionStyle = UITableViewCellSelectionStyleNone;return cell02;}
}
10.实现UISegmentControl的接近跳跃
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {CGFloat contentx = self.scrollView.contentOffset.x;CGFloat w = scrollView.frame.size.width;CGFloat index = contentx / w;NSInteger select = (NSInteger)(index + 0.5);//很关键,实现找到最近的整数if (select >= self.segmentControl.numberOfSegments) {select =self.segmentControl.numberOfSegments - 1;}if (self.segmentControl.selectedSegmentIndex != select){self.segmentControl.selectedSegmentIndex = select;}
}
11.实现UISegmentControl的平滑切换
- (void)segChanged {NSInteger selected = self.segmentControl.selectedSegmentIndex;CGFloat offsetx = selected * self.scrollView.bounds.size.width;[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{self.scrollView.contentOffset = CGPointMake(offsetx, 0);} completion:nil];
}
options:决定动画变速:
UIViewAnimationOptionCurveEaseInout:慢快慢
--EaseIn:慢-快
--EaseOut:快-慢
--Linnear;匀速
animations:动画块:需要变化的动画
completion:回调方法
(NSNumber是OC对象,NSInteger是基本类型,不是OC对象)