参考文档:
参考代码: VideoEditing
@property (weak, nonatomic) IBOutlet UIView *viewContainer;
@property (weak, nonatomic) IBOutlet UIImageView *centerImageView;
@property (strong,nonatomic) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer; //相机拍摄预览图层
- (void)viewWillAppear:(BOOL)animated {
...
/* 创建视频预览层,用于实时展示摄像头状态 */
_captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.captureSession];
CALayer *layer = self.viewContainer.layer;
/* 将视频预览层添加到界面中 */
//[layer addSublayer:_captureVideoPreviewLayer];
[layer insertSublayer:_captureVideoPreviewLayer below:self.centerImageView.layer];
...
}
点击:
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(action:)];
imageView.userInteractionEnabled = YES;
[imageView addGestureRecognizer:tapRecognizer];
-(void) action:(id)sender {
UITapGestureRecognizer *tapRecognizer = (UITapGestureRecognizer *)sender;
// tapRecognizer.view ...
}
长按:
{
...
let longPressRecognizer:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLandmarkImageLongPress(_:)))
someUIView!.addGestureRecognizer(longPressRecognizer)
...
}
func handleLandmarkImageLongPress(longPressRecognizer:UILongPressGestureRecognizer) {
if ((UIGestureRecognizerState.Ended == longPressRecognizer.state)
|| (UIGestureRecognizerState.Cancelled == longPressRecognizer.state)
|| (UIGestureRecognizerState.Failed == longPressRecognizer.state)) {
...
return
}
let someUIView = longPressRecognizer.view as! SomeUIView
let point:CGPoint = longPressRecognizer.locationInView(someUIView)
...
if (UIGestureRecognizerState.Began == longPressRecognizer.state) {
...
}
}
捏:
{
let pinchRecognizer:UIPinchGestureRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(handleLandmarkImagePinch(_:)))
someUIView!.addGestureRecognizer(pinchRecognizer)
}
func handleLandmarkImagePinch(pinchRecognizer:UIPinchGestureRecognizer) {
if (UIGestureRecognizerState.Began == pinchRecognizer.state) {
...
return
}
if (UIGestureRecognizerState.Changed == pinchRecognizer.state) {
...
let scale: CGFloat = pinchRecognizer.scale;
...
return
}
if ((UIGestureRecognizerState.Ended == pinchRecognizer.state)
|| (UIGestureRecognizerState.Cancelled == pinchRecognizer.state)) {
...
return
}
}
参考文档:
文件上传(多文件):
#define kUrl @"http://192.168.1.208/FileUpload.aspx"
#define kBOUNDARY_STRING @"lsclone"
#pragma mark 取得mime types
-(NSString *)getMIMETypes:(NSString *)fileName{
return @"image/jpg";
}
#pragma mark 取得数据体
-(NSData *)getHttpBody:(NSString *)fileName{
NSMutableData *dataM=[NSMutableData data];
NSString *strTop=[NSString stringWithFormat:@"--%@\nContent-Disposition: form-data; name=\"images\"; filename=\"%@\"\nContent-Type: %@\n\n",kBOUNDARY_STRING,fileName,[self getMIMETypes:fileName]];
NSString *strBottom = [NSString stringWithFormat:@"\n"];
NSString *filePath=[[NSBundle mainBundle] pathForResource:fileName ofType:nil];
NSData *fileData=[NSData dataWithContentsOfFile:filePath];
[dataM appendData:[strTop dataUsingEncoding:NSUTF8StringEncoding]];
[dataM appendData:fileData];
[dataM appendData:[strBottom dataUsingEncoding:NSUTF8StringEncoding]];
return dataM;
}
#pragma mark 上传文件
-(void)uploadFile:(NSArray*)nameArray {
NSURL *url = [NSURL URLWithString:kUrl];
NSMutableURLRequest *request= [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:5.0f];
request.HTTPMethod=@"POST";
NSMutableData *data = [NSMutableData data];
for(int i=0; i<[nameArray count]; i++) {
[data appendData:[self getHttpBody:(NSString*)nameArray[i]]];
}
NSString *strBottom = [NSString stringWithFormat:@"--%@--", kBOUNDARY_STRING];
[data appendData:[strBottom dataUsingEncoding:NSUTF8StringEncoding]];
//通过请求头设置
[request setValue:[NSString stringWithFormat:@"%lu",(unsigned long)data.length] forHTTPHeaderField:@"Content-Length"];
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",kBOUNDARY_STRING] forHTTPHeaderField:@"Content-Type"];
//设置数据体
request.HTTPBody=data;
//发送异步请求
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if(connectionError){
NSLog(@"error:%@", connectionError.localizedDescription);
} else {
NSError *jsonError = nil;
id jsonObj = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
if(jsonObj == nil) {
NSLog(@"Error parsing JSON: %@", jsonError);
} else {
if ([jsonObj isKindOfClass:[NSArray class]]) {
NSArray *jsonArray = (NSArray *)jsonObj;
...
} else if([jsonObj isKindOfClass:[NSDictionary class]]) {
NSDictionary *jsonDictionary = (NSDictionary *)jsonObj;
...
}
}
}
}];
}
*参考文档:
参考文档: iOS多线程编程:线程同步总结
参考文档:
//添加边框
CALayer *layer = [imageView layer];
layer.borderColor = [UIColor whiteColor].CGColor;
layer.borderWidth = 5.0f;
//添加四个边阴影
imageView.layer.shadowColor = [UIColor blackColor].CGColor;
imageView.layer.shadowOffset = CGSizeMake(0,0);
imageView.layer.shadowOpacity = 0.5;
imageView.layer.shadowRadius = 10.0;//给imageview添加阴影和边框
//添加两个边的阴影
imageView.layer.shadowColor = [UIColor blackColor].CGColor;
imageView.layer.shadowOffset = CGSizeMake(4,4);
imageView.layer.shadowOpacity = 0.5;
imageView.layer.shadowRadius=2.0;
参考网址: IOS-UIImageView
#define ItemWidth 100
#define ItemHeight 80
#define ItemMargin 2
#define ItemNums 10
for(int i=0, pos=0; i<ItemNums; i++) {
UIImageView* imageview = [[UIImageView alloc]initWithFrame:CGRectMake(pos, 0, ItemWidth, ItemHeight)];
imageview.userInteractionEnabled = YES;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(selectItem:)];
[imageview addGestureRecognizer:singleTap];
pos += ItemWidth+ItemMargin;
[self.scrollView setContentSize:CGSizeMake(pos, ItemHeight)];
[self.scrollView addSubview:imageview];
}
参考网址:
/*
** hexColorString:
** 0xffffff or #FFFFFF
*/
+ (UIColor *)colorWithHexString:(NSString *)hexColorString {
if ([hexColorString length] < 6) { //长度不合法
return [UIColor blackColor];
}
NSString *tempString = [hexColorString lowercaseString];
if ([tempString hasPrefix:@"0x"]) { //检查开头是0x
tempString = [tempString substringFromIndex:2];
} else if ([tempString hasPrefix:@"#"]) { //检查开头是#
tempString = [tempString substringFromIndex:1];
}
if ([tempString length] != 6) {
return [UIColor blackColor];
}
//分解三种颜色的值
NSRange range = NSMakeRange(0, 2);
NSString *rString = [tempString substringWithRange:range];
range.location = 2;
NSString *gString = [tempString substringWithRange:range];
range.location = 4;
NSString *bString = [tempString substringWithRange:range];
//取三种颜色值
unsigned int r, g, b;
[[NSScanner scannerWithString:rString] scanHexInt:&r];
[[NSScanner scannerWithString:gString] scanHexInt:&g];
[[NSScanner scannerWithString:bString] scanHexInt:&b];
return [UIColor colorWithRed:((float)r / 255.0f)
green:((float)g / 255.0f)
blue:((float)b / 255.0f)
alpha:1.0f];
}
+ (NSUInteger)degressFromVideoFileWithURL:(NSURL *)url {
//根据url创建AVURLAsset
AVURLAsset *urlAsset = [AVURLAsset assetWithURL:url];
//check video orientation
UIImageOrientation orient = UIImageOrientationUp;
NSArray *tracks = [urlAsset tracksWithMediaType:AVMediaTypeVideo];
if([tracks count] > 0) {
AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
CGAffineTransform t = videoTrack.preferredTransform;
if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0){
// AVCaptureVideoOrientationPortrait
orient = UIImageOrientationRight; // rotate 90 degrees clockwise
}else if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0){
// AVCaptureVideoOrientationPortraitUpsideDown
orient = UIImageOrientationLeft; // rotate 90 degrees counter clockwise
}else if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0){
// AVCaptureVideoOrientationLandscapeRight
orient = UIImageOrientationUp; // rotate 0 degrees clockwise
}else if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0){
// AVCaptureVideoOrientationLandscapeLeft
orient = UIImageOrientationDown; // rotate 180 degrees
}
}
}
参考网址: 获取视频方向
CGRect frame = CGRectMake(0.0, 219.0, 323.0, 20.0);
UISlider *myslider = [[UISlider alloc] initWithFrame:frame];
[myslider addTarget:self action:@selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
[myslider setBackgroundColor:[UIColor clearColor]];
[myslider setThumbImage: [UIImage imageNamed:@"sliderThumb@2x.png"] forState:UIControlStateNormal];
myslider.minimumValue = 0.0;
myslider.maximumValue = 50.0;
myslider.continuous = YES;
myslider.value = 15.0;
[self.view addSubview:myslider];
实现方式1:
利用Storyboard创建Navigation Control,可以自定义root view control。
二级导航添加方法:创建second view control,按住ctrl键,点击root view上的button或prototype cell,并向second view拖拽。
弹出storyboard sagues, 选择push(push,modal, custom)。
参考网址: Use Storyboards to Build Navigation Controller and Table View
实现方式2:
利用Storyboard创建Navigation Control,可以自定义root view control。
二级导航添加方法:Windows+N创建second view control并添加到storyboard,右键second view control,点击push并拖动到root view control,弹出manual并确认,建立导航push segue to "second view control";root view control.m添加button点击响应函数:
- (IBAction)buttonClicked:(id)sender {
//SndViewController *sndCtrl = [self.storyboard instantiateViewControllerWithIdentifier:@"sndpage"];
SndViewController* sndCtrl = [[SndViewController alloc] init];
// push data to second view control
...
[self.navigationController pushViewController:sndCtrl animated:YES];
}
参考网址:
另注:
/* change tint color */
self.navigationController.navigationBar.tintColor = [UIColor redColor];
/* change title color */
self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName:[UIColor redColor]};
/* set navigationbar background to transparent (alpha 0) */
[[[self.navigationController.navigationBar subviews] objectAtIndex:0] setAlpha:0];
参考网址:
参考网址:
UIGraphicsBeginImageContext(CGSizeMake(100, 100));
/* draw image */
[srcimage drawAtPoint:CGPointMake(0,0)];
CGContextRef ctx = UIGraphicsGetCurrentContext();
/* draw point */
CGContextSetFillColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextAddEllipseInRect(ctx, CGRectMake(x, y, width, height));
CGContextFillPath(ctx);
/* draw line */
CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextMoveToPoint(ctx, x1, y1);
CGContextAddLineToPoint(ctx, x2, y2);
CGContextSetLineWidth(ctx, 10);
CGContextStrokePath(ctx);
/* get target image */
UIImage* dstimage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
参考网址:
/* CGContextDrawImage draws image upside down */
UIImage *image = [UIImage imageNamed:@"testImage.png"];
CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height);
CGContextTranslateCTM(context, 0, image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, imageRect, image.CGImage);
参考网址:
//实现的是放大和缩小
view.transform=CGAffineTransformScale(view.transform, 0.5, 0.5);
//实现的是旋转
view.transform=CGAffineTransformRotate(view.transform, 0.2);
//实现的是平移
view.transform=CGAffineTransformTranslate(view.transform, 20, 20);
参考: UIView的transform属性以及 CGAffineTransform的使用
#import <MobileCoreServices/MobileCoreServices.h>
@interface ViewController()<UINavigationControllerDelegate, UIImagePickerControllerDelegate>
@end
@implementation ViewController
- (IBAction)buttonClicked:(UIButton *)sender {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.mediaTypes = @[(NSString*)kUTTypeImage, (NSString *)kUTTypeMovie, (NSString*)kUTTypeVideo];
picker.delegate = self;
picker.allowsEditing = YES; //设置选择后的图片/视频可被编辑
[self presentViewController:picker animated:YES completion:nil]; //打开相册
}
#pragma mark - UIImagePickerControllerDelegate方法
-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSString *type = [info objectForKey:UIImagePickerControllerMediaType];
if ([type isEqualToString:@"public.image"]) {
UIImage* image = [info objectForKey:UIImagePickerControllerOriginalImage]; //图片
...
} else if ([type isEqualToString:@"public.movie"] || [type isEqualToString:@"public.video"]) {
NSURL* url = [info objectForKey:UIImagePickerControllerMediaURL]; //视频路径
...
}
[self dismissViewControllerAnimated:YES completion:nil]; //关闭相册
}
@end
参考网址:
public func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
public func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?)
public func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?)
public func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?)
objective-c code:
- (void)moveSideBarToXposition: (int) iXposition{
[UIView animateWithDuration:0.5f
delay:0.1
options: UIViewAnimationOptionTransitionNone
animations:^{ self.mainView.frame = CGRectMake(iXposition, 20, self.mainView.frame.size.width, self.mainView.frame.size.height); }
completion:^(BOOL finished){
if (self.isSidebarHidden==YES) {
self.isSidebarHidden = NO;
}
else{
self.isSidebarHidden = YES;
}
}];
}
swift code:
func moveSideBarToXposition(iXposition: Float) {
let convertedXposition = CGFloat(iXposition)
UIView.animateWithDuration(0.5, delay: 1.0, options: UIViewAnimationOptions.TransitionNone, animations: { () -> Void in
self.contentView.frame = CGRectMake(convertedXposition, 20, self.contentView.frame.size.width, self.contentView.frame.size.height)
}, completion: { (finished: Bool) -> Void in
// you can do this in a shorter, more concise way by setting the value to its opposite, NOT value
isMenuHidden = !isMenuHidden
})
}
参考网址:
override func viewWillAppear(animated: Bool) {
captureMovieFileOutput?.addObserver(self, forKeyPath: "recording", options: NSKeyValueObservingOptions([.Old, .New]), context: nil)
}
deinit {
captureMovieFileOutput?.removeObserver(self, forKeyPath: "recording")
}
var progressTimer: NSTimer?
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
guard captureMovieFileOutput != nil else {
return
}
if keyPath == "recording" {
if !self.captureMovieFileOutput!.recording {
self.progressTimer?.invalidate()
self.progressTimer = nil
} else {
if (self.progressTimer == nil) {
self.progressTimer = NSTimer.createTimer(0.005, block: {
let duration: Float64 = CMTimeGetSeconds(self.captureMovieFileOutput!.recordedDuration)
let time: Float64 = CMTimeGetSeconds(self.captureMovieFileOutput!.maxRecordedDuration)
let progress: Float = Float(duration/time)
self.recordProgressView.setProgress(progress, animated: true)
}, repeats: true)
NSRunLoop.mainRunLoop().addTimer(progressTimer!, forMode: NSDefaultRunLoopMode)
}
}
}
}
import UIKit
public typealias TimerClosure = @convention(block)()->()
extension NSTimer {
class func createTimer(timeInterval:NSTimeInterval, block:TimerClosure, repeats:Bool) -> NSTimer {
return NSTimer.init(timeInterval: timeInterval, target: self, selector: #selector(NSTimer.invoke), userInfo: unsafeBitCast(block, AnyObject.self), repeats: true)
}
class func invoke(timer:NSTimer) {
let block = unsafeBitCast(timer.userInfo, TimerClosure.self)
block()
}
}
参考网址:
应用(swift version):
class MyView: UIView {
...
//Location transformation is necessary because of zooming in or out.
func transformLocation(location location:CGPoint) -> CGPoint {
let transformedLocation = CGPointMake(location.x * transform.a + location.y * transform.c + transform.tx,
location.x * transform.b + location.y * transform.d + transform.ty)
return transformedLocation
}
func transformLocation(touch:UITouch) -> CGPoint {
let location = touch.locationInView(self)
return transformLocation(location: location)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if 1 != touches.count {
return
}
let touch:UITouch = touches.first!
let location:CGPoint = transformLocation(touch)
...
}
}
touch.locationInView(self) 获取的是相对UIView原始尺寸的坐标(x, y),UIView缩放之后的相应坐标点需要通过transformLocation计算,参考The Math Behind the Matrices
参考网址:
参考网址: assets官网
参考网址:
1. write NSData to file
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// Generate the file path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"yourfilename.dat"];
// Save NSData into file system
[data writeToFile:dataPath atomically:YES];
});
2. NSMutableData remove bytes
参考网址: NSMutableData remove bytes
参考网址:
参考网址: iOS MFi App端开发步骤
RunLoop从字面上看是运行循环的意思,首先循环体的开始需要检测是否有需要处理的事件,如果有则去处理,如果没有则进入睡眠以节省CPU时间。 所以重点便是这个需要处理的事件,在RunLoop中,需要处理的事件分两类,一种是输入源,一种是定时器。
每一个线程都有其对应的RunLoop,但是默认非主线程的RunLoop是没有运行的,需要为RunLoop添加至少一个事件源,然后去run它。一般情况下我们是没有必要去启用线程的RunLoop的,除非你在一个单独的线程中需要长久的检测某个事件。
参考网址:
start sub-thread and runloop:
{
// NSThread *_thread
_thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadFunc) object:nil];
[_thread start];
}
- (void)threadFunc {
NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:time target:self selector:@selector(onTimer) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
}
- (void)onTimer {
}
re-write for making runloop can be stopped
- (void)threadFunc {
[NSStream setDelegate:self];
[NSStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[NSStream open];
_shouldKeepRunning = YES;
while (_shouldKeepRunning && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]]);
// TODO: some operation after stopping runloop
}
#pragma mark NSStreamDelegate
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
}
- (void)close {
[self performSelector:@selector(stop:) onThread:_thread withObject:nil waitUntilDone:NO];
}
- (void)stop:(id)sender {
[NSStream close];
[NSStream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[NSStream setDelegate:nil];
_shouldKeepRunning = NO;
}
参考网址: