zoukankan      html  css  js  c++  java
  • IOS开发学习笔记043-QQ聊天界面实现

    QQ聊天界面实现

    效果如下:

    屏幕快照 2015 06 07 15 26 21 

     实现过程:

     1、首先实现基本界面

            头像使用 UIImageView :

            文字消息使用 UIButton

            标签使用 UILable :水平居中

            所有元素在一个cell中,在加载cell时进行判断显示和隐藏。

            合理设置各个控件之间的约束关系。主要是UIIimageVIew和UIButton顶部对齐,间距为10。UIButton的宽度设置一个约束范围,比如说 (>=60 &&  <=300);

            底部添加一个UIView ,添加输入框等。

           屏幕快照 2015 06 07 15 37 51 

    2、创建模型文件

          所有元素在一个cell中,在加载cell时进行判断显示和隐藏。

           按照message.plist文件内容添加需要的属性,然后添加一个cellHeight属性计算cell高度,和一个决定是否显示时间到cell得属性hideTime。

    #import <UIKit/UIKit.h>

     

    // 枚举类型,

    typedefenum{

        SLQMessageTypeMe = 0,

        SLQMessageTypeOther = 1

    }SLQMessageType;

      

    @interface SLQMessage : NSObject

    /*内容*/

    @property (strong, nonatomic) NSString *text;

    /*时间*/

    @property (strong, nonatomic) NSString *time;

    /*类型*/

    @property (assign, nonatomic) SLQMessageType type;

     

    /*cellHeight*/

    @property (assign, nonatomic) CGFloat cellHeight;

    /*是否隐藏时间*/

    @property (assign, nonatomic,getter=isHideTime) BOOL hideTime;

     

    + (instancetype)MessageWithDict:(NSDictionary *)dict;

      

    @end

     

    实现文件

     

    #import "SLQMessage.h"

     

    @implementation SLQMessage

     

    +(instancetype)MessageWithDict:(NSDictionary *)dict

    {

        SLQMessage *message = [[SLQMessage alloc] init];

        [message setValuesForKeysWithDictionary:dict];

        return  message;

    }

     

    @end

            这里需要注意的就是枚举类型的使用,如果在一个类中要定义枚举类型,那么命名规则就是:

            以类名开头后面直接跟操作标识;如 SLQMessage + Type

    3、实现对cell操作的封装

    #import <UIKit/UIKit.h>

    @classSLQMessage;

    @interface SLQMessageCell : UITableViewCell

     

    /*模型对象*/

    @property (strong, nonatomic) SLQMessage *message;

     

    + (instancetype)cellWithTableView:(UITableView *)tableView;

     

    @end

    对tableView的每一个控件拖线建立关联。然后重写setter方法,对控件进行赋值。

     

    #import "SLQMessageCell.h"

    #import "SLQMessage.h"

     

    //define this constant if you want to use Masonry without the 'mas_' prefix

    #define MAS_SHORTHAND

    //define this constant if you want to enable auto-boxing for default syntax

    #define MAS_SHORTHAND_GLOBALS

    #import "Masonry.h"

     

     

    @interfaceSLQMessageCell ()

    @property (weak, nonatomic) IBOutletUILabel *timeLable;

    @property (weak, nonatomic) IBOutletUIButton *meBtn;

    @property (weak, nonatomic) IBOutletUIImageView *meImage;

    @property (weak, nonatomic) IBOutletUIButton *otherBtn;

    @property (weak, nonatomic) IBOutletUIImageView *otherImage;

    @end

     

    @implementation SLQMessageCell

     

    // 重写setter方法

     

    - (void)setMessage:(SLQMessage *)message

    {

        _message = message;

       

        self.backgroundColor = [UIColorbrownColor];

        if(message.isHideTime) // 隐藏时间

        {

            self.timeLable.hidden = YES;

            [self.timeLableupdateConstraints:^(MASConstraintMaker *make) {

                make.height.equalTo(0); // 高度为0

            }];

        }

        else

        {

            self.timeLable.text = message.time;

            self.timeLable.hidden = NO;

            [self.timeLableupdateConstraints:^(MASConstraintMaker *make) {

                make.height.equalTo(22);

            }];

        }

        

        if (message.type == SLQMessageTypeMe)

        {

            [selfsetShowBtn:self.meBtnWithShowImage:self.meImageWithHideBtn:self.otherBtnWithHideImage:self.otherImage];

        }

        if (message.type == SLQMessageTypeOther)

        {

            [selfsetShowBtn:self.otherBtnWithShowImage:self.otherImageWithHideBtn:self.meBtnWithHideImage:self.meImage];

        }

    }

            因为每次显示cell都要进行计算,将cell的显示封装到方法中。

    // 显示隐藏控件并计算控件的高度

    - (void)setShowBtn:(UIButton *)showBtn WithShowImage:(UIImageView *)showImage WithHideBtn:(UIButton *)hideBtn WithHideImage:(UIImageView *)hideImage

    {

        [showBtn setTitle:self.message.textforState:UIControlStateNormal];

     

        // 隐藏其他

        hideBtn.hidden = YES;

        hideImage.hidden = YES;

        // 显示自己

        showBtn.hidden = NO;

        showImage.hidden = NO;

        

        // 强制更新

        [selflayoutIfNeeded];

        // 更新约束,设置按钮的高度就是textLable的高度

        [showBtn updateConstraints:^(MASConstraintMaker *make) {

            CGFloat buttonH = showBtn.titleLabel.frame.size.height;// 

            make.height.equalTo(buttonH);

        }];

        // 强制更新

        [selflayoutIfNeeded];

        CGFloat btnMaxY = CGRectGetMaxY(showBtn.frame);

        CGFloat imageMaxY = CGRectGetMaxY(showImage.frame);

        // 设置cell高度

        self.message.cellHeight = MAX(btnMaxY, imageMaxY) + 10;

    }

        其他方法和以往一样

    + (instancetype)cellWithTableView:(UITableView *)tableView

    {

        SLQMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:@"message"];

        return cell;

    }

    - (void)awakeFromNib {

        // Initialization code

        // 多行显示

         self.meBtn.titleLabel.numberOfLines=0;

         self.otherBtn.titleLabel.numberOfLines=0;

    }

    4、接下来说说按钮背景的问题

            按钮背景默认填充整个按钮,但是默认情况下的填充效果不是很好。

    如下代码:

        UIImageView *imageView = [[UIImageView alloc] init];

        imageView.frame = CGRectMake(10, 10, 300, 200);

        UIImage *image = [UIImage imageNamed:@"chat_send_nor"];

     

        // 方法1 ,设置拉伸间距,默认拉伸中心1*1像素

        //image = [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height * 0.5];

        // 方法2 设置边界

        UIEdgeInsets edge = UIEdgeInsetsMake(50, 40, 40, 40);

        //image = [image resizableImageWithCapInsets:edge ];

        

        // UIImageResizingModeStretch 拉伸模式

        // UIImageResizingModeTile 填充模式

        image = [image resizableImageWithCapInsets:edge resizingMode:UIImageResizingModeStretch];

        // 方法3

        // images.xcassets中对图片进行设置

        

        imageView.image = image;

        [self.view addSubview:imageView];

     

        // 对比图片

        UIImageView *imageView1 = [[UIImageView alloc] init];

        imageView1.frame = CGRectMake(10, 210, 300, 200);

        UIImage *image1 = [UIImage imageNamed:@"chat_send_nor"];

        imageView1.image = image1;

        [self.view addSubview:imageView1];

    会出现以下效果,默认是下边的图片,所以有必要对图片进行拉伸。

             屏幕快照 2015 06 07 16 21 42

          其中方法3的设置是将图片导入Image.xcassets中后选中图片设置。

            屏幕快照 2015 06 06 14 30 58

           可以通过代码设置按钮的内间距

        // 可以这样设置内间距

        UIEdgeInsets edge = UIEdgeInsetsMake(15151515);

        [showBtn setTitleEdgeInsets:edge];

           或者直接在按钮的属性里设置

             屏幕快照 2015 06 07 16 08 34

            设置过间距后,就可以计算btn的高度时,因为textlable的高度不固定,所以让btn的高度等于textLable 的高度。但是又因为按钮背景图片的边缘有一部分是透明的,如下:红色是按钮,蓝色是图片。  

            屏幕快照 2015 06 07 16 04 27   

           所以显示文字高度会,这里对其按钮高度 + 30,而textLable默认会水平垂直居中。

            屏幕快照 2015 06 07 16 07 07

    5、在控制器中得实现方法和以往的一样

            只需要在这里判断以下消息显示的时间是否一致,如果一致就隐藏。

    - (NSMutableArray *)messages

    {

        if (_messages == nil)

        {

            NSArray *dictArray = [NSArrayarrayWithContentsOfFile:[[NSBundlemainBundle] pathForResource:@"messages.plist"ofType:nil]];

            NSMutableArray *tempArray = [NSMutableArrayarray];

            // 记录上一个message,判断是否显示时间

            SLQMessage *lastMessage = nil;

            for (NSDictionary *dict in dictArray)

            {

                SLQMessage *message = [SLQMessage MessageWithDict:dict];

                message.hideTime = [message.time isEqualToString:lastMessage.time];

                [tempArray addObject:message];

                // 重新赋值

                lastMessage = message;

            }

            _messages = tempArray;

        }

        return_messages;

    }

     

     

    - (void)viewDidLoad {

        [superviewDidLoad];

    }

    /**

     *  tableView 行数

     */

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

    {

        //NSLog(@"%zd",self.messages.count);

        returnself.messages.count;

    }

    /**

     *  设置每一个cell

     */

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

    {

        SLQMessageCell *cell = [SLQMessageCellcellWithTableView:tableView];

        

        cell.message = self.messages[indexPath.row];

        

        return  cell;

    }

    /**

    设置cell高度

    */

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

    {

        SLQMessage *message = self.messages[indexPath.row];

        return message.cellHeight;

    }

    /**

     *  给出预估高度

     */

    - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath

    {

        return  200;

    }

     

    @end

     
     
    总结:
    这是一种方法,还有其他的实现方法,接下来尝试一下。
     

    5、用两个cell实现界面

    屏幕快照 2015 06 07 17 32 08

    只需改动一些代码就行。
            1、改动每个cell的标志 一个是me,一个是other
            2、修改setter方法

    // 重写setter方法

    - (void)setMessage:(SLQMessage *)message

    {

        _message = message;

       

        self.backgroundColor = [UIColorbrownColor];

        if(message.isHideTime) // 隐藏时间

        {

            self.timeLable.hidden = YES;

            [self.timeLableupdateConstraints:^(MASConstraintMaker *make) {

                make.height.equalTo(0);

            }];

        }

        else

        {

            self.timeLable.text = message.time; // 显示时间

            self.timeLable.hidden = NO;

            [self.timeLableupdateConstraints:^(MASConstraintMaker *make) {

                make.height.equalTo(22);

            }];

        }

        //

        [self.contentBtnsetTitle:message.textforState:UIControlStateNormal];

        // 强制布局

        [selflayoutIfNeeded];

        // 添加约束

        [self.contentBtnupdateConstraints:^(MASConstraintMaker *make) {

            CGFloat textLableHeight = self.contentBtn.titleLabel.frame.size.height + 30;

            make.height.equalTo(textLableHeight);

        }];

        

        [selflayoutIfNeeded];

        CGFloat btnMaxY = CGRectGetMaxY(self.contentBtn.frame);

        CGFloat iconMaxY = CGRectGetMaxY(self.iconImage.frame);

        message.cellHeight = MAX(btnMaxY, iconMaxY);

    }

            3、修改返回cell对象的方法,传入一个message用来判断是哪个cell

    /**

     *  返回cell对象

     */

    + (instancetype)cellWithTableView:(UITableView *)tableView andMessage:(SLQMessage *)message

    {

        NSString *ID =  (message.type == SLQMessageTypeMe)?@"me":@"other";

        SLQMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

        return cell;

    }  

          4、在控制器中设置如下

    /**

     *  设置每一个cell

     */

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

    {

        // 获取一个cell,根据类型

        SLQMessageCell *cell = [SLQMessageCell cellWithTableView:tableView andMessage:self.messages[indexPath.row]];

        

        cell.message = self.messages[indexPath.row];

        return  cell;

    }

     
    好了,效果一样。
     
     

    更新: 滚动到最新的一行

    响应一个发送按钮,点击发送按钮后获取文本框数据,并显示到tableView中。
    滚动到最新一行
     
    发送按钮如下
     

    /**

     *  发送信息

     */

    - (IBAction)sendMessage:(id)sender

    {

        // 获取文字内容

        NSString *message = self.textField.text;

        SLQMessageType type = (arc4random_uniform(2));

        // 更新模型数据

        SLQMessage *mess = [[SLQMessage alloc] init];

        mess.time = @"2015-11-23";

        mess.text = message;

        mess.type = type;

        // 设置模型数据,添加到数组

        [self.messages addObject:mess];

        

        // 刷新表格

        [self.tableViewreloadData];

        // 滚动到底部方法

        [selfscrollToBottom];

    }

     
    滚动底部方法
     

    // 滚动到底部

    - (void)scrollToBottom

    {

        CGFloat yOffset = 0;

        // 如果tableView的高度大于tableView的自有有高度,y轴偏移量就等于contentSize - bounds

        if (self.tableView.contentSize.height > self.tableView.bounds.size.height) {

            yOffset = self.tableView.contentSize.height - self.tableView.bounds.size.height;

        }

        // 设置偏移量为最底部

        [self.tableViewsetContentOffset:CGPointMake(0, yOffset) animated:NO];

    }

  • 相关阅读:
    学习Easyui
    JS链表
    Javascript数组
    布局管理器(转)
    JCombobox组合框效果实现(转)
    JComboBox
    java.lang.ClassFormatError
    JSplitPane demo
    USB OTG简单介绍
    Cookie/Session机制具体解释
  • 原文地址:https://www.cnblogs.com/songliquan/p/4559051.html
Copyright © 2011-2022 走看看