Layout and design of the QQ chat interface (IOS)-first season and first season of ios

Source: Internet
Author: User
Tags network function

Layout and design of the QQ chat interface (IOS)-first season and first season of ios

  • The source file I wrote will be released in the second season ~, If you are interested in Baidu online storage, you can follow my blog updates and download them by yourself ~. Meow~~~

    QQChat Layout-Season 1. Preparations
  • 1. Import the false data messages. plist and icon image files to the project.

  • 2. Create a message for the corresponding data model to ensure that the attribute of the data model is the same as that in plist. Provides a constructor for the message class. (Since the name is the same as that of plist, we use KVC technology to initialize the data model. It will automatically assign values to attributes with the same name as in the dictionary ).
#import <UIKit/UIKit.h>typedef enum {    MessageWhoIsMe,    MessageWHoIsAnother}MessageWho;@interface Message : NSObject@property (nonatomic, strong) NSString * text;@property (nonatomic, strong) NSString * time;@property (nonatomic, assign) MessageWho type;@property (nonatomic, assign) CGFloat height;+ (instancetype)messageWithDict:(NSDictionary *)dict;@end
  • 3. in the ViewController of sb, drag the UITableView and UIView controls, set the number of cells in TableView to 1, and UIView is used as the QQ menu. first, add the constraint. The height is 44. The distance from the parent control is 0 to 0 at the bottom, left, and right. then, set the menu bar at the bottom of UITableView to 0 from QQ, and the parent control to 0 from left, right, and top. This gives you a general framework of the QQ chat interface.
Ii. UI framework construction

  • Observation: For example, through observation, we can know every chat message in QQ, which is actually a UITableViewCell object in one row. In other words, the chat box can be considered as a UITableView in essence. Therefore, as long as we can make the corresponding cell object, we can complete this interface. The problem is that the cell is not very high, which is one of the difficulties in this layout. For how to solve the problem, see the analysis in my project. Now we will focus on cell design. Obviously, we must customize the cell. There are multiple methods for customizing the cell. We choose storyBoard to customize the method.
  • Analysis: A message contains three elements: time, message avatar, and message content. Therefore, we drag a UILabel used to display the time and a UIButton used to display the content into the cell. Because the content has a background, it is more appropriate to use UIButton, you can also use UIImageView to display the Avatar. then set constraints. To complete the cell Layout and constraints settings.

  • Details:

    1. Create a MessageCell to inherit from UITableViewCell, and change the cell type in SB to the MessageCell type, for example, (to make the created cell the MessageCell object ).

    2. Use the drag-and-drop function to quickly associate the cell controls in SB with attributes in MessageCell in the MessageCell class.
Iii. Development
  • Meow ~~~~~, Good bird. All preparations are done. Next we will start encoding. What? That's all. Yes. Next, you have to listen to me carefully and tell me why you need to write code like this. Please bypass ~.

  • Step 1: Because we use false data, that is, the data in the plist file is simulated. Therefore, we omit the step of getting data from the network. We only need to load the plist data first. So how can we load data? To improve program efficiency, we use lazy loading to load data, that is, where data is needed, the data will be automatically loaded and cached. Meow ~~~, It seems amazing. I was so scared to go to the ground.

@ Interface ViewController () <UITableViewDataSource, UITableViewDelegate> @ property (weak, nonatomic) IBOutlet UITableView * tableView;/*** cache array for all dialogs */@ property (nonatomic, strong) NSArray * messages; @ end
// Lazy load-(NSArray *) messages {if (_ messages = nil) {NSString * path = [[NSBundle mainBundle] pathForResource: @ "messages" ofType: @ "plist"]; NSArray * dictArray = [NSArray arrayWithContentsOfFile: path]; NSMutableArray * messages = [NSMutableArray array]; for (NSDictionary * dict in dictArray) {Message * message = [Message messageWithDict: dict]; [messages addObject: message];} _ messages = messages;} return _ messages ;}
  • Step 2: implement the data source method to tell tableView how many rows of data are there and how many rows of data have data models. Therefore, we return the number of data models instead of writing code, in this way, when the number of chats increases or decreases, we do not need to change the numberOfRowsInSection method. We only need to add or delete model data. That is
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {    return self.messages.count;}
  • Step 3: implement the cellForRowAtPath of the data source method: The heightForRowAtPath method of the proxy object. One thing we have to do is to use the data model to drive the view and change the data to control the view changes. The intermediate controller serves as a logical transmission bridge for this change. This is the so-called MVC model. In this way, the responsibility is clearly defined, and the logic and data are separated, so the Code Coupling Degree is greatly reduced. However, the problem is that the heightForRowAtPath is generally called before cellForRowAtPath. At this time, the cell has not been created, that is, the data model has not been passed to the cell object through the Controller for data display, in this case, you cannot obtain the correct height. So we have to find a way to make these two methods execute in turn. Fortunately, Apple provides us with an attribute,estimatedRowHeightYou only need to set the estimated attribute size in a unified manner, or set the estimated cell height for each row (that is, each cell). Then, cellForRowAtPath is called to create the cell object, the height of the estimate is used to create the initialized cell, but heightForRowAtPath is also called when the cell is to be displayed on the interface. for convenience, I directly use the following code to provide a uniform estimate height and then implement these two methods.
- (void)viewDidLoad {    [super viewDidLoad];    self.tableView.estimatedRowHeight = 120;    // Do any additional setup after loading the view, typically from a nib.}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {    static NSString * ID = @"messageCell";    MessageCellTableViewCell * cell = [self.tableView dequeueReusableCellWithIdentifier:ID];    cell.message = self.messages[indexPath.row];    return cell;}- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {    return ((Message *)self.messages[indexPath.row]).height;}
  • Step 4: drive development and continue to improve. The development method I used is similar to the test-driven development method. I first wrote the desired results and then developed the results. Code above,cell.message = self.messages[indexPath.row];. What I want to achieve is to pass the data model directly to the cell object, because we do not need to expose the view layer to the controller layer. The view layer is related to data, in this way, we can achieve the separation of logic and data. The advantage is that, for example, if you have more than 10 controllers in your project, you also need to use this cell, then they need to repeatedly write more than 10 rows of operation data in the controller, which is unwise and poor encapsulation, therefore, we should encapsulate the code into the class that the cell object belongs to, and the cell will handle it by itself. in this encapsulation, the controller does not need to care about how the cell processes the data, but only needs to hand over the data to the cell for processing. So now we can come to the UIMessageCell class, add the Message attribute of the message class to it, and rewrite setter. Then, in setter, we need to do three things, the first thing is to keep the message pair, the second thing is to display the data on the control, and the third thing is to calculate the height of the cell after the data is filled, and move it to the data model. (When calculating the height, we need to use layoutIfNeeded twice to force the layout. For the specific reason, see the following notes)
@ Implementation MessageCellTableViewCell // get the image name of the corresponding Avatar-(NSString *) getPicture :( MessageWho) who {return who = MessageWhoIsMe? @ "Me": @ "other";}-(void) setMessage :( Message *) message {// 1. _ message = message; _ icon. image = [UIImage imageNamed: [self getPicture: message. type]; [_ text setTitle: message. text forState: UIControlStateNormal]; _ timeLabel. text = message. time; // 2. after the mandatory data layout is installed, the value of the set button height is accurate, and the update constraint [_ text layoutIfNeeded] is updated; // You must force the layout first. Then, the update constraint is accurate. // The update constraint is updated, the height of the button is equal to the text height. /* When creating a custom button-that is a button with the type UIButtonTypeCustom-the frame of the button is set to (0, 0, 0, 0) initially. before adding the button to your interface, you should update the frame to a more appropriate value. when the button is a M style, its frmae value is zero. The label in the button does not automatically wrap by default. */[_ Text updateConstraints: ^ (MASConstraintMaker * make) {CGFloat textH = CGRectGetHeight (_ text. titleLabel. frame); make. height. similar to (textH);}]; // 3. force the layout again to make the constraint take effect, so that the obtained button height is accurate [_ text layoutIfNeeded]; CGFloat textH = CGRectGetMaxY (_ text. frame); CGFloat iconH = CGRectGetMaxY (_ icon. frame); CGFloat cellH = MAX (textH, iconH) + 10; // 4. update cell height to model _ message. height = cellH;}-(void) awakeFromNib {// set wrap _ text. titleLabel. numberOfLines = 0;}-(void) setSelected :( BOOL) selected animated :( BOOL) animated {[super setSelected: selected animated: animated]; // Configure the view for the selected state}
  • If you have any questions about other small details, you can leave a message and discuss them with each other. If you have any questions, please advise. Please keep an eye on my blog and continue to improve and introduce how to make this QQ chat interface. If you have enough time in the future, the network function will be added ~~~.
  • The effects of the first season are as follows,We are looking forward to the second quarter's complete QQ conversation background and the simulated double conversation effect.~.
  • The source file I wrote will be released in the second season ~, If you are interested in Baidu online storage, you can follow my blog updates and download them by yourself ~. Meow~~~

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.