毕业设计总结——自闭症儿童识别面部表情训练系统

      很开心完成了这个app,在新年愿望里其中有一个就是能有app上线AppStore,虽然未达到但相信会完成的。

      从15年12月份考研之后到今年的3月初,根据指导老师黄玲老师的需求做需求分析文档、设计文档、UML建模还有每一星期的计划报告,从需求分析到完成设计,体验了一次完整的软件开发过程。

      开学来到学校,同学们都在忙着找工作,校招、考公务员,那时我的心思全在项目上面,以致于到现在寝室里只剩我还在奔波找工作,小伙伴们准备打包行李回家/(ㄒoㄒ)/~~。不过,独立完成开发APP还是很爽的。

      好了,开始正题!

      我选择的毕业设计是自闭症儿童识别面部表情训练系统,老师的需求是通过玩游戏的形式让自闭症儿童识别人脸面部表情。参照过三星做的一款自闭症儿童辅助治疗app——LOOK AT ME,首尔大学的心理学教授,研究自闭症的专家来参与制作,是三星的良心之作。国内也有一款叫星星语,但只是一款辅助自闭症儿童进行与人交流的app。做不到三星那样的高大上,但有些地方是可以学习的。比如其中的拍摄人脸表情训练,于是,我想到了用上传用户头像。也就是实现出来是,给出一个题目让儿童拍摄人脸照片,(前提是与父母一起做这个训练,与父母做训练有利于儿童进行社会交流能力),完成后由父母评定拍摄照片是否正确,而LOOK AT ME是系统判定。

用的是hei苹果,Xcode版本是15年下载的6.0。

情景训练部分代码:

  1 //
  2 //  sightViewController.m
  3 //  情绪识别训练
  4 //
  5 //  Created by lpx on 16/3/16.
  6 //  Copyright (c) 2016年 lpx. All rights reserved.
  7 //
  8 
  9 #import "sightViewController.h"
 10 
 11 @interface sightViewController ()
 12 @property (weak, nonatomic) IBOutlet UIImageView *imaView;
 13 @property(nonatomic, strong) NSData *fileData;
 14 @property (weak, nonatomic) IBOutlet UILabel *showLabel;
 15 @end
 16 
 17 @implementation sightViewController
 18 
 19 int count = 0; //计数
 20 
 21 //返回菜单
 22 - (IBAction)backBtnClick:(id)sender {
 23     [self dismissModalViewControllerAnimated:YES];
 24 }
 25 #pragma mark - 修改状态栏样式
 26 - (UIStatusBarStyle)preferredStatusBarStyle {
 27     // 把statusBar的样式修改为白色
 28     return UIStatusBarStyleLightContent;
 29 }
 30 
 31 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
 32 {
 33     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
 34     if (self) {
 35         // Custom initialization
 36     }
 37     return self;
 38 }
 39 
 40 - (void)viewDidLoad {
 41     [super viewDidLoad];
 42     //换行
 43     _showLabel.lineBreakMode = UILineBreakModeWordWrap;
 44     _showLabel.numberOfLines = 0;
 45     
 46         self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"Bg-02.png"]];
 47 
 48     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
 49     NSString *documentsDirectory = [paths objectAtIndex:0];
 50     NSString *imageFilePath = [documentsDirectory stringByAppendingPathComponent:@"selfPhoto.jpg"];
 51     NSLog(@"imageFile->>%@",imageFilePath);
 52     UIImage *selfPhoto = [UIImage imageWithContentsOfFile:imageFilePath];//
 53     self.imaView.image = selfPhoto;
 54     [self.imaView.layer setCornerRadius:CGRectGetHeight([self.imaView bounds]) / 10];//修改半径
 55     self.imaView.layer.masksToBounds = YES;
 56     _showLabel.text = @"请拍一张高兴的人脸照片";
 57     count=0;//防止再次载入的时候 点击正确按钮无反应
 58 }
 59 
 60 - (IBAction)btnClik:(UIButton *)sender {
 61     
 62     UIActionSheet* actionSheet = [[UIActionSheet alloc]
 63                                   initWithTitle:@"请选择文件来源"
 64                                   delegate:self
 65                                   cancelButtonTitle:@"取消"
 66                                   destructiveButtonTitle:nil
 67                                   otherButtonTitles:@"照相机",@"本地相簿",nil];
 68     [actionSheet showInView:self.view];
 69 }
 70 - (IBAction)xiugai:(UIButton *)sender {
 71     
 72     
 73     [self.imaView setHidden:YES];
 74 }
 75 
 76 - (IBAction)zhengque:(UIButton *)sender {
 77        count =count+1;
 78     switch (count) {
 79         case 1:
 80        _showLabel.text=@"请拍一张悲伤的人脸照片";
 81             break;
 82         case 2:
 83        _showLabel.text=@"请拍一张惊讶的人脸照片";
 84             break;
 85         case 3:
 86        _showLabel.text=@"请拍一张害怕的人脸照片";
 87             break;
 88         case 4:
 89         _showLabel.text=@"请拍一张生气的照片";
 90             break;
 91         case 5:
 92             _showLabel.text=@"请拍一张中性的人脸照片";
 93             break;
 94             default:
 95             _showLabel.text=@"跟爸爸或妈妈合照一张,结束今天的训练!";
 96             break;
 97     }
 98 }
 99 
100 #pragma mark -
101 #pragma UIActionSheet Delegate
102 - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
103 {
104     // NSLog(@"buttonIndex = [%d]",buttonIndex);
105     switch (buttonIndex) {
106         case 0://照相机
107         {
108             UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
109             imagePicker.delegate = self;
110             imagePicker.allowsEditing = YES;
111             imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
112             //            [self presentModalViewController:imagePicker animated:YES];
113             [self presentViewController:imagePicker animated:YES completion:nil];
114         }
115             break;
116         case 1://本地相簿
117         {
118             UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
119             imagePicker.delegate = self;
120             imagePicker.allowsEditing = YES;
121             imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
122             //            [self presentModalViewController:imagePicker animated:YES];
123             [self presentViewController:imagePicker animated:YES completion:nil];
124         }
125             break;
126         default:
127             break;
128     }
129 }
130 
131 #pragma mark -
132 #pragma UIImagePickerController Delegate
133 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
134 {
135     if ([[info objectForKey:UIImagePickerControllerMediaType] isEqualToString:(__bridge NSString *)kUTTypeImage]) {
136         UIImage *img = [info objectForKey:UIImagePickerControllerEditedImage];
137         [self performSelector:@selector(saveImage:)  withObject:img afterDelay:0.5];
138     }
139     else if ([[info objectForKey:UIImagePickerControllerMediaType] isEqualToString:(__bridge NSString *)kUTTypeMovie]) {
140         NSString *videoPath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
141         self.fileData = [NSData dataWithContentsOfFile:videoPath];
142     }
143     //    [picker dismissModalViewControllerAnimated:YES];
144     [picker dismissViewControllerAnimated:YES completion:nil];
145 }
146 
147 - (void)saveImage:(UIImage *)image {
148     BOOL success;
149     NSFileManager *fileManager = [NSFileManager defaultManager];
150     NSError *error;
151     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
152     NSString *documentsDirectory = [paths objectAtIndex:0];
153     NSString *imageFilePath = [documentsDirectory stringByAppendingPathComponent:@"selfPhoto.jpg"];
154     NSLog(@"imageFile->>%@",imageFilePath);
155     success = [fileManager fileExistsAtPath:imageFilePath];
156     if(success) {
157         success = [fileManager removeItemAtPath:imageFilePath error:&error];
158     }
159      UIImage *smallImage = [self thumbnailWithImageWithoutScale:image size:CGSizeMake(300.0f, 300.0f)];//将图片尺寸改为300*300
160     [UIImageJPEGRepresentation(smallImage, 1.0f) writeToFile:imageFilePath atomically:YES];//写入文件
161     UIImage *selfPhoto = [UIImage imageWithContentsOfFile:imageFilePath];//读取图片文件
162     self.imaView.image = selfPhoto;
163 }
164 
165 - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
166 {
167     //    [picker dismissModalViewControllerAnimated:YES];
168     [picker dismissViewControllerAnimated:YES completion:nil];
169 }
170 
171 //保持原来的长宽比,生成一个缩略图
172 - (UIImage *)thumbnailWithImageWithoutScale:(UIImage *)image size:(CGSize)asize
173 {
174     UIImage *newimage;
175     if (nil == image) {
176         newimage = nil;
177     }
178     else{
179         CGSize oldsize = image.size;
180         CGRect rect;
181         if (asize.width/asize.height > oldsize.width/oldsize.height) {
182             rect.size.width = asize.height*oldsize.width/oldsize.height;
183             rect.size.height = asize.height;
184             rect.origin.x = (asize.width - rect.size.width)/2;
185             rect.origin.y = 0;
186         }
187         else{
188             rect.size.width = asize.width;
189             rect.size.height = asize.width*oldsize.height/oldsize.width;
190             rect.origin.x = 0;
191             rect.origin.y = (asize.height - rect.size.height)/2;
192         }
193         UIGraphicsBeginImageContext(asize);
194         CGContextRef context = UIGraphicsGetCurrentContext();
195         CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
196         UIRectFill(CGRectMake(0, 0, asize.width, asize.height));//clear background
197         [image drawInRect:rect];
198         newimage = UIGraphicsGetImageFromCurrentImageContext();
199         UIGraphicsEndImageContext();
200     }
201     
202 [self.imaView setHidden:NO];  //点击修改button的时候imgview不可见  在这里回复可见
203     return newimage;
204 }
205 @end

 

     训练分为四部分,接下来就是基础训练。

    基础训练,我是以播放帧动画的形式表现人脸情绪表情,播放动画的同时还会播放一段故事情景语音,带儿童进入一个故事情景训练,我想这样的训练效果会更好。

基础训练具体代码实现:

  1 //
  2 //  highViewController.m
  3 //  情绪识别训练
  4 //
  5 //  Created by lpx on 16/3/16.
  6 //  Copyright (c) 2016年 lpx. All rights reserved.
  7 //
  8 
  9 #import "highViewController.h"
 10 #import <AudioToolbox/AudioToolbox.h>
 11 
 12 typedef enum
 13 {
 14     kHappy = 0,     // 高兴
 15     kPain,          // 悲伤
 16     kAngry,         // 生气
 17     kFear,          // 害怕
 18     kSurprise,      // 惊讶
 19     kDetest,        // 厌恶
 20     kNormal,        // 中性
 21 } kAnimationType;
 22 
 23 @interface highViewController ()
 24 {
 25      //表情数据字典
 26        NSMutableDictionary *_emotionDict;
 27 
 28     // 音效的数据字典
 29     NSMutableDictionary *_soundDict;
 30 }
 31 @end
 32 
 33 @implementation highViewController
 34 //返回菜单
 35 - (IBAction)backBtnClick:(id)sender {
 36     [self dismissModalViewControllerAnimated:YES];
 37 }
 38 
 39 #pragma mark - 修改状态栏样式
 40 - (UIStatusBarStyle)preferredStatusBarStyle {
 41     // 把statusBar的样式修改为白色
 42     return UIStatusBarStyleLightContent;
 43 }
 44 
 45 /**
 46  用数据字典来实现音效的管理
 47  */
 48 - (SystemSoundID)loadSoundId:(NSString *)soundFile
 49 {
 50     NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:soundFile ofType:nil]];
 51     SystemSoundID soundId;
 52     AudioServicesCreateSystemSoundID((__bridge CFURLRef)(url), &soundId);
 53     return soundId;
 54 }
 55 
 56    //初始化界面入口
 57 - (void)viewDidLoad {
 58     [super viewDidLoad];
 59 
 60     //设置背景图片
 61     self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"Bg-02.png"]];
 62     
 63     // 数据初始化工作,加载数据字典成员变量
 64     
 65     // 1. 需要指定路径
 66     NSString *path = [[NSBundle mainBundle]pathForResource:@"Emotion" ofType:@"plist"];
 67     
 68     // 2. 加载数据字典
 69     _emotionDict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
 70 
 71     // 3. 初始化音效字典
 72     _soundDict = [NSMutableDictionary dictionary];
 73     
 74 }
 75 
 76 - (IBAction)animationBtnClick:(UIButton *)sender {
 77     if ([_emotionView isAnimating]) {
 78         return;
 79     }
 80     NSDictionary *dict;
 81     switch (sender.tag) {
 82         case kHappy:
 83             dict = _emotionDict[@"happy"];
 84             break;
 85         case kPain:
 86             dict = _emotionDict[@"pain"];
 87             break;
 88         case kAngry:
 89             dict = _emotionDict[@"angry"];
 90             break;
 91         case kFear:
 92             dict = _emotionDict[@"fear"];
 93             break;
 94         case kSurprise:
 95             dict = _emotionDict[@"surprise"];
 96             break;
 97         case kDetest:
 98             dict = _emotionDict[@"detest"];
 99             break;
100         case kNormal:
101             dict = _emotionDict[@"normal"];
102             break;
103         default:
104             break;
105     }
106 
107     NSMutableArray *imageList = [NSMutableArray array];
108     for (NSInteger i = 0; i < [dict[@"frames"]integerValue]; i++) {
109         NSString *imageFile = [NSString stringWithFormat:dict[@"imageFormat"], i];
110         UIImage *image = [UIImage imageNamed:imageFile];
111         [imageList addObject:image];
112     }
113     
114     NSArray *array = dict[@"soundFiles"];
115     // 2) 判断数组中是否有数据,如果有数据做进一步处理
116     SystemSoundID soundId = 0;
117     if (array.count > 0) {
118         // 3) 我们根据数组中得文件名,判断音频字典中是否有对应的记录,如果没有,建立新的音频数据字典
119         for (NSString *fileName in array) {
120             SystemSoundID playSoundId = [_soundDict[fileName]unsignedLongValue];
121             
122             // 如果在字典中没有定义音频代号,初始化音频Id,并且加入字典
123             if (playSoundId <= 0) {
124                 playSoundId = [self loadSoundId:fileName];
125                 // 将playSoundId加入到数据字典,向字典中增加数值,不是用add
126                 // 向NSDict NSArray中添加数值需要“包装”
127                 // @() 会把一个NSInteger的数字,变成NSNumber的对象
128                 [_soundDict setValue:@(playSoundId) forKey:fileName];
129             }
130         }
131         
132         // 每一个动画的声音可以是多个,采用随机数的方式播放音效
133         NSInteger seed = arc4random_uniform(array.count);
134         
135         NSString *fileName = array[seed];
136         
137         soundId = [_soundDict[fileName]unsignedLongValue];
138 
139     }
140     
141     
142     // 设置图像的动画属性
143     [_emotionView setAnimationImages:imageList];
144     [_emotionView setAnimationDuration:[dict[@"frames"]integerValue] / 10.0];
145     [_emotionView setAnimationRepeatCount:1];
146     [_emotionView startAnimating];
147 
148     // 播放声音
149     if (soundId > 0) {
150         
151     AudioServicesPlaySystemSound(soundId);
152         
153     }
154     
155 }
156 @end

第三部分是看图猜字游戏训练,给出一张人脸表情,填该图的情绪表情。

具体代码实现:

  1 //
  2 //  BasicViewController.m
  3 //  情绪识别训练
  4 //
  5 //  Created by lpx on 16/3/16.
  6 //  Copyright (c) 2016年 lpx. All rights reserved.
  7 //
  8 #import "BasicViewController.h"
  9 #import "MUModel.h"
 10 #import <AVFoundation/AVFoundation.h>
 11 
 12 // 定义 答案区域按钮的宽高
 13 #define kButtonWidht 30
 14 
 15 // 定义 答案区域按钮之间的间距
 16 #define kMargin 10
 17 
 18 // 屏幕的size
 19 #define kScreenSize ([UIScreen mainScreen].bounds.size)
 20 
 21 @interface BasicViewController ()
 22 
 23 @property (weak, nonatomic) IBOutlet UILabel *indexLabel;
 24 @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
 25 @property (weak, nonatomic) IBOutlet UIButton *imagebutton;
 26 @property (weak, nonatomic) IBOutlet UIView *answerview;
 27 @property (weak, nonatomic) IBOutlet UIView *optionView;
 28 @property (weak, nonatomic) IBOutlet UIButton *tipButton;
 29 @property (weak, nonatomic) IBOutlet UIButton *nextButton;
 30 @property (weak, nonatomic) IBOutlet UIButton *coinButton;
 31 @property (nonatomic, strong) NSArray *dataArray;
 32 // 表示第几题
 33 @property (nonatomic, assign) NSInteger index;
 34 @end
 35 
 36 @implementation BasicViewController
 37 //返回菜单
 38 - (IBAction)backBtnClick:(id)sender {
 39     [self dismissModalViewControllerAnimated:YES];
 40 }
 41 
 42 #pragma mark - 修改状态栏样式
 43 - (UIStatusBarStyle)preferredStatusBarStyle {
 44     // 把statusBar的样式修改为白色
 45     return UIStatusBarStyleLightContent;
 46 }
 47 
 48 #pragma mark - 懒加载数据
 49 - (NSArray *)dataArray {
 50     if (nil == _dataArray) {
 51         
 52         // 1. 读取文件路径
 53         NSString *path = [[NSBundle mainBundle] pathForResource:@"questions.plist" ofType:nil];
 54         
 55         // 2. 读取内容到临时数组
 56         NSArray *tempArray = [NSArray arrayWithContentsOfFile:path];
 57         
 58         // 3. 创建一个可变数组
 59         NSMutableArray *mutableArray = [NSMutableArray array];
 60         
 61         // 4. 遍历临时数组中的字典转为模型 , 存放到可变数组
 62         for (NSDictionary *dict in tempArray) {
 63             MUModel *guessModel = [MUModel guessModelDict:dict];
 64             [mutableArray addObject:guessModel];
 65         }
 66         
 67         // 5. 把可变数组赋值给 _dataArray
 68         _dataArray = mutableArray;
 69     }
 70     return _dataArray;
 71 }
 72 
 73 #pragma mark - 页面加载
 74 - (void)viewDidLoad {
 75     [super viewDidLoad];//界面入口
 76 
 77     // 初始化index = 1
 78     _index = 1;
 79     
 80     [self setupUI];
 81 //    _nextButton.enabled = NO;
 82 }
 83 
 84 #pragma mark - 设置UI界面
 85 - (void)setupUI {
 86     // 给控件设置数据
 87     // 取出_index - 1 在 数组中对应的数据
 88     MUModel *guessModel = self.dataArray[_index - 1];
 89     
 90     // 索引label
 91     _indexLabel.text = [NSString stringWithFormat:@"%ld/%ld",_index, self.dataArray.count];
 92     
 93     // titleLabel
 94     _titleLabel.text = guessModel.title;
 95     
 96     //换行
 97     _titleLabel.lineBreakMode = UILineBreakModeWordWrap;
 98     _titleLabel.numberOfLines = 0;
 99     
100     // 设置 imageButton
101     // 取出图片名称
102     NSString *imageName = guessModel.icon;
103     
104     // 实例化一个image对象
105     UIImage *image = [UIImage imageNamed:imageName];
106     
107     [_imagebutton setImage:image forState:UIControlStateNormal];
108 
109     /**
110      答案区域中, button的个数是跟答案的长度有关
111      根据每道题的答案个数来决定按钮的个数
112      
113      初始设置
114      [self setupAnswerView];
115      
116      答案的个数是不同的, 需要根据每一题的答案长度来确定
117      接收的参数: 答案的长度
118      修改后:
119      [self setupAnswerViewWithLenght:length];
120      */
121     
122     // 获取答案
123     NSString *answer = guessModel.answer;
124     
125     // 答案长度
126     NSInteger length = answer.length;
127     
128     [self setupAnswerViewWithLenght:length];
129     
130     /**
131      选项区域 3行 7 列 , 21 个按钮
132      按钮的个数不会发生变化, 变化的知识按钮上的文字
133      
134      初始设置:
135      [self setupOptionView];
136      
137      修改:
138      选项区域中的button上需要设置文本
139      传递参数: model中 options 数组, 存放button上需要的文字
140      */
141     [self setupOptionViewWithOptions:guessModel.options];
142 }
143 
144 #pragma mark - 答案区域设置
145 - (void)setupAnswerViewWithLenght:(NSInteger)count {
146     // 表示答案的长度, button的个数
147     //    int count = 5;
148     // (屏幕的宽度 - button的总宽度 - margin的总宽度)/ 2;
149     CGFloat startX = (kScreenSize.width - count * kButtonWidht - (count - 1) * kMargin)/2;
150     
151     // 添加本题的按钮的时候, 要把上一题的按钮给移除掉
152     //    for (UIView *view in _answerView.subviews) {
153     //        [view removeFromSuperview];
154     //    }
155     /**
156      让数组中所有的元素都执行 removeFromSuperview
157      */
158     [_answerview.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
159     
160     for (int i = 0; i < count; i++) {
161         // 计算button的x值
162         CGFloat buttonX = i * kButtonWidht + i * kMargin + startX;
163         
164         // 实例化button
165         UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(buttonX, 0, kButtonWidht, kButtonWidht)];
166         // 设置button的背景图片
167         [button setBackgroundImage:[UIImage imageNamed:@"Btn-option45"] forState:UIControlStateNormal];
168         [button setBackgroundImage:[UIImage imageNamed:@"btn_answer_highlighted"] forState:UIControlStateHighlighted];
169         // 设置文本颜色
170         [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
171         // 添加点击事件
172         [button addTarget:self
173                    action:@selector(didClickAnswerButton:)
174          forControlEvents:UIControlEventTouchUpInside];
175         // 添加到 answerView上
176         [_answerview addSubview:button];
177     }
178 }
179 
180 #pragma mark -  选项区域
181 - (void)setupOptionViewWithOptions:(NSArray *)options {
182     int column = 7;    // 确定列数
183     NSInteger count = options.count;     // 21个按钮
184     // 计算margin
185     CGFloat margin = (kScreenSize.width - column * kButtonWidht) / (column + 1);
186     // 把button给移除掉
187     [_optionView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
188     // 循环添加button
189     for (int i = 0; i < count; i++) {
190         // 得到行索引和列索引
191         NSInteger rowIndex = i / column;
192         NSInteger columnIndex = i % column;
193         // 计算x, y
194         CGFloat buttonX = (columnIndex + 1) * margin + columnIndex * kButtonWidht;
195         CGFloat buttonY = rowIndex * margin + rowIndex * kButtonWidht;
196         // 实例化按钮
197         UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(buttonX, buttonY, kButtonWidht, kButtonWidht)];
198         // 设置背景图片
199         [button setBackgroundImage:[UIImage imageNamed:@"Btn-option45"] forState:UIControlStateNormal];
200         [button setBackgroundImage:[UIImage imageNamed:@"btn_option_highlighted"] forState:UIControlStateHighlighted];
201         // 设置按钮的文字
202         [button setTitle:options[i] forState:UIControlStateNormal];
203         // 修改文本的颜色
204         [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
205         // 添加按钮的点击事件
206         [button addTarget:self
207                    action:@selector(didClickOptionButton:)
208          forControlEvents:UIControlEventTouchUpInside];
209         // 添加按钮到optionView
210         [_optionView addSubview:button];
211     }
212 }
213 
214 #pragma mark -  点击答案区域的按钮
215 - (void)didClickAnswerButton:(UIButton *)answerButton {
216     // 0. 对文本长度做判断
217     if (answerButton.currentTitle.length == 0) {
218         return;
219     }
220     /**
221      0. 如果被点击按钮没有文本, 就直接返回, 不必再执行后面的代码
222      1. 取出被点击按钮的文本
223      2. 清空被点击按钮的文本
224      3. 在选项区域中 对应到文本的按钮 显示出来
225      4. 如果用户输入错误导致字体变红, 当用户点击答案区域的按钮的时候, 就表示用户还没有输入完成
226      5. 打开选项区域的用户交互功能(如果用户完成输入, 会把选项区域给禁用)
227      */
228     
229     // 1. 取出文本
230     NSString *title = answerButton.currentTitle;
231     
232     // 2.清空被点击按钮的文本
233     [answerButton setTitle:@"" forState:UIControlStateNormal];
234     
235     // 3. 在选项区域中, 对应到文本的按钮, 显示出来
236     [_optionView.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
237         UIButton *optionButton = obj;
238         
239         // 取出button文本和 title进行比较, 如果相同, 就显示出来
240         if ([optionButton.currentTitle isEqualToString:title]) {
241             optionButton.hidden = NO;
242             
243             *stop = YES;
244         }
245     }];
246     
247     // 4. 把按钮的红色改为黑色
248     [_answerview.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
249         UIButton *answerButton = obj;
250         
251         [answerButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
252     }];
253     
254     // 5. 打开选项区域的用户交互
255     _optionView.userInteractionEnabled = YES;
256 }
257 
258 #pragma mark -  点击选项区域的按钮
259 - (void)didClickOptionButton:(UIButton *)optionButton {
260     /**
261      取button的title 一定要分状态
262      [optionButton titleForState:UIControlStateNormal];
263      
264      optionButton.currentTitle
265      
266      1. 把被点击按钮的文字取出来
267      2. 隐藏被点击按钮
268      3. 被点击按钮的文字出现在 答案区域的按钮上
269      4. 判断用户是否输入完成
270      5. 判断用户是否输入正确
271      */
272     
273     // 1. 取出文字
274     NSString *title = optionButton.currentTitle;
275     
276     // 2. 隐藏被点击按钮
277     optionButton.hidden = YES;
278     
279     // 3. 被点击按钮的文字 显示到 答案区域
280     // obj -->  数组中的对象
281     // idx -->  下标
282     // *stop --> 如果设置为 yes 的化,会立即跳出遍历
283     [_answerview.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
284         
285         UIButton *answerButton = obj;
286         if(answerButton.currentTitle.length==0)
287         {
288             [answerButton setTitle:title forState:UIControlStateNormal];
289         *stop = YES;
290            }
291     }];
292     // 4. 判断用户是否输入完成
293     // isComplete = YES 表示, 用户输入完成
294     __block BOOL isComplete = YES;
295     [_answerview.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
296         // 类型转换
297         UIButton *answerButton = obj;
298         if (answerButton.currentTitle.length == 0) {
299             // 该按钮还没有被设置文本
300             isComplete = NO;
301             *stop = YES;
302         }
303     }];
304     if (isComplete) { // 表示用户输入完成
305         // 用户不能再点击 选项区域中的按钮
306         // userInteractionEnabled = NO  禁止任何用户交互, 如果是父view设置了这个属性为NO, 那么它的子view也将不会接受用户交互
307         _optionView.userInteractionEnabled = NO;
308         /**
309          5. 判断用户是否输入正确
310          5.1 取出用户输入的答案
311          5.2 取出当前题目的正确答案
312          5.3 进行比较
313          */
314         
315         // 5.1 取出用户输入的答案
316         
317         // 定义一个可变字符串
318         NSMutableString *userAnswer = [NSMutableString string];
319         [_answerview.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
320             UIButton *answerButton = obj;
321             // 拼接每一个button上的文本
322             [userAnswer appendString:answerButton.currentTitle];
323         }];
324         
325         // 5.2 取出当前题目的正确答案
326         MUModel *guessModel = self.dataArray[_index - 1];
327         NSString *rightAnswer = guessModel.answer;
328         
329         // 5.3.2.1 取出当前的金币数量
330         NSInteger currentCoin = _coinButton.currentTitle.integerValue;
331         // 5.3 进行比较
332         if ([userAnswer isEqualToString:rightAnswer]) {
333             /**
334              用户输入正确
335 
336              1. 自动的跳入下一题
337              2. 增加100 金币
338              */
339             /********  答案正确播放音效  ********/
340             //1.获取音效文件
341             NSString *path = [[NSBundle mainBundle]pathForResource:@"你真棒.mp3" ofType:nil];
342             NSURL *url = [NSURL fileURLWithPath:path];
343             SystemSoundID soundID = 0;
344             AudioServicesCreateSystemSoundID((__bridge CFURLRef)(url), &soundID);
345             AudioServicesPlaySystemSound(soundID);
346             
347             //播放提示
348             //  实例化UIAlertController , ios7 UIAlertView
349                     UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"答对了!" message:@"你真厉害(ง •̀_•́)ง" preferredStyle:UIAlertControllerStyleAlert];
350                               //  展示alert
351                     [self presentViewController:alertController animated:YES completion:nil];
352              [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(creatAlert:) userInfo:alertController repeats:NO];
353             
354             
355             
356             // 5.3.1 自动跳入下一题
357             [self performSelector:@selector(didClickNextButton:) withObject:nil afterDelay:1];
358             
359             /**
360              5.3.2 增加100金币
361              1. 取出当前的金币数量
362              2. 更新(加/减)
363              3. 赋值回去
364              */
365             // 5.3.2.1 增加100金币
366             currentCoin += 100;
367             
368         } else {
369             /**
370              用户输入不正确
371              
372              1. 答案区域文本的字体变红
373              2. 减少1000金币
374              */
375             
376             // 5.3.1 当用户输入错误, 答案区域的文字变为红色
377             [_answerview.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
378                 UIButton *answerButton = obj;
379                 
380                 [answerButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
381                 
382             }];
383             
384 
385             // 5.3.2.2 减少1000金币
386             currentCoin -= 1000;
387         }
388         
389         // 5.3.2.3 把修改过的金币数量赋值给  _coinButotn
390         NSString *coinString = [NSString stringWithFormat:@"%ld",currentCoin];
391         
392         [_coinButton setTitle:coinString forState:UIControlStateNormal];
393     }
394 }
395 
396 //UIAlertView计时器
397 -(void)creatAlert:(NSTimer * )timer{
398     UIAlertController *alertController = [timer userInfo];
399     [alertController dismissViewControllerAnimated:YES completion:nil];
400     alertController = nil;
401 }
402 
403 #pragma mark - 点击提示按钮
404 - (IBAction)didClickTipButton:(id)sender {
405     
406     /**
407      1. 减去1000金币
408      2. 取出正确答案的第一个字
409      3. 在答案区域的第一个button上显示 第一个字, 其他按钮文本清空
410      4. 选项区域中, 只有第一字对应的button隐藏, 其他的显示出来
411      5. 答案区域的文本要变为黑色
412      6. 允许选项区域用户交互
413      7. 对用户的金币数量做判断, 如果不够减就提示用户
414      */
415     
416     // 1. 减去1000金币
417     // 1.1 取出当前的金币数量
418     NSInteger currentCoin = _coinButton.currentTitle.integerValue;
419     
420     // 1.2 减去1000
421     currentCoin -= 100;
422       // 1.3 赋值回去
423     NSString *coinString = [NSString stringWithFormat:@"%ld", currentCoin];
424     [_coinButton setTitle:coinString forState:UIControlStateNormal];
425     
426     // 2. 取出正确答案的第一个字
427     // 2.1 先取出正确答案
428     MUModel *guessModel = self.dataArray[_index - 1];
429     NSString *rightAnswer = guessModel.answer;
430     
431     // 2.2 取第一个字
432     NSString *firstString = [rightAnswer substringToIndex:1];
433     
434     // 3. 答案区域第一个按钮显示 firstString , 其他按钮的文本清空掉
435     [_answerview.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
436         UIButton *answerButton = obj;
437         
438         if (idx == 0) { // 第一个button , 设置正确答案的第一个字
439             [answerButton setTitle:firstString forState:UIControlStateNormal];
440         } else { // 如果不是第一个按钮, 就直接清空文本
441             [answerButton setTitle:@"" forState:UIControlStateNormal];
442         }
443         
444     }];
445     
446     // 4. 选项区域中和第一个字对应的button隐藏, 其他的全部显示
447     [_optionView.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
448         UIButton *optionButton = obj;
449         
450         if ([optionButton.currentTitle isEqualToString:firstString]) {
451             // 如果字符串相等, 就把button隐藏
452             optionButton.hidden = YES;
453         } else {
454             // 不等的话就显示出来
455             optionButton.hidden = NO;
456         }
457     }];
458     
459     // 5. 修改答案区域文本颜色为黑色
460     [_answerview.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
461         UIButton *answerButton = obj;
462         
463         [answerButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
464     }];
465     
466     // 6. 允许选项区域的用户交互
467     _optionView.userInteractionEnabled = YES;
468 }
469 #pragma mark -
470 #pragma mark -  点击"下一题"按钮
471 - (IBAction)didClickNextButton:(id)sender {
472     
473     // 0. 是否是最后一道题进行判断
474     if (_index == self.dataArray.count) {
475         
476         return;
477     }
478     
479     /**
480      0. 先进行判断是否是最后一道题, 如果是, 就直接返回 (防止最后一道题回答正确之后,导致的崩溃)
481      1. 让index + 1
482      2. 切换界面数据
483      3. 到最后一题的时候, 按钮禁用
484      4. 如果用户输入完成, optionView的用户交互功能会被禁用, 在这里要打开
485      */
486     
487     // 1. 让index + 1
488     _index++;
489     
490     // 2. 切换数据
491     [self setupUI];
492     
493     // 3. 到最后一题的时候禁用按钮
494     // 按钮被禁用将不再响应任何用户交互(点击按钮之后不会再调用相应的方法)
495     _nextButton.enabled = (_index != self.dataArray.count);
496     
497     // 4. 开启optionView的用户交互功能
498     _optionView.userInteractionEnabled = YES;
499 }
500 @end

最后一个情景训练,框架跟上一个训练是一样的,只不过把图片改成了播放情景视频,给出训练题目,观看视频,然后回答问题。

具体代码实现:

  1 //
  2 //  VideoViewController.m
  3 //  情绪识别训练
  4 //
  5 //  Created by lpx on 16/4/11.
  6 //  Copyright (c) 2016年 lpx. All rights reserved.
  7 //
  8 
  9 #import "VideoViewController.h"
 10 #import <MediaPlayer/MediaPlayer.h>
 11 #import "MUModel.h"
 12 #import <AVFoundation/AVFoundation.h>
 13 
 14 // 屏幕的size
 15 #define kScreenSize ([UIScreen mainScreen].bounds.size)
 16 // 定义 答案区域按钮的宽高
 17 #define kButtonWidht 60
 18 
 19 // 定义 答案区域按钮之间的间距
 20 #define kMargin 10
 21 
 22 @interface VideoViewController ()
 23 @property (weak, nonatomic) IBOutlet UILabel *indexLabel;
 24 @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
 25 @property (weak, nonatomic) IBOutlet UIButton *imagebutton;
 26 @property (weak, nonatomic) IBOutlet UIView *optionView;
 27 @property (weak, nonatomic) IBOutlet UIButton *nextButton;
 28 @property (weak, nonatomic) IBOutlet UIButton *previousBtn;
 29 @property (nonatomic, strong) MPMoviePlayerController  *vc;
 30 @property (nonatomic, strong) NSArray *dataArray;
 31 // 表示第几题
 32 @property (nonatomic, assign) NSInteger index;
 33 @end
 34 
 35 @implementation VideoViewController
 36 
 37 - (void)viewDidLoad {
 38     [super viewDidLoad];
 39     self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"Bg-02.png"]];
 40     
 41     // 初始化index = 1
 42     _index = 1;
 43 
 44     [self setupUI];
 45 }
 46 
 47 - (IBAction)returnBtn:(id)sender {
 48     [self dismissModalViewControllerAnimated:YES];
 49 
 50 }
 51 
 52 #pragma mark - 懒加载数据
 53 - (NSArray *)dataArray {
 54     if (nil == _dataArray) {
 55         
 56         // 1. 读取文件路径
 57         NSString *path = [[NSBundle mainBundle] pathForResource:@"MovieQuestion.plist" ofType:nil];
 58         
 59         // 2. 读取内容到临时数组
 60         NSArray *tempArray = [NSArray arrayWithContentsOfFile:path];
 61         
 62         // 3. 创建一个可变数组
 63         NSMutableArray *mutableArray = [NSMutableArray array];
 64         
 65         // 4. 遍历临时数组中的字典转为模型 , 存放到可变数组
 66         for (NSDictionary *dict in tempArray) {
 67             MUModel *guessModel = [MUModel guessModelDict:dict];
 68             
 69             [mutableArray addObject:guessModel];
 70         }
 71         
 72         // 5. 把可变数组赋值给 _dataArray
 73         _dataArray = mutableArray;
 74         
 75     }
 76     return _dataArray;
 77 }
 78 
 79 #pragma mark - 设置UI界面
 80 - (void)setupUI {
 81     
 82     // 给控件设置数据
 83     // 取出_index - 1 在 数组中对应的数据
 84     MUModel *guessModel = self.dataArray[_index - 1];
 85     
 86         // 索引label
 87         _indexLabel.text = [NSString stringWithFormat:@"%ld/%ld",(long)_index, (unsigned long)self.dataArray.count];
 88     
 89         // titleLabel
 90         _titleLabel.text = guessModel.title;
 91     
 92     //设置 imageButton
 93     // 取出图片名称
 94       NSString *imageName = guessModel.icon;
 95     //    // 实例化一个image对象
 96        UIImage *image = [UIImage imageNamed:imageName];
 97     //
 98        [_imagebutton setImage:image forState:UIControlStateNormal];
 99     //
100     
101     //换行
102     _titleLabel.lineBreakMode = UILineBreakModeWordWrap;
103     _titleLabel.numberOfLines = 0;
104     
105     /**
106 
107      按钮的个数不会发生变化, 变化的知识按钮上的文字
108      初始设置:
109      [self setupOptionView];
110      
111      修改:
112      选项区域中的button上需要设置文本
113      传递参数: model中 options 数组, 存放button上需要的文字
114      */
115     [self setupOptionViewWithOptions:guessModel.options];
116     
117       _optionView.userInteractionEnabled = NO;
118 }
119 
120 #pragma mark -  选项区域
121 - (void)setupOptionViewWithOptions:(NSArray *)options {
122     // 确定列数
123     int column = 4;
124 
125     NSInteger count = options.count;
126     
127     // 计算margin
128     CGFloat margin = (kScreenSize.width - column * kButtonWidht) / (column + 1);
129     
130     // 把button给移除掉
131     
132     [_optionView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
133     
134     // 循环添加button
135     for (int i = 0; i < count; i++) {
136         // 得到行索引和列索引
137         NSInteger rowIndex = i / column;
138         NSInteger columnIndex = i % column;
139         
140         // 计算x, y
141         CGFloat buttonX = (columnIndex + 1) * margin + columnIndex * kButtonWidht;
142         CGFloat buttonY = rowIndex * margin + rowIndex * kButtonWidht;
143         
144         // 实例化按钮
145         UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(buttonX, buttonY, kButtonWidht, kButtonWidht)];
146         
147         // 设置背景图片
148         [button setBackgroundImage:[UIImage imageNamed:@"Btn-answer57"] forState:UIControlStateNormal];
149         [button setBackgroundImage:[UIImage imageNamed:@"btn_option_highlighted"] forState:UIControlStateHighlighted];
150         
151         // 设置按钮的文字
152         [button setTitle:options[i] forState:UIControlStateNormal];
153         
154         // 修改文本的颜色
155         [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
156         
157         // 添加按钮的点击事件
158         [button addTarget:self
159                    action:@selector(didClickOptionButton:)
160          forControlEvents:UIControlEventTouchUpInside];
161         
162         // 添加按钮到optionView
163         [_optionView addSubview:button];
164     }
165 }
166 
167 #pragma mark -  点击选项区域的按钮
168 - (void)didClickOptionButton:(UIButton *)optionButton {
169     
170     // 1. 取出文字
171     NSString *title = optionButton.currentTitle;
172     // 5.2 取出当前题目的正确答案
173     MUModel *guessModel = self.dataArray[_index - 1];
174     
175     NSString *rightAnswer = guessModel.answer;
176     
177     //如果回答正确
178     if (title==rightAnswer) {
179         
180         NSString *path = [[NSBundle mainBundle]pathForResource:@"你真棒.mp3" ofType:nil];
181         NSURL *url = [NSURL fileURLWithPath:path];
182         SystemSoundID soundID = 0;
183         AudioServicesCreateSystemSoundID((__bridge CFURLRef)(url), &soundID);
184         AudioServicesPlaySystemSound(soundID);
185         
186         //播放提示
187         
188         // 1. 实例化UIAlertController , ios7 UIAlertView
189         UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"答对了!" message:@"你真厉害(ง •̀_•́)ง" preferredStyle:UIAlertControllerStyleAlert];
190         [self presentViewController:alertController animated:YES completion:nil];
191         [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(creatAlert:) userInfo:alertController repeats:NO];
192         
193         // 自动跳入下一题
194         [self performSelector:@selector(nextBtn:) withObject:nil afterDelay:1];
195        
196     }
197 }
198 
199 //计时器
200 -(void)creatAlert:(NSTimer * )timer{
201     UIAlertController *alertController = [timer userInfo];
202     [alertController dismissViewControllerAnimated:YES completion:nil];
203     alertController = nil;
204 }
205 //播放视频
206 - (IBAction)play:(id)sender {
207     MUModel *guessModel = self.dataArray[_index - 1];
208     NSString *movieName = guessModel.moviename;
209     //创建播放器
210     NSString *path = [[NSBundle mainBundle]pathForResource:movieName ofType:nil];
211     MPMoviePlayerController  *vc = [[MPMoviePlayerController alloc]initWithContentURL:[NSURL fileURLWithPath:path]];
212     vc.view.frame = self.view.bounds;
213     [self.view addSubview:vc.view];
214     self.vc = vc;
215     //播放
216     [self.vc play];
217     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myMovieFinishedCallback:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
218 }
219 //播放完成后销毁视频控制器
220 -(void)myMovieFinishedCallback:(NSNotification*)notify
221 {
222     //视频播放对象
223     MPMoviePlayerController* vc = [notify object];
224     //销毁播放通知
225     [[NSNotificationCenter defaultCenter] removeObserver:self
226                                                     name:MPMoviePlayerPlaybackDidFinishNotification
227                                                   object:vc];
228     [vc.view removeFromSuperview];
229     
230       _optionView.userInteractionEnabled = YES;
231     
232 }
233 
234 - (IBAction)nextBtn:(id)sender {
235     
236     _previousBtn.enabled=YES;
237     // 0. 是否是最后一道题进行判断
238     if (_index == self.dataArray.count) {
239         return;
240     }
241     
242     /**
243      0. 先进行判断是否是最后一道题, 如果是, 就直接返回 (防止最后一道题回答正确之后,导致的崩溃)
244      1. 让index + 1
245      2. 切换界面数据
246      3. 到最后一题的时候, 按钮禁用
247      4. 如果用户输入完成, optionView的用户交互功能会被禁用, 在这里要打开
248      */
249     
250     // 1. 让index + 1
251     _index++;
252     
253     // 2. 切换数据
254     [self setupUI];
255     
256     // 3. 到最后一题的时候禁用按钮
257     // 按钮被禁用将不再响应任何用户交互(点击按钮之后不会再调用相应的方法)
258     _nextButton.enabled = (_index != self.dataArray.count);
259     
260     // 4. 开启optionView的用户交互功能
261  
262 }
263 
264 - (IBAction)previousBtn:(id)sender {
265     _nextButton.enabled=YES;
266     if (_index<0) {
267         return;
268     }
269         _index=_index-2;
270 
271     if (_index ==1 ) {
272         _previousBtn.enabled=NO;
273     }
274     
275        [self setupUI];
276 }
277 @end

 

posted @ 2016-05-25 22:57  活在梦里  阅读(977)  评论(0编辑  收藏  举报