65、iOS开发:相机与照片库应用及应用本地化指南

iOS开发:相机与照片库应用及应用本地化指南

相机与照片库应用开发

在开发一个允许用户使用相机拍照、拍摄视频,或者从照片库中选择内容并显示在屏幕上的应用时,需要进行一系列的操作。

1. 处理用户取消图像选择器的情况

当用户取消图像选择器时,需要确保正确关闭选择器。以下是 imagePickerControllerDidCancel: 方法的基本实现:

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    [picker dismissViewControllerAnimated:YES completion:NULL];
}
2. 设计界面
  • 创建项目 :在Xcode中使用单视图应用模板创建一个名为 Camera 的新项目。
  • 添加出口和协议 :在 ViewController.m 的类扩展中添加以下协议和属性:
#import "ViewController.h"

@interface ViewController ()
<UIImagePickerControllerDelegate, UINavigationControllerDelegate>

@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UIButton *takePictureButton;

@end

由于 UIImagePickerController UINavigationController 的子类,所以需要同时遵循这两个协议。

  • 添加动作方法 :添加两个动作方法,目前先创建空实现:
- (IBAction)shootPictureOrVideo:(UIButton *)sender {
}

- (IBAction)selectExistingPictureOrVideo:( UIButton *)sender {
}
  • 在Interface Builder中编辑GUI
    1. 从库中拖两个按钮到视图中,上面的按钮标题设为 New Photo or Video ,下面的按钮标题设为 Pick from Library
    2. 拖一个图像视图到按钮上方,将其背景设为黑色,模式设为 Aspect Fit
    3. 建立连接:从视图控制器图标控制拖动到图像视图选择 imageView 出口,再拖动到 New Photo or Video 按钮选择 takePictureButton 出口。
    4. 连接事件:选择 New Photo or Video 按钮,从 Touch Up Inside 事件拖动到视图控制器选择 shootPictureOrVideo: 动作;对 Pick from Library 按钮进行同样操作,选择 selectExistingPictureOrVideo: 动作。
    5. 添加自动布局约束:
      • Pick from Library 按钮控制拖动到主视图,选择 Leading Space to Container Margin Trailing Space to Container Margin Bottom Space to Bottom Layout Guide
      • New Photo or Video 按钮控制拖动到 Pick from Library 按钮,选择 Vertical Spacing
      • New Photo or Video 按钮控制拖动到主视图,选择 Leading Space to Container Margin Trailing Space to Container Margin
      • New Photo or Video 按钮控制拖动到图像视图,选择 Vertical Spacing
      • 从图像视图控制拖动到主视图,选择 Leading Space to Container Margin Trailing Space to Container Margin Top Space to Top Layout Guide
      • 同时选中两个按钮,点击 Pin 按钮,勾选 Width 并添加约束。
3. 实现相机视图控制器
  • 添加属性和导入头文件 :在 ViewController.m 中添加以下内容:
#import "ViewController.h"
#import <MediaPlayer/MediaPlayer.h>
#import <MobileCoreServices/UTCoreTypes.h>

@interface ViewController ()
<UIImagePickerControllerDelegate, UINavigationControllerDelegate>

@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UIButton *takePictureButton;
@property (strong, nonatomic) MPMoviePlayerController *moviePlayerController;
@property (strong, nonatomic) UIImage *image;
@property (strong, nonatomic) NSURL *movieURL;
@property (copy, nonatomic) NSString *lastChosenMediaType;

@end
  • 增强 viewDidLoad viewDidAppear: 方法
@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    if (![UIImagePickerController isSourceTypeAvailable:
          UIImagePickerControllerSourceTypeCamera]) {
        self.takePictureButton.hidden = YES;
    }
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self updateDisplay];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}
  • 实现实用方法
    • updateDisplay 方法
- (void)updateDisplay {
    if ([self.lastChosenMediaType isEqual:(NSString *)kUTTypeImage]) {
        self.imageView.image = self.image;
        self.imageView.hidden = NO;
        self.moviePlayerController.view.hidden = YES;
    } else if ([self.lastChosenMediaType isEqual:(NSString *)kUTTypeMovie]) {
        if (self.moviePlayerController == nil) {
            self.moviePlayerController = [[MPMoviePlayerController alloc]
                                          initWithContentURL:self.movieURL];
            UIView *movieView = self.moviePlayerController.view;
            movieView.frame = self.imageView.frame;
            movieView.clipsToBounds = YES;
            [self.view addSubview:movieView];
            [self setMoviePlayerLayoutConstraints];
        } else {
            self.moviePlayerController.contentURL = self.movieURL;
        }
        self.imageView.hidden = YES;
        self.moviePlayerController.view.hidden = NO;
        [self.moviePlayerController play];
    }
}
- **`setMoviePlayerLayoutConstraints` 方法**:
- (void)setMoviePlayerLayoutConstraints {
    UIView *moviePlayerView = self.moviePlayerController.view;
    UIView *takePictureButton = self.takePictureButton;
    moviePlayerView.translatesAutoresizingMaskIntoConstraints = NO;
    NSDictionary *views =
         NSDictionaryOfVariableBindings(moviePlayerView, takePictureButton);
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
            @"H:|[moviePlayerView]|" options:0 metrics:nil views:views]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:
            @"V:|[moviePlayerView]-0-[takePictureButton]" options:0 metrics:nil
            views:views]];
}
- **`pickMediaFromSource:` 方法**:
- (void)pickMediaFromSource:(UIImagePickerControllerSourceType)sourceType {
    NSArray *mediaTypes = [UIImagePickerController
                           availableMediaTypesForSourceType:sourceType];
    if ([UIImagePickerController
         isSourceTypeAvailable:sourceType] && [mediaTypes count] > 0) {
        UIImagePickerController *picker =
                    [[UIImagePickerController alloc] init];
        picker.mediaTypes = mediaTypes;
        picker.delegate = self;
        picker.allowsEditing = YES;
        picker.sourceType = sourceType;
        [self presentViewController:picker animated:YES completion:NULL];
    } else {
        UIAlertController *alertController = [UIAlertController
                     alertControllerWithTitle:@"Error accessing media"
                               message:@"Unsupported media source."
                               preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK"
                                   style:UIAlertActionStyleCancel handler:nil];
        [alertController addAction:okAction];
        [self presentViewController:alertController animated:YES
              completion:nil];
    }
}
  • 实现动作方法
- (IBAction)shootPictureOrVideo:(id)sender {
    [self pickMediaFromSource:UIImagePickerControllerSourceTypeCamera];
}

- (IBAction)selectExistingPictureOrVideo:(id)sender {
    [self pickMediaFromSource:UIImagePickerControllerSourceTypePhotoLibrary];
}
  • 实现委托方法
#pragma mark - Image Picker Controller delegate methods

- (void)imagePickerController:(UIImagePickerController *)picker
       didFinishPickingMediaWithInfo:(NSDictionary *)info {
    self.lastChosenMediaType = info[UIImagePickerControllerMediaType];

    if ([self.lastChosenMediaType isEqual:(NSString *)kUTTypeImage]) {
        self.image = info[UIImagePickerControllerEditedImage];
    } else if ([self.lastChosenMediaType isEqual:(NSString *)kUTTypeMovie]) {
        self.movieURL = info[UIImagePickerControllerMediaURL];
    }
    [picker dismissViewControllerAnimated:YES completion:NULL];
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    [picker dismissViewControllerAnimated:YES completion:NULL];
}

完成上述步骤后,编译并运行应用。在模拟器上只能从照片库选择内容,而在真机上可以拍照、拍摄视频,并且首次访问用户照片时会请求权限。

应用本地化

随着iOS设备在全球超过90个国家可用,应用的潜在市场非常大。iOS提供了强大的本地化架构,允许将应用轻松翻译成多种语言甚至同一语言的不同方言。

1. 本地化架构概述
  • 非本地化应用 :运行时应用的所有文本将以开发者的语言(开发基础语言)呈现。
  • 本地化应用 :开发者为每个支持的语言在应用包中创建子目录(本地化文件夹),文件夹名以 .lproj 结尾,包含翻译后的资源。
2. 资源加载规则

当本地化应用需要加载资源时,会检查用户设置的语言和地区,按以下顺序查找本地化文件夹:
1. 先查找语言/地区匹配的文件夹,如用户选择法语(瑞士),先找 fr-CH.lproj
2. 若未找到,使用语言的三字母ISO代码查找,如 fre-CH fra-CH
3. 若仍未找到,只查找语言匹配的文件夹,如 fr.lproj
4. 若都未找到,使用开发基础语言的资源。

如果有多个匹配的本地化文件夹,会优先查找更具体的匹配。例如,用户选择瑞士法语,优先查找 fr-CH.lproj ,若未找到资源再查找 fr.lproj

3. 本地化建议

只对受语言或地区影响的资源进行本地化。例如,没有文字且含义通用的图像无需本地化。

通过以上步骤,开发者可以开发出功能丰富的相机与照片库应用,并实现应用的本地化,以满足全球用户的需求。

iOS开发:相机与照片库应用及应用本地化指南(续)

相机与照片库应用开发总结

为了更清晰地展示相机与照片库应用开发的流程,我们可以用以下流程图表示:

graph TD;
    A[创建项目] --> B[设计界面];
    B --> C[实现相机视图控制器];
    C --> D[编译运行];
    B --> B1[添加出口和协议];
    B --> B2[添加动作方法];
    B --> B3[编辑GUI];
    B --> B4[添加自动布局约束];
    C --> C1[添加属性和导入头文件];
    C --> C2[增强视图方法];
    C --> C3[实现实用方法];
    C --> C4[实现动作方法];
    C --> C5[实现委托方法];

下面我们通过一个表格总结开发过程中的关键代码和功能:
| 功能模块 | 代码示例 | 功能说明 |
| — | — | — |
| 处理用户取消选择器 | objc - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { [picker dismissViewControllerAnimated:YES completion:NULL]; } | 当用户取消图像选择器时,关闭选择器 |
| 视图控制器协议和属性 | objc @interface ViewController () <UIImagePickerControllerDelegate, UINavigationControllerDelegate> @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property (weak, nonatomic) IBOutlet UIButton *takePictureButton; @end | 遵循必要协议,定义出口属性 |
| 动作方法 | objc - (IBAction)shootPictureOrVideo:(id)sender { [self pickMediaFromSource:UIImagePickerControllerSourceTypeCamera]; } - (IBAction)selectExistingPictureOrVideo:(id)sender { [self pickMediaFromSource:UIImagePickerControllerSourceTypePhotoLibrary]; } | 调用 pickMediaFromSource: 方法选择媒体源 |
| 实用方法 - updateDisplay | objc - (void)updateDisplay { if ([self.lastChosenMediaType isEqual:(NSString *)kUTTypeImage]) { self.imageView.image = self.image; self.imageView.hidden = NO; self.moviePlayerController.view.hidden = YES; } else if ([self.lastChosenMediaType isEqual:(NSString *)kUTTypeMovie]) { // ... } } | 根据选择的媒体类型更新显示内容 |
| 实用方法 - setMoviePlayerLayoutConstraints | objc - (void)setMoviePlayerLayoutConstraints { UIView *moviePlayerView = self.moviePlayerController.view; UIView *takePictureButton = self.takePictureButton; moviePlayerView.translatesAutoresizingMaskIntoConstraints = NO; NSDictionary *views = NSDictionaryOfVariableBindings(moviePlayerView, takePictureButton); [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"H:|[moviePlayerView]|" options:0 metrics:nil views:views]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: @"V:|[moviePlayerView]-0-[takePictureButton]" options:0 metrics:nil views:views]]; } | 设置电影播放器的布局约束 |
| 实用方法 - pickMediaFromSource: | objc - (void)pickMediaFromSource:(UIImagePickerControllerSourceType)sourceType { NSArray *mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:sourceType]; if ([UIImagePickerController isSourceTypeAvailable:sourceType] && [mediaTypes count] > 0) { UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.mediaTypes = mediaTypes; picker.delegate = self; picker.allowsEditing = YES; picker.sourceType = sourceType; [self presentViewController:picker animated:YES completion:NULL]; } else { // ... } } | 创建并配置图像选择器,根据源类型选择相机或媒体库 |
| 委托方法 | objc - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { self.lastChosenMediaType = info[UIImagePickerControllerMediaType]; if ([self.lastChosenMediaType isEqual:(NSString *)kUTTypeImage]) { self.image = info[UIImagePickerControllerEditedImage]; } else if ([self.lastChosenMediaType isEqual:(NSString *)kUTTypeMovie]) { self.movieURL = info[UIImagePickerControllerMediaURL]; } [picker dismissViewControllerAnimated:YES completion:NULL]; } - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { [picker dismissViewControllerAnimated:YES completion:NULL]; } | 处理选择媒体完成和取消选择的情况 |

应用本地化深入探讨
1. 本地化操作步骤

要实现应用的本地化,具体操作步骤如下:
1. 创建本地化文件夹 :在应用包中为每个支持的语言创建子目录,命名以 .lproj 结尾。例如,为英语创建 en.lproj ,为法语创建 fr.lproj 等。
2. 翻译资源 :将应用中受语言影响的资源(如文本、图片中的文字等)翻译成对应语言,并放入相应的本地化文件夹中。
3. 设置支持的语言 :在Xcode项目设置中,添加支持的语言。具体操作如下:
- 打开项目的 Info.plist 文件。
- 找到 Localizations 字段,点击 + 号添加支持的语言。

2. 本地化注意事项
  • 资源管理 :确保每个本地化文件夹中的资源与开发基础语言的资源结构一致,避免出现资源缺失或不匹配的问题。
  • 动态文本 :对于应用中动态生成的文本,需要使用本地化函数进行处理,以确保在不同语言环境下正确显示。例如,在Objective - C中可以使用 NSLocalizedString 函数:
NSString *localizedText = NSLocalizedString(@"Hello", @"Greeting message");
  • 日期和时间格式 :不同地区的日期和时间格式可能不同,需要根据用户的地区设置进行调整。可以使用 NSDateFormatter 类来处理日期和时间的格式化:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
NSString *formattedDate = [dateFormatter stringFromDate:[NSDate date]];
3. 本地化测试

在完成本地化后,需要进行充分的测试,以确保应用在不同语言和地区环境下都能正常显示和运行。可以通过以下方式进行测试:
- 模拟器测试 :在iOS模拟器中设置不同的语言和地区,运行应用检查显示是否正确。
- 真机测试 :在不同语言和地区设置的真机上运行应用,进行全面的测试。

总结

通过本文的介绍,我们详细了解了iOS相机与照片库应用的开发流程,以及应用本地化的相关知识。在开发相机与照片库应用时,需要注意界面设计、视图控制器的实现和委托方法的处理。而在进行应用本地化时,要遵循资源加载规则,合理选择需要本地化的资源,并进行充分的测试。通过这些步骤,开发者可以开发出功能完善、支持多语言的iOS应用,满足全球用户的需求。

基于数据驱动的 Koopman 算子的递归神经网络模型线性化,用于纳米定位系统的预测控制研究(Matlab代码实现)内容概要:本文围绕“基于数据驱动的 Koopman 算子的递归神经网络模型线性化,用于纳米定位系统的预测控制研究”展开,提出了一种结合数据驱动方法Koopman算子理论的递归神经网络(RNN)模型线性化方法,旨在提升纳米定位系统的预测控制精度动态响应能力。研究通过构建数据驱动的线性化模型,克服了传统非线性系统建模复杂、计算开销大的问题,并在Matlab平台上实现了完整的算法仿真验证,展示了该方法在高精度定位控制中的有效性实用性。; 适合人群:具备一定自动化、控制理论或机器学习背景的科研人员工程技术人员,尤其是从事精密定位、智能控制、非线性系统建模预测控制相关领域的研究生研究人员。; 使用场景及目标:①应用于纳米级精密定位系统(如原子力显微镜、半导体制造设备)中的高性能预测控制;②为复杂非线性系统的数据驱动建模线性化提供新思路;③结合深度学习经典控制理论,推动智能控制算法的实际落地。; 阅读建议:建议读者结合Matlab代码实现部分,深入理解Koopman算子RNN结合的建模范式,重点关注数据预处理、模型训练控制系统集成等关键环节,并可通过替换实际系统数据进行迁移验证,以掌握该方法的核心思想工程应用技巧。
基于粒子群算法优化Kmeans聚类的居民用电行为分析研究(Matlb代码实现)内容概要:本文围绕基于粒子群算法(PSO)优化Kmeans聚类的居民用电行为分析展开研究,提出了一种结合智能优化算法传统聚类方法的技术路径。通过使用粒子群算法优化Kmeans聚类的初始聚类中心,有效克服了传统Kmeans算法易陷入局部最优、对初始值敏感的问题,提升了聚类的稳定性和准确性。研究利用Matlab实现了该算法,并应用于居民用电数据的行为模式识别分类,有助于精细化电力需求管理、用户画像构建及个性化用电服务设计。文档还提及相关应用场景如负荷预测、电力系统优化等,并提供了配套代码资源。; 适合人群:具备一定Matlab编程基础,从事电力系统、智能优化算法、数据分析等相关领域的研究人员或工程技术人员,尤其适合研究生及科研人员。; 使用场景及目标:①用于居民用电行为的高效聚类分析,挖掘典型用电模式;②提升Kmeans聚类算法的性能,避免局部最优问题;③为电力公司开展需求响应、负荷预测和用户分群管理提供技术支持;④作为智能优化算法机器学习结合应用的教学科研案例。; 阅读建议:建议读者结合提供的Matlab代码进行实践操作,深入理解PSO优化Kmeans的核心机制,关注参数设置对聚类效果的影响,并尝试将其应用于其他相似的数据聚类问题中,以加深理解和拓展应用能力。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值