JQAddWordController
#import <UIKit/UIKit.h>
@interface JQAddWordController : UIViewController
@property (nonatomic,copy) NSString *queryStr;
@end
#import "JQAddWordController.h"
#import "JQWord.h"
#import "JQMessage.h"
#import "JQTextView.h"
#import "JQMessageFrame.h"
#import "JQMessageCell.h"
#import "JQQueryTool.h"
#import "JQNavigationController.h"
@interface JQAddWordController () <UITableViewDelegate,UITableViewDataSource,UIScrollViewDelegate,UITextViewDelegate>
@property (nonatomic,weak)JQTextView *textView;//自定义的自适应高度输入框
@property (nonatomic,weak)UIButton *backBtn;//输入框左边返回按钮
@property (nonatomic,weak)UIButton *sendBtn;//输入框右边选择btn
@property (nonatomic,weak)UITableView *tableView;
@property (nonatomic,strong)NSMutableArray *messageFrames;
@end
@implementation JQAddWordController
- (NSMutableArray *)messageFrames{
if (!_messageFrames) {
_messageFrames=[NSMutableArray array];
}
return _messageFrames;
}
#pragma mark 生命周期方法
- (void)viewDidLoad{
[super viewDidLoad];
self.title=@"查词";
self.view.backgroundColor=JQBoardBGColor;
//配置子控件:(底部输入框)
[self configSubview];
//监听键盘
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
//外界传参处理:(比如在webView中提交的单词)
[self configParam];
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
if (self.queryStr) return; //如果有外界的查询,那么不弹起键盘
//弹出键盘
[self.textView becomeFirstResponder];
}
-(void)dealloc{
/**
* 解除监听
*/
[[NSNotificationCenter defaultCenter]removeObserver:self];
}
- (void)configSubview{
//添加底部输入框
[self addSubviews];
//布局子控件
[self autoLayoutSubviews];
}
#pragma mark 创建控件方法
/**
* 添加TableView
*/
- (void)addSubviews{
//1.添加tableView
UITableView *tableView = [[UITableView alloc]init];
tableView.dataSource = self;
tableView.delegate = self;
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
tableView.backgroundColor = [UIColor clearColor];
tableView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:tableView];
self.tableView = tableView;
//2.添加返回按钮
UIButton *backBtn=[[UIButton alloc]init];
backBtn.translatesAutoresizingMaskIntoConstraints = NO;
[backBtn setImage:[UIImage imageNamed:@"back"] forState:UIControlStateNormal];
[backBtn addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:backBtn];
self.backBtn = backBtn;
//3.添加输入框
JQTextView *textView = [[JQTextView alloc]init];
textView.delegate = self;
textView.font = [UIFont systemFontOfSize:14];
textView.placeHoder = @"请输入要查询的内容";
[self.view addSubview:textView];
self.textView = textView;
//4.添加发送按钮
UIButton *sendBtn = [[UIButton alloc]init];
sendBtn.translatesAutoresizingMaskIntoConstraints = NO;
[sendBtn setImage:[UIImage imageNamed:@"send"] forState:UIControlStateNormal];
[sendBtn addTarget:self action:@selector(send:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:sendBtn];
self.sendBtn = sendBtn;
}
/**
* 布局子控件
*/
- (void)autoLayoutSubviews{
NSDictionary *views = NSDictionaryOfVariableBindings(_textView,_tableView,_backBtn,_sendBtn);
NSDictionary *metrics = @{@"margin":@8};
NSArray *constrain01 = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-margin-[_backBtn(30)]-margin-[_textView]-margin-[_sendBtn(==_backBtn)]-margin-|" options:NSLayoutFormatAlignAllCenterY metrics:metrics views:views];
NSArray *constrain02 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[_tableView]-margin-[_textView]-margin-|" options:0 metrics:metrics views:views];
NSArray *constrain03 = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[_tableView]-0-|" options:0 metrics:metrics views:views];
NSArray *constrain04 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[_backBtn(30)]" options:0 metrics:metrics views:views];
NSArray *constrain05 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[_sendBtn(==_backBtn)]" options:0 metrics:metrics views:views];
NSLayoutConstraint *constrainH = [NSLayoutConstraint constraintWithItem:_textView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeWidth multiplier:1 constant:20];
//->给textView赋值高度约束,让其可以自适应高度
_textView.constrainH = constrainH;
[self.view addConstraints:constrain01];
[self.view addConstraints:constrain02];
[self.view addConstraints:constrain03];
[self.view addConstraints:constrain04];
[self.view addConstraints:constrain05];
[_textView addConstraint:constrainH];
}
#pragma mark 点击方法
- (void)back{
//先退回键盘
[self.view endEditing:YES];
[self dismissViewControllerAnimated:YES completion:nil];
}
/**
* 点击发送button
*/
- (void)send:(UIButton *)btn{
NSString *queryStr = self.textView.text;
//0.判断输入框是否为空
if (queryStr.length <= 0)
return;
//1.发送查询的单词到聊天框
[self sendWordMsg:self.textView.text];
//2.获取结果
[JQQueryTool queryWord:queryStr completion:^(JQWord *word) {
if (word) { //如果查询到了单词翻译,那么返回word对象
[JQQueryTool queryExample:queryStr completion:^(NSString *example) {
JQMessage *message=[[JQMessage alloc]init];
message.type=JQMessageTypeWordInfo;
message.word = word;
word.examples = example;
JQMessageFrame *messageFrame=[JQMessageFrame messageFrameWithMessage:message];
[self.messageFrames addObject:messageFrame];
[self.tableView reloadData];
//4.滚到最后一行
[self scrollToLastRow];
}];
}else{
[JQQueryTool queryTranslation:queryStr completion:^(NSString *translation) {
JQMessage *message=[[JQMessage alloc]init];
message.type=JQMessageTypeTranslation;
message.text=translation;
JQMessageFrame *msgFrame=[JQMessageFrame messageFrameWithMessage:message];
[self.messageFrames addObject:msgFrame];
[self.tableView reloadData];
//4.滚到最后一行
[self scrollToLastRow];
}];
}
}];
/*
先查询单词的基本信息,如果没有查到对应单词翻译,那么转为查询句子翻译
*/
//3.回收键盘
[self.view endEditing:YES];
//4.清空文本
self.textView.text = @"";
}
#pragma mark 其他方法
/**
* 屏幕上显示用户发的 查询信息
*/
- (void)sendWordMsg:(NSString *)word_name{
JQMessage *message=[[JQMessage alloc]init];
message.text=word_name;
message.type=JQMessageTypeWord;
JQMessageFrame *messageFrame=[JQMessageFrame messageFrameWithMessage:message];
[self.messageFrames addObject:messageFrame];
[self.tableView reloadData];
}
/**
* 判断是否外界有传递查询的单词:(比如在单词模块复制单词时)
*/
- (void)configParam{
if (self.queryStr){
self.textView.text = self.queryStr;
[self send:nil];
}
}
#pragma mark 通知响应方法
/**
* 当键盘改变了frame(位置和尺寸)的时候调用
*/
- (void)keyboardWillChangeFrame:(NSNotification *)note
{
// 0.取出键盘动画的时间
CGFloat duration = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
// 1.取得键盘最后的frame
CGRect keyboardFrame = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
// 2.计算控制器的view需要平移的距离
CGFloat transformY = keyboardFrame.origin.y - self.view.frame.size.height;
// 3.执行动画
__block __weak typeof(self) temp=self;
[UIView animateWithDuration:duration animations:^{
temp.view.transform = CGAffineTransformMakeTranslation(0, transformY);
}];
}
#pragma mark UITableViewDelegate 代理方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.messageFrames.count;
}
- (JQMessageCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
JQMessageCell *cell=[JQMessageCell cellWithTableView:tableView];
cell.messageFrame=self.messageFrames[indexPath.row];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
JQMessageFrame *messageFrame=self.messageFrames[indexPath.row];
return messageFrame.cellHeight;
}
#pragma mark UITextViewDelegate 代理方法
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
if ([text isEqualToString:@"\n"]) { //换行相当于是发送
[self send:nil];
return NO;
}
return YES;
/*要么输入换行发送,要么点击发送按钮*/
}
#pragma mark UIScrollViewDelegate 代理方法
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
[self.view endEditing:YES];
[self.view endEditing:YES];
}
#pragma mark 内部工具方法
/**
* 滚动到最后一行
*/
- (void)scrollToLastRow{
NSIndexPath *lastPath = [NSIndexPath indexPathForRow:self.messageFrames.count - 1 inSection:0];
[self.tableView scrollToRowAtIndexPath:lastPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
/**
* tableView刷新插入的最后一行数据
*/
- (void)tableViewInsertLastRow{
NSIndexPath *indexPath=[NSIndexPath indexPathForRow:self.messageFrames.count-1 inSection:0];
[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
@end
JQMessageFrame
@interface JQMessageFrame : NSObject
@property (nonatomic,assign)CGRect iconFrame;//头像frame
@property (nonatomic,assign)CGRect textFrame;//文本frame()
@property (nonatomic,assign)CGRect cardViewFrame;
@property (nonatomic,assign)CGFloat cellHeight;//cell的高度
@property (nonatomic,strong)JQMessage *message;//消息
+ (instancetype)messageFrameWithMessage:(JQMessage *)message;
- (instancetype)initWithMessage:(JQMessage *)message;
@end
#define JQTextPadding 20 //用于内边距
#import "JQMessageFrame.h"
#import "JQMessage.h"
@implementation JQMessageFrame
+ (instancetype)messageFrameWithMessage:(JQMessage *)message{
return [[self alloc]initWithMessage:message];
}
- (instancetype)initWithMessage:(JQMessage *)message{
self=[super init];
if(self){
_message=message;
// 间距
CGFloat padding = 10;
// 屏幕的宽度
CGFloat screenW = [UIScreen mainScreen].bounds.size.width;
// 2.头像:(根据JQMessageType来判断头像的X)
CGFloat iconY = padding;
CGFloat iconW = 40;
CGFloat iconH = 40;
CGFloat iconX;
if (message.type == JQMessageTypeWord) {// word
iconX = screenW - padding - iconW;
} else {
iconX = padding;
}
_iconFrame = CGRectMake(iconX, iconY, iconW, iconH);
// 3.发送的单词或者翻译结果
if (message.type==JQMessageTypeWord || message.type==JQMessageTypeTranslation) {
// 3.正文
CGFloat textY = iconY;
// 文字的尺寸
CGSize textSize = [message.text sizeWithFont:JQFont maxSize:CGSizeMake(150, MAXFLOAT)];
CGSize textBtnSize = CGSizeMake(textSize.width + JQTextPadding * 2, textSize.height + JQTextPadding * 2);
CGFloat textX=0;
if (message.type==JQMessageTypeTranslation) {
textX=CGRectGetMaxX(_iconFrame) +padding;
}else{
textX=iconX - padding - textBtnSize.width;
}
_textFrame = (CGRect){{textX, textY}, textBtnSize};
}
//4.单词信息
else{ //给cardView尺寸
CGFloat cardViewW = 230;
CGFloat cardViewH = 430;
CGFloat cardViewY = CGRectGetMaxY(_iconFrame)+padding;
CGFloat cardViewX = (JQMainScreenSize.width-cardViewW)*0.5;
_cardViewFrame=(CGRect){{cardViewX,cardViewY},cardViewW,cardViewH};//CGRectMake(cardViewX, cardViewY, cardViewW, cardViewH);
#warning CGRect另类写法
}
// 4.cell的高度
CGFloat textMaxY = CGRectGetMaxY(_textFrame);
CGFloat iconMaxY = CGRectGetMaxY(_iconFrame);
CGFloat cardViewMaxY = CGRectGetMaxY(_cardViewFrame);
_cellHeight = MAX(cardViewMaxY, MAX(textMaxY, iconMaxY)) + padding;
}
return self;
}
@end
/*
通过传递过来的message信息来构造messageFrame
1.头像
如果 message.type == JQMessageTypeWord 说明是发送方
那么头像的位置在右边,否则是查询结果,那么头像位置在左边
设置对应_iconFrame
2.文本
如果 message.type == JQMessageTypeWordInfo 那么说明查询
到了单词信息,那么给_cardViewFrame设置frame
否则 message.type == JQMessageTypeWord或JQMessageTypeTranslation
那么给_textFrame赋值frame
3.计算cell的高度
*/
JQMessgae
typedef enum {
JQMessageTypeWord = 0, // 单词
JQMessageTypeWordInfo, // 单词信息
JQMessageTypeTranslation //翻译
} JQMessageType;
#import <Foundation/Foundation.h>
#import "JQWord.h"
@interface JQMessage : NSObject
/**
* 聊天内容
*/
@property (nonatomic, copy) NSString *text;
/**
* 信息的类型
*/
@property (nonatomic, assign) JQMessageType type;
/**
* 单词
*/
@property (nonatomic,strong)JQWord *word;
@end
JQMessageCell
#import <UIKit/UIKit.h>
#import "JQMessageFrame.h"
#import "JQMessage.h"
#import "JQCardView.h"
@interface JQMessageCell : UITableViewCell
@property (nonatomic,strong)JQMessageFrame *messageFrame;
+ (instancetype)cellWithTableView:(UITableView *)tableView;
@end
#define JQTextPadding 20 //文本内边距
#import "JQMessageCell.h"
#import "JQAddWordController.h"
#import "JQWordTool.h"
#import "JQButton.h"
@interface JQMessageCell ()
@property (nonatomic,weak) JQButton *textBtn;
@property (nonatomic,weak)JQCardView *cardView;
@property (nonatomic,weak)UIImageView *iconImgView;
@end
@implementation JQMessageCell
+ (instancetype)cellWithTableView:(UITableView *)tableView{
static NSString *ID=@"JQMessaeg";
JQMessageCell *messageCell=[tableView dequeueReusableCellWithIdentifier:ID];
if (!messageCell) {
messageCell=[[JQMessageCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
}
//不要选中状态
messageCell.selectionStyle = UITableViewCellSelectionStyleNone;
return messageCell;
}
/**
* 重写该方法来创建子控件
*/
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
self=[super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self createSubControl];
}
return self;
}
/**
* 创建子控件
*/
- (void)createSubControl{
//1.头像
UIImageView *iconImgView=[[UIImageView alloc]init];
[self.contentView addSubview:iconImgView];
self.iconImgView=iconImgView;
//2.文本
JQButton *textBtn=[[JQButton alloc]init];
textBtn.titleLabel.font=JQFont;
[textBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
textBtn.titleLabel.numberOfLines=0;//自动换行
//->设置文本按钮内边距,这样拉伸的北京图片才能完整摆放文本内容
textBtn.contentEdgeInsets=UIEdgeInsetsMake(JQTextPadding, JQTextPadding, JQTextPadding, JQTextPadding);
[textBtn setBackgroundImage:[UIImage resizedImage:@"chat_send_nor"] forState:UIControlStateNormal];
[self.contentView addSubview:textBtn];
self.textBtn=textBtn;
//->添加点击事件
[textBtn addTarget:self action:@selector(copy:) forControlEvents:UIControlEventTouchUpInside];
//3.cardView
JQCardView *cardView=[[JQCardView alloc]init];
[self.contentView addSubview:cardView];
self.cardView=cardView;
//背景色
self.backgroundColor=[UIColor clearColor];
}
/**
* 设置数据和Frame
*/
- (void)setMessageFrame:(JQMessageFrame *)messageFrame
{
_messageFrame = messageFrame;
JQMessage *message = messageFrame.message;
// 2.头像
NSString *icon = (message.type == JQMessageTypeWord) ? @"me" : @"JQWord";
self.iconImgView.image = [UIImage imageNamed:icon];
self.iconImgView.frame = messageFrame.iconFrame;
// 3.正文
[self.textBtn setTitle:message.text forState:UIControlStateNormal];
self.textBtn.frame = messageFrame.textFrame;
if (message.type==JQMessageTypeTranslation) {
[self.textBtn setBackgroundImage:[UIImage resizedImage:@"chat_recive_nor"] forState:UIControlStateNormal];
[self.textBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
}
// 4.cardView
self.cardView.frame=messageFrame.cardViewFrame;
self.cardView.word=message.word;
self.cardView.editTitle=@"添加";
//->添加操作
__weak typeof(self) messageCell=self;
self.cardView.editAction=^(){
if (!message.word) {
return ;
}
[JQWordTool addWord:message.word];
JQAddWordController *VC=(JQAddWordController *)messageCell.parentViewController;
//2.销毁当前控制器
[VC dismissViewControllerAnimated:YES completion:nil];
};
}
- (BOOL)canBecomeFirstResponder{
return YES;
}
#pragma mark 按钮实现弹出菜单控制器
/**
* 允许用@select()方式调用指定方法
*/
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (action == @selector(copyItemClicked:)) {
return YES;
}
return NO;
}
- (void)copy:(JQButton *)btn{
[btn becomeFirstResponder];
UIMenuController *menu=[UIMenuController sharedMenuController];
UIMenuItem *copyItem = [[UIMenuItem alloc] initWithTitle:@"复制" action:@selector(copyItemClicked:)];
/*@selector(copyItemClicked:) 必须加":"不然显示不出来*/
[menu setMenuItems:[NSArray arrayWithObjects:copyItem,nil]];
[menu setTargetRect:btn.frame inView:self];
[menu setMenuVisible:YES animated:YES];
}
- (void)copyItemClicked:(UIMenuController *)menu{
UIPasteboard *board = [UIPasteboard generalPasteboard];
board.string = self.textBtn.currentTitle;
}
@end
JQQueryTool
#import <Foundation/Foundation.h>
#import "JQWord.h"
@interface JQQueryTool : NSObject
+ (void)queryWord:(NSString *)wordName completion:(void (^)(JQWord *word))completion;
+ (void)queryExample:(NSString *)wordName completion:(void (^)(NSString *example))completion;
+ (void)queryTranslation:(NSString *)wordName completion:(void (^)(NSString *translation))completion;
@end
#import "JQQueryTool.h"
@implementation JQQueryTool
+ (void)queryWord:(NSString *)wordName completion:(void (^)(JQWord *word))completion{
//关闭菊花
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
AFHTTPSessionManager *manager=[AFHTTPSessionManager manager];
manager.requestSerializer.timeoutInterval=5.0;
//参数
NSMutableDictionary *params=[NSMutableDictionary dictionary];
params[@"keyfrom"]=@"wsxxjqr";
params[@"key"]=@"1645610927";
params[@"type"]=@"data";
params[@"doctype"]=@"json";
params[@"version"]=@"1.1";
params[@"q"]=wordName;
[manager GET:@"http://fanyi.youdao.com/openapi.do" parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
//关闭菊花
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
//1.获得基本数据:单词 音标 词义
JQWord *word=[JQWord wordWithDict:responseObject[@"basic"]];
word.word_name=wordName;
if(completion){
if (word.explains.count<=0)
completion (nil);
else
completion (word);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[SVProgressHUD showErrorWithStatus:@"请求失败"];
//关闭菊花
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if(completion){
completion (nil);
}
}];
}
+ (void)queryExample:(NSString *)wordName completion:(void (^)(NSString *example))completion{
//拼接查询路径
NSString *convert_word=[wordName stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
#warning word_name有可能是中文,必须转码
NSString *urlStr=[NSString stringWithFormat:@"http://dj.iciba.com/%@",convert_word];
NSURL *url=[NSURL URLWithString:urlStr];
//资源str
NSString *resourceStr=[NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
//:得到结果数组
NSArray *resultArr=[resourceStr arrFromStr:@"con=\"" toStr:@"\"" excStr:@"http" count:6];
//:数组中英拼接
NSMutableString *exampleStr=[NSMutableString string];
for (int i=0; i<resultArr.count; i+=2) {
[exampleStr appendString:[NSString stringWithFormat:@"%@\n",resultArr[i]]];
[exampleStr appendString:[NSString stringWithFormat:@"%@\n\n",resultArr[i+1]]];
}
if (completion) {
completion(exampleStr);
}
}
/**
* 使用百度api查询句子翻译
*/
+ (void)queryTranslation:(NSString *)wordName completion:(void (^)(NSString *translation))completion{
//显示菊花(表示正在加载单词对应信息)
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
AFHTTPSessionManager *manager=[AFHTTPSessionManager manager];
manager.requestSerializer.timeoutInterval=5.0;
//参数
NSMutableDictionary *params=[NSMutableDictionary dictionary];
params[@"q"]=wordName;
params[@"from"]= (wordName.hasChinese?@"zh":@"en");//使用分类判断单词中时候包含中文
params[@"to"] = (wordName.hasChinese?@"en":@"zh");
params[@"appid"] = @"20160529000022355";
params[@"salt"] = @(arc4random_uniform(10)).stringValue;
NSString *sign = [NSString stringWithFormat:@"%@%@%@%@",params[@"appid"],params[@"q"],params[@"salt"],@"ur3weJBGAhDn5FmJfJgh"];
params[@"sign"] = [sign md5String];
[manager GET:@"http://api.fanyi.baidu.com/api/trans/vip/translate" parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
//关闭菊花
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSString *str=[responseObject[@"trans_result"] firstObject][@"dst"];
if (completion){
completion(str);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
//关闭菊花
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[SVProgressHUD showErrorWithStatus:@"请求失败"];
if (completion){
completion(@"无");
}
}];
}
@end