IOS开发笔记(九)——IM聊天工具个人详情页面,自定义tableview的accessaryView

中山大学数据科学与计算机学院本科生实验报告

(2019年春季学期)

课程名称IOS开发任课老师郑贵锋
年级16专业(方向)软件工程(计算机应用方向)
学号16340132姓名梁颖霖
电话13680473185Emaildic0k@qq.com
开始日期2019/5/12完成日期2019/5/15

一、实验题目

IM聊天工具

二、实现内容

  • 个人详情页面UI
  • 后端接口:获取聊天消息记录

三、实验结果

聊天消息记录

1.概述

为了实现聊天工具对话的消息传递,这里我们引入了序列号的概念,每一个消息都有它特定的序号,我们根据这个序列号来确定这个消息是否已经发送,是否已经被接受到,是否需要删除等逻辑。

除此之外,为了实现多用户间的对话,例如A->B, A->C, B->C,他们之间如何能找到属于他们各自的信息呢?这里我们利用的是维护一个消息表,每一条消息都有发送用户的id,接受用户的id,内容的id,然后再通过内容的id在内容表格中找具体的内容。

2. URL设计
获取用户之间聊天记录
/history/personal
POST
{
to: {username}
data: {}
}

在Django的urls.py文件中表现为

urlpatterns = [
    path('personal', views.personal, name='personal'),
]
3. 具体实现
a.从消息表通过用户名获取聊天记录
# 返回聊天记录
def personal(request, t_username):
    response = {'state':'fail', 'msg':'no msg'}

    # 要在登录状态下
    if 'login_id' not in request.session:
        response['msg'] = 'no login'
        return HttpResponse(json.dumps(response), content_type = 'application/json')

    # 只允许GET方法
    if request.method != 'POST':
        response['msg'] = 'wrong method'
        return HttpResponse(json.dumps(response), content_type = 'application/json')

    # 查询的用户名为空
    if t_username == '':
        response['msg'] = 'miss username'
        return HttpResponse(json.dumps(response), content_type = 'application/json')
   
    # 已经登录, 所以拿取用户信息
    cur_username = request.session['login_id']

    # 数据库操作,查询消息
    try:
        # 当前用户发送给对方的信息
        cur_to_t_msg = Msg.objects.filter(Username = t_username, From = cur_username)
        
        # 对方发送给当前用户的信息
        t_to_cur_msg = Msg.objects.filter(Username = cur_username, From = t_username)
    except Exception as e:
        response['msg'] = 'db error'
        return HttpResponse(json.dumps(response), content_type = 'application/json')
    else:
        # 根据两类消息的ContentID来找出所有content
        # 这里先假设所有记录为文字类型,图片类型未知结果,待测试
        # Content_Text 
        ctArray = []
        # Content_Image 
        ciArray = []

        for msg in cur_to_t_msg:
            if msg.Type == 'text':
                ctArray.append(Content_Text.objects.filter(Cid = msg.ContentID))
            elif msg.Type == 'image':
                ciArray.append(Content_Image.objects.filter(Cid = msg.ContentID))

        for msg in t_to_cur_msg:
            if msg.Type == 'text':
                ctArray.append(Content_Text.objects.filter(Cid = msg.ContentID))
            elif msg.Type == 'image':
                ciArray.append(Content_Image.objects.filter(Cid = msg.ContentID))

        # 根据ContentID来进行append,保证时间有序
        
        if len(Content_Text) >= 1:
            # 序列化,返回多条文字内容
            serialized_obj = serializers.serialize('json', ctArray)
            response = {'state':'ok', 'msg':'ok', "data":serialized_obj}
        else:
            response['msg'] = 'no data'

    return HttpResponse(json.dumps(response), content_type = 'application/json')

具体逻辑

  • 定义返回体的内容,包括一个state和msg
  • 判断是否已经登陆状态
    • 是,直接返回HttpResponse,告诉前端已经登陆,无须注册
    • 否,下一步
  • 判断方法是否为GET
  • 判断查询的用户名是否为空
  • 获取用户登陆的用户名以及密码
  • 数据库操作
    • 通过用户名获取当前用户发送给对方的信息
    • 通过用户名获取对方发送给当前用户的信息
    • 根据两类消息的ContentID来找出所有content
    • 根据ContentID来进行append,保证时间有序
    • 序列化,返回多条文字内容

个人详情页面

效果截图:

r1

个人详情页面是使用UITableView来模仿微信聊天工具的详情所制作的

InfoViewController.h

#import <UIKit/UIKit.h>
#import "UserModel.h"

NS_ASSUME_NONNULL_BEGIN

@interface InfoViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *Birthplace;
@property (weak, nonatomic) IBOutlet UILabel *NickName;
@property (weak, nonatomic) IBOutlet UILabel *ID;
@property (weak, nonatomic) IBOutlet UILabel *Gender;
@property (strong, nonatomic) UserModel* User;
@property (weak, nonatomic) IBOutlet UIImageView *ProfilePicture;

@end

首先在.h文件定义所用到的一些属性,包括用户名,地区,性别,id号,头像等,还有一个登陆后的User的信息。

InfoViewController.m

这里首先定义所用到TableView,以及左侧的标题列表,右侧的内容列表来存储数据

#import "InfoViewController.h"

@interface InfoViewController ()<UITableViewDelegate, UITableViewDataSource>

@property(nonatomic, strong) UITableView *tableView;
@property(nonatomic, strong) NSMutableArray<NSString*> *titleList;
@property(nonatomic, strong) NSMutableArray<NSString*> *contentList;

@end

viewDidLoad函数中加载数据

  • 绑定User中的信息到之前定义的属性当中。
  • 定义navigationItem的标题名。
  • 获取屏幕的宽与高来定义tableview视图的大小与位置
  • 取消tableview默认的多余的横线
- (void)viewDidLoad {
    [super viewDidLoad];
    // [self.navigationController setNavigationBarHidden:NO animated:NO];
    self.navigationController.navigationBarHidden = NO;
    // Do any additional setup after loading the view.
    if (self.User == nil)
    {
        self.User = [[UserModel alloc] initWithProperties:@"peppa ID" NickName:@"Peppa" RemarkName:@"peppy" Gender:@"female" Birthplace:@"UK" ProfilePicture:@"peppa.jpg"];
    }
    self.ProfilePicture.image = [UIImage imageNamed:self.User.ProfilePicture];
    self.NickName.text = self.User.NickName;
    self.ID.text = self.User.UserID;
    self.Gender.text = self.User.Gender;
    self.Birthplace.text = self.User.Birthplace;
    
    self.navigationItem.title = @"个人信息";
    // 获取屏幕的宽高
    CGRect rect = [[UIScreen mainScreen] bounds];
    CGSize size = rect.size;
    CGFloat width = size.width;
    CGFloat height = size.height;
    
    self.tableView = ({
        UITableView *tableView = [[UITableView alloc]
                                  initWithFrame:CGRectMake(0, 50, width, height/2+70) style:UITableViewStylePlain];
        tableView.delegate = self;
        tableView.dataSource = self;
        tableView;
    });
    // 取消多余的横线
    self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
    
    [self.view addSubview:self.tableView];
    
    [self loadData];
}

加载数据,定义titleList,contentList

- (void)loadData {
    self.titleList = [NSMutableArray array];
    self.contentList = [NSMutableArray array];
    [self.titleList addObjectsFromArray:[[NSArray alloc] initWithObjects:@"头像", @"昵称", @"账号", @"性别", @"地区",nil]];
    [self.contentList addObjectsFromArray:[[NSArray alloc] initWithObjects:@"小猪佩奇", @"Peppa", @"peppy", @"female", @"UK",nil]];
}
  • 用numberOfSectionsInTableView定义tableview的section数目
  • 用heightForRowAtIndexPath定义tableview每一个cell的高度
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.titleList.count;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 80;
}

根据不同的行来给每个cell自定义accessoryView, 并绑定不同的数据。这里我们第一行是图片,故需要特殊处理来显示图片,而其他行则是显示内容,我这里修改一下它的字体与大小使得更加美观,对比度更加高。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *cellID = [NSString stringWithFormat:@"cellID:%zd", indexPath.section];
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    if (nil == cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
    }
    
    // cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    cell.textLabel.text = self.titleList[indexPath.row];
    cell.textLabel.font = [UIFont fontWithName:@"PingFangSC-Regular" size:18.f];
    if (indexPath.row != 0){
        UILabel *rightLabel = [[UILabel alloc]initWithFrame:CGRectMake(0,0,70,55)];
        rightLabel.text = self.contentList[indexPath.row];
        rightLabel.font = [UIFont fontWithName:@"PingFangSC-Regular" size:14.f];
        rightLabel.textColor = [UIColor grayColor];
        cell.accessoryView = rightLabel;
        //cell.accessoryView.backgroundColor = [UIColor redColor];   //加上红色容易看清楚
    }
    else{
        cell.accessoryView = ({
            UIImageView *imgV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:self.User.ProfilePicture]];
            CGRect frame = imgV.frame;
            frame = CGRectMake(0, 0, 100, 55);
            imgV.frame = frame;
            [imgV setContentMode:UIViewContentModeScaleAspectFit];
            imgV;
        });
    }
    return cell;
}

点击列表的item时跳转至修改页面

#pragma mark ------------ UITableViewDelegate ------------------

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    
    InfoViewController *controller = [[InfoViewController alloc] init];
    controller.hidesBottomBarWhenPushed = YES;
    [self.navigationController pushViewController:controller animated:YES];
}

用户退出按钮绑定事件,这里要与服务器进行交互,删除之前登陆的session

- (IBAction)logout:(id)sender {
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
    NSURL *url = [NSURL URLWithString:@"http://118.89.65.154:8000/account/logout/"];
    NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if(error == nil) {
            if(NSClassFromString(@"NSJSONSerialization")) {
                NSError *e = nil;
                id object = [NSJSONSerialization JSONObjectWithData:data options:0 error:&e];
                if(e) {
                    NSLog(@"error");
                }
                if([object isKindOfClass:[NSDictionary class]]) {
                    NSDictionary *result = object;
                    if([result[@"state"] isEqualToString:@"ok"]) {
                        NSLog(@"logout success");
                        UIStoryboard *indexStoryboard = [UIStoryboard storyboardWithName:@"Index" bundle:nil];
                        [UIApplication sharedApplication].keyWindow.rootViewController = indexStoryboard.instantiateInitialViewController;
                    }
                    else {
                        NSLog(@"logout fail");
                    }
                }
                else {
                    NSLog(@"Not dictionary");
                }
            }
        }
        else {
            NSLog(@"网络异常");
        }
    }];
    [task resume];
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值