iOS视频封面选择

在做一个iOS视频封面选择功能时,遇到的所有的Google的东西

UITableView取消点击cell的选择状态

点击cell的时候,默认会有一个选择状态的背景颜色,用下面两种方法可以取消:

方法1:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}

方法2:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}

我自己使用方法1没生效,方法2生效了

浮点类型取整

ceil是天花板,floor是地板,给一个中间的数值,推算天花板和地板处的数值

  • round: 如果参数是小数,则求本身的四舍五入
  • ceil: 如果参数是小数,则求最小的整数但不小于本身
  • floor: 如果参数是小数,则求最大的整数但不大于本身

每个方法根据参数和返回值不同,又各自分别有三个方法

extern float ceilf(float);

extern double ceil(double);

extern long double ceill(long double);

CMTime如何打印出来

NSLog(@"seconds = %f", CMTimeGetSeconds(cmTime));

字符串和数字类型的转换

字符串拼接

NSString *newString = [NSString stringWithFormat:@"%@%@", tempA, tempB];

字符转int

int intString = [newString intValue];

int转字符

NSString *stringInt = [NSString stringWithFormat:@"%d", intString];

字符转float

float floatString = [newString floatValue];

float转字符

NSString *stringFloat = [NSString stringWithFormat:@"%f", intString];

NSDictionary字典和NSMutableDictionary可变字典

字典用于保存具有映射关系数据的集合
一个key—value对认为是一个条目entry,字典是存储key—value对的容器
与数组不同,字典靠key存取元素
key不能重复,value必须是对象
键值对在字典中是无序存储的
字典分: 不可变字NSDictionary和可变字典NSMutableDictionary
不可变字典一旦创建,键值对就不可更改,不可添加,不可删除,仅能读取key或者value

创建字典

NSDictionary *dic1 = [[NSDictionary alloc] initWithObjectsAndKeys:@"Duke", @"name", @33, @"age", @"男", @"gender", nil];

NSDictionary *dic2 = [NSDictionary dictionaryWithObjectsAndKeys:@"Duke", @"name", @33, @"age", @"男", @"gender", nil];

// 创建字典对象时两个数组元素个数必须一致
NSArray *keys = @[@"name", @"age", @"gender"];
NSArray *values = @[@"Duke", @33, @"male"];

NSDictionary *dic3 = [[NSDictionary alloc] initWithObjects:values forKeys:keys];

NSDictionary *dic4 = [NSDictionary dictionaryWithObjects:values forKeys:keys];

NSDictionary *dic5 = @{@"name" : @"Duke", @"age" : @33, @"gender" : @"male"};

遍历字典

NSInteger count = [dic count];
NSArray *allKeys = [dic allKeys];
NSArray *allValues = [dic allValues];

for (int i = 0; i < count; i++) {
id key = [allKeys objectAtIndex:i];
id value = [dic objectForKey:key];

NSString* result = [value isKindOfClass:[NSString class]] ? @"YES" : @"NO";
NSLog(@"%@:%@-->%@", key, value, result);
}

// 快速遍历
for (NSString *key in dic) {
NSLog(@"dictionary[%@]:%@", key, dic[key]);
}

可变字典

[dic setObject:@"Duke" forKey:@"name"];

[dic removeObjectForKey:@"age"];

[dic removeAllObjects];

集合

OC中的集合(NSSet)与数学中的集合一样,集合中的元素具有唯一性、存储单元的元素是无序的、存储元素必须是对象类型

// 用数组对象来创建集合对象
// 可以通过这种方法过滤掉数组中重复的元素对象
NSArray *array = @[@1, @2, @3, @2, @3];

NSSet *set3 = [[NSSet alloc] initWithArray:array];

NSSet *set4 = [NSSet setWithArray:array];

来源 OC中NSDictionary(字典)、NSMutableDictionary(可变字典)、NSSet(集合)、NSMutableSet(可变集合)得常用方法

UIImageView的contentMode

当我使用UIViewContentModeScaleAspectFill这个contentMode的时候,发现图片的内容会超出UIImageView的宽高,我希望图片内容被裁剪

_imageView.layer.masksToBounds = YES;

加上这个属性就可以裁剪了,如果为true,则将与图层边界匹配的隐式遮罩应用于图层(包括cornerRadius属性的效果)

解决这个问题的教训就是,不知道的事情先Google,不然就是浪费时间,浪费生命

来源 iOS开发——UIImageView的contentMode、裁剪和layer属性详解

居中布局

make.centerX.equalTo(weakSelf.mas_centerX);

以后抄的时候,注意要多看两眼

一个类的入口是viewDidLoad

viewWillAppear

viewWillAppear总是在viewDidLoad之后被调用,但不是立即,当你只是引用了属性view,却没有立即把view添加到任何已经展示的视图上时,viewWillAppear不会被调用,这在view被外部引用时,就会发生。当然,随着ViewController的多次推入,多次进入子页面后返回,该方法会被多次调用

锁屏之后会被调用吗?

不会。viewWillAppear关注的是view在层次中的显示与消失,锁屏并没有改变App本身的层次

Window叠加后,会被调用吗?

不会。同锁屏时的原因类似,叠加Window并没有改变ViewController所在Window的视图层次,换句话说,view并没有被覆盖或删除(相对于自己所在Window)

视图显示后

- (void)viewDidAppear:(BOOL)animated将被调用,子视图有自定义动画时,建议在Did方法中启动,在Will中启动动画时,动画效果将不会很理想。

viewWillAppear 与 viewDidAppear 之间发生了什么

- viewWillLayoutSubviews- viewDidLayoutSubviews将会被调用

而使用Autolayout时,子视图大小只有在viewDidLayoutSubviews才真正被设置好,所以这里才是获取子视图大小的正确位置,常见的错误是,在viewDidLoad中读取了某个view.frame,用来给其它子视图赋值,结果得到一堆大小“不定”的视图,甚至可能为零,在视图中看不见!

来源 iOS开发基础:【从诞生到死亡】ViewController的生命周期

UITableView设置横向

iOS中的tableview默认是竖向的,但是开发中往往有布局横向tableview的需求,其实tableview可以设置旋转角度实现方向

//设置逆时针旋转90度。 M_PI是π=3.1415926,意为180°,M_PI前带-指逆时针,不带指顺时针
self.tableView.transform = CGAffineTransformMakeRotation(-M_PI / 2);

这里实现tableview的旋转,但是如果只这样大家会发现cell的方向是不正确的,方法是cell生成的时候设置旋转cell:

//设置逆时针旋转270度。
cell.transform = CGAffineTransformRotation(-M_PI * 1.5);

这样的话tableview就被设置为横放了。

若想设置tableview的frame应在设置旋转后设置,否则旋转将破环原来的frame
一定要在旋转后再设置frame,切记,切记

来源 ios之UITableView设置横向

触摸与手势

触摸事件处理

响应者对象

在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件。我们称之为“响应者对象”

UIApplication、UIViewController、UIView都继承自UIResponder,因此它们都是响应者对象,都能够接收并处理事件

UIResponder

UIResponder内部提供了以下方法来处理事件:

// 触摸事件
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

// 加速计事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;

// 远程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;

UIView的触摸事件处理

UIView是UIResponder的子类,可以覆盖下列4个方法处理不同的触摸事件:

/* 一根或者多根手指开始触摸view,系统会自动调用view的下面方法 */
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

/* 一根或者多根手指在view上移动,系统会自动调用view的下面方法(随着手指的移动,会持续调用该方法) */
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

/* 一根或者多根手指离开view,系统会自动调用view的下面方法 */
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

/* 触摸结束前,某个系统事件(例如电话呼入)会打断触摸过程,系统会自动调用view的下面方法 */
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

// 提示:touches中存放的都是UITouch对象

然后关于UITouchUIEvent有一写属性和方法

如何寻找最合适的View?

  1. 先判断自己是否能够接收触摸事件,如果能够接收事件再继续往下判断
  2. 如果在自己身上,它会从后往前遍历子控件,遍历出每一个子控件后,重复前面的两个步骤
  3. 如果没有符合条件的子控件,那么它自己就是最适合的View
  4. 注意: 如果父控件不能接收触摸事件,那么子控件就不可能接收到触摸事件

UIView不能接收触摸事件的三种情况

  • 不接收用户交互时不能够处理事件: userInteractionEnabled = NO
  • 当一个控件隐藏的时候不能够接收事件: Hidden = YES的时候
  • 当一个控件为透明白时候也不能够接收事件: alpha = 0.0 ~ 0.01
  • 注意: UIImageView的userInteractionEnabled默认就是NO,因此UIImageView以及它的子控件默认是不能接收触摸事件的

手势事件

手势类UIGestureRecognizer是更高级的封装,使用起来更方便

  • UITapGestureRecognizer(轻触,点按)
  • UILongPressGestureRecognizer(长按)
  • UISwipeGestureRecognizer(轻扫手势)
  • UIRotationGestureRecognizer(旋转手势)
  • UIPanGestureRecognizer(拖拽手势)
  • UIPinchGestureRecognizer(捏合手势,缩放用)

我用到了UITapGestureRecognizerUIPanGestureRecognizer

UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)];
[_tableView addGestureRecognizer:singleTap];

UIPanGestureRecognizer *panTap = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panTap:)];
[_tableView addGestureRecognizer:panTap];

开始的时候,我发现singleTap会在手指轻按屏幕并离开时被调用,无法在手指触摸到屏幕的时候被调用
实现下面这个UIGestureRecognizerDelegate代理方法,可以拿到手指触摸到屏幕时的事件

// 手指触摸屏幕后回调的方法,返回 NO 则不再进行手势识别,方法触发等
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
// 手指触摸屏幕时触发
CGPoint point = [touch locationInView:self.tableView];
[self touchHandle:point];
return NO;
}

来源 iOS学习之触摸事件
来源 UIGestureRecognizer 手势识别

获取视频的任意一帧

+ (UIImage *)buildEveryImageWithFileUrl:(NSURL *)fileUrl withDegress:(CGFloat)degress {
if (!fileUrl)
{
return nil;
}
AVAsset * avasset = [AVAsset assetWithURL:fileUrl];
if (avasset) {
AVAssetImageGenerator * imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:avasset];
imageGenerator.appliesPreferredTrackTransform = YES;

// 获取精确时间需要,否则会取缓存
imageGenerator.requestedTimeToleranceAfter = kCMTimeZero;
imageGenerator.requestedTimeToleranceBefore = kCMTimeZero;

double duration = avasset.duration.value;

// CMTimeMake(a, b); a当前第几帧,b每秒钟多少帧,b越大越精准
CMTime time = CMTimeMake(duration * degress / 100.0f, 1000);

NSError * error = nil;
CGImageRef cgimage = [imageGenerator copyCGImageAtTime:time actualTime:nil error:&error];

UIImage * image = [UIImage imageWithCGImage:cgimage];
CGImageRelease(cgimage);
return image;
}
return nil;
}

来源 iOS 获取视频的任意一帧

UISlider的调研

UISlider* mySlider = [[UISlider alloc] initWithFrame:CGRectMake(20.0, 10.0, 200.0, 0.0)];

mySlider.mininumValue = 0.0; // 下限
mySlider.maxinumValue = 50.0; // 上限

mySlider.value = 22.0;

// 自定义滑块和两端的图片
[mySlider setThumbImage:thumbImage forState:UIControlStateNormal];
[mySlider setMinimumTrackImage:[UIImage imageWithColor:[UIColor clearColor]] forState:UIControlStateNormal];
[mySlider setMaximumTrackImage:[UIImage imageWithColor:[UIColor clearColor]] forState:UIControlStateNormal];

无法实现的需求:

  1. 只能拖拽,不能通过点击某一点跳转进度
  2. 只能自定义图片,不能自定义UIView

所以没有使用