The iOS_29 and ios_29 imitation chat Interfaces
Finally:
Encapsulation of custom Cells
BeyondCell
//// BeyondCell. h // 29_imitation chat /// Created by beyond on 14-9-4. // Copyright (c) 2014 com. beyond. all rights reserved. // # import <UIKit/UIKit. h> @ class BeyondCellFrame; @ interface BeyondCell: UITableViewCell // a custom cell line. during initialization, all controls are generated and added to contentView. Then, the cellWithCellFrame method is used, set all member frames and data of the CellFrame parameter (including the Msg object) to the controls in the cell. // return the reusable cellID + (NSString *) cellID written on the xib interface; // return a cell object (BeyondCell *) cellWithCellFrame :( BeyondCellFrame *) cellFrame; @ end through a WeiboFrames model object (which itself contains a Weibo Data Model)
//// BeyondCell. m // 29_imitation chat /// Created by beyond on 14-9-4. // Copyright (c) 2014 com. beyond. all rights reserved. // # import "BeyondCell. h "# import" BeyondCellFrame. h "# import" Msg. h "// class extension, also known as anonymous classification @ interface BeyondCell () {// 1, profile picture UIImageView * _ headImg; // 2, body content UILabel * _ content; // 3, large image UIImageView * _ bgImg;} @ end @ implementation BeyondCell // return the reusable cellID + (NSString *) written on the xib Interface *) cellID {return @ "BeyondCell";} // when no Cell exists in the pool, create a pure Cell and alloc all the child controls at a time, add contentView-(id) initWithStyle :( UITableViewCellStyle) style reuseIdentifier :( NSString *) reuseIdentifier {self = [super initWithStyle: style reuseIdentifier: reuseIdentifier]; if (self) {// No background color self after cell is selected. selectionStyle = UITableViewCellSelectionStyleNone; self. backgroundColor = [UIColor clearColor]; // no matter which one or two methods are used, instantiate all the controls and add them to contentView. // 1, avatar _ headImg = [[UIImageView alloc] init]; _ headImg. layer. cornerRadius = 10; _ headImg. layer. masksToBounds = YES; [self. contentView addSubview: _ headImg]; // 2, large image _ bgImg = [[UIImageView alloc] init]; [self. contentView addSubview: _ bgImg]; // 3. Add _ content = [[UILabel alloc] init] In the background image; _ content. backgroundColor = [UIColor clearColor]; // the font of the body content. The macro is defined in. h _ content. font = kContentFnt; _ content. numberOfLines = 0; _ content. lineBreakMode = NSLineBreakByWordWrapping; [_ bgImg addSubview: _ content];} return self;} // uses a Frames model object (it contains a data model ), return A cell Object filled with data. set all the member Frames and data of the frames parameter to the controls in the cell.-(BeyondCell *) cellWithCellFrame :( BeyondCellFrame *) cellFrame {Msg * msg = cellFrame. msg; // assign all the attribute values in the model object to the member control of the cell object. // 1. if ([msg. name isEqualToString: @ "nana"]) {_ headImg. image = [UIImage imageNamed: @ "icon01.jpg"];} else {_ headImg. image = [UIImage imageNamed: @ "icon02.jpg"];} // 5, body content _ content. text = msg. content; // 6, large image if ([msg. name isEqualToString: @ "nana"]) {_ bgImg. image = [UIImage imageStretchedWithName: @ "chatfrom_bg_normal.png" xPos: 0.5 yPos: 0.6];} else {_ bgImg. image = [UIImage imageStretchedWithName: @ "chatto_bg_normal.png" xPos: 0.5 yPos: 0.6];} // 1. The frame _ headImg of the Avatar. frame = cellFrame. headImgFrame; // 2, frame _ content of the body. frame = cellFrame. contentFrame; // 3, frame _ bgImg of bigImg. frame = cellFrame. contentBgImgFrame; return self;} @ end
Encapsulated Data Source Model
//// Msg. h // 29_imitation chat /// Created by beyond on 14-9-4. // Copyright (c) 2014 com. beyond. all rights reserved. // model, member: icon, body text # import <Foundation/Foundation. h> // font for content # define kContentFnt [UIFont fontWithName: @ "HelveticaNeue" size: 18366f] @ interface Msg: NSObject // Avatar image name @ property (nonatomic, copy) NSString * headImg; // message content @ property (nonatomic, copy) NSString * content; @ property (nonatomic, copy) NSString * name; @ property (nonatomic, strong) NSString * recordFileFath; // class method. The dictionary-to-object conversion is similar to the one-time filling + (Msg *) msgWithDict :( NSDictionary *) dict; // object method. After setting the object attributes, returned object-(Msg *) initWithDict :( NSDictionary *) dict; + (Msg *) msgWithName :( NSString *) name content :( NSString *) content recordFilePath :( NSString *) path; @ end
//// Msg. m // 29_imitation chat /// Created by beyond on 14-9-4. // Copyright (c) 2014 com. beyond. all rights reserved. // # import "Msg. h "@ implementation Msg // class method. The dictionary conversion object is similar to the one-time filling + (Msg *) msgWithDict :( NSDictionary *) dict {return [self alloc] initWithDict: dict];} // object method. After setting the object attributes, the returned object-(Msg *) initWithDict :( NSDictionary *) is returned *) dict {// The init method of the parent NSObject must be called first if (self = [super init]) {// set the attributes of the object. // assign the dictionary value to each attribute of the object through traversal. for (NSString * key in dict) {[self setValue: dict [key] forKeyPath: key];} // assign a dictionary value to each attribute of the object at a time. // [self setValuesForKeysWithDictionary: dict] ;}// return the filled object return self;} + (Msg *) msgWithName :( NSString *) name content :( NSString *) content recordFilePath :( NSString *) path {Msg * msg = [[self alloc] init]; msg. name = name; msg. content = content; msg. recordFileFath = path; return msg;} @ end
Key: frame Calculation Based on Data sources
//// BeyondCellFrame. h // 29_imitation chat /// Created by beyond on 14-9-4. // Copyright (c) 2014 com. beyond. all rights reserved. // # import <Foundation/Foundation. h> @ class Msg; // the margin between the control and the control # define kMargin 7 // the height and width of the Avatar # define kHeadImgHW 85 @ interface BeyondCellFrame: NSObject // The largest Y value, that is, the Row Height @ property (nonatomic, assign, readonly) CGFloat maxY; // it is important to have a member: object, which is used in the controller, after passing in the object, you can use the data of this model object to calculate all frames @ property (nonatomic, strong) Msg * msg; // frame @ property (nonatomic, assign, readonly) CGRect headImgFrame; // frame @ property (nonatomic, assign, readonly) of the background image of the chat body CGRect contentBgImgFrame; // frame @ property (nonatomic, assign, readonly) CGRect contentFrame; @ end
//// BeyondCellFrame. m // 29_imitation chat /// Created by beyond on 14-9-4. // Copyright (c) 2014 com. beyond. all rights reserved. // # import "BeyondCellFrame. h "# import" Msg. h "@ implementation BeyondCellFrame // a unique method of the CellFrame class: when setting Msg, you can use its data to calculate each frame and the largest Y, that is, the line height-(void) setMsg :( Msg *) msg {_ msg = msg; // The code for calculating each frame is put here ~~~ If ([msg. name isEqualToString: @ "nana"]) {[self standLeft: msg];} else {[self standRight: msg] ;}// put what I said on the right-(void) standRight :( Msg *) msg {// 1, frame // x CGFloat headImgX = 320-kHeadImgHW-kMargin; // y CGFloat headImgY = 0; // H CGFloat headImgH = kHeadImgHW; // W CGFloat headImgW = kHeadImgHW; _ headImgFrame = CGRectMake (headImgX, headImgY, headImgH, headImgW ); // ============================****************** ====== ==========================/// 2, bg frame // Width W CGFloat bgW = 320-kHeadImgHW-kMargin; // x CGFloat bgX = 320-bgW-kHeadImgHW-kMargin; // y CGFloat bgY = 0; // CGFloat winWidth = [[UIApplication sharedApplication] statusBarFrame]. size. width; // H CGFloat bgH = 300; _ contentBgImgFrame = CGRectMake (bgX, bgY, bgW, bgH ); // ============================****************** ====== ==========================/// 3, the frame body of the text is added to the image, and the upper left corner of the image is 0 0 // x CGFloat contentX = kMargin * 1.5; // y CGFloat contentY = kMargin; // If the width of W is greater than one row, assume CGFloat contentW = bgW-contentX-kMargin; CGFloat contentH = 0; // determine whether the content is sufficient for one row... // obtain the NSString size CGSize oneLineSize = [msg. content sizeWithAttributes: [NSDictionary dictionaryWithObjectsAndKeys: kContentFnt, NSFontAttributeName, nil]; CGFloat oneLineW = oneLineSize. width; if (oneLineW <contentW) {// if one row does not exist, CGFloat oneLineH = oneLineSize. height; contentX = kMargin * 1.2; _ contentFrame = CGRectMake (contentX, contentY, oneLineW, oneLineH); contentH = oneLineH; contentW = oneLineW; // 5, re-adjust the frame height of contentBgImg // the following three steps are the OC standard code, because OC does not allow users to directly repair the value of the members of the struct attribute in this object, the temporary struct variable CGRect frame = _ contentBgImgFrame; frame. size. width = contentW + kMargin * 3.5; frame. size. height = contentH + kMargin * 3; frame. origin. x = 320-contentW-headImgW-kMargin * 4; _ contentBgImgFrame = frame;} else {// if more than one row exists, calculate the height based on the following algorithm // dynamically set the height CGRect tmpRect = [msg. content Disposition: CGSizeMake (contentW, MAXFLOAT) options: incluattributes: [NSDictionary attributes: kContentFnt, NSFontAttributeName, nil] context: nil]; // height H contentH = tmpRect. size. height; _ contentFrame = CGRectMake (contentX, contentY, contentW, contentH); // 5, re-adjust the height of the contentBgImg frame. // the following three steps are the OC standard code, because OC does not allow users to directly repair the Member values of the struct attribute in this object, the temporary struct variable CGRect frame = _ contentBgImgFrame; frame must be passed. size. height = contentH + kMargin * 3; _ contentBgImgFrame = frame;} // 8. In this case, you can calculate the maximum value of Y, that is, if (headImgH> _ contentBgImgFrame. size. height) {_ maxY = CGRectGetMaxY (_ headImgFrame) + kMargin;} else {_ maxY = CGRectGetMaxY (_ contentBgImgFrame) + kMargin;}-(void) standLeft :( Msg *) msg {// 1, frame of the Avatar // x CGFloat headImgX = kMargin; // y CGFloat headImgY = kMargin of the Avatar; // H CGFloat headImgH = kHeadImgHW of the Avatar; // W CGFloat headImgW = kHeadImgHW; _ headImgFrame = CGRectMake (headImgX, headImgY, headImgH, headImgW ); // ============================****************** ====== ========================/// 4, bg frame // x CGFloat bgX = _ headImgFrame. size. width + kMargin; // y CGFloat bgY = _ headImgFrame. origin. y; // CGFloat winWidth = [[UIApplication sharedApplication] statusBarFrame]. size. width; // W CGFloat bgW = 320-bgX-kMargin; // H CGFloat bgH = 300; _ contentBgImgFrame = CGRectMake (bgX, bgY, bgW, bgH ); // 4. Add the frame body of the text to the image, and set it to 0 in the upper left corner of the image. // x CGFloat contentX = kMargin * 3; // y CGFloat contentY = kMargin; // CGFloat winWidth = [[UIApplication sharedApplication] statusBarFrame]. size. width; // If the width of W is greater than one CGFloat contentW = bgW-contentX-kMargin; CGFloat contentH = 0; // you can determine whether the content is sufficient for one row... // obtain the NSString size CGSize oneLineSize = [msg. content sizeWithAttributes: [NSDictionary dictionaryWithObjectsAndKeys: kContentFnt, NSFontAttributeName, nil]; CGFloat oneLineW = oneLineSize. width; if (oneLineW <contentW) {// if one row does not exist, CGFloat oneLineH = oneLineSize. height; contentX = kMargin * 2; _ contentFrame = CGRectMake (contentX, contentY, oneLineW, oneLineH); contentH = oneLineH; contentW = oneLineW; // 5, re-adjust the frame height of contentBgImg // the following three steps are the OC standard code, because OC does not allow users to directly repair the value of the members of the struct attribute in this object, the temporary struct variable CGRect frame = _ contentBgImgFrame; frame. size. width = contentW + kMargin * 3.5; frame. size. height = contentH + kMargin * 3; _ contentBgImgFrame = frame;} else {// If a row is exceeded, calculate the height based on the following algorithm // dynamically set the height CGRect tmpRect = [msg. content Disposition: CGSizeMake (contentW, MAXFLOAT) options: incluattributes: [NSDictionary attributes: kContentFnt, NSFontAttributeName, nil] context: nil]; // height H contentH = tmpRect. size. height; _ contentFrame = CGRectMake (contentX, contentY, contentW, contentH); // 5, re-adjust the height of the contentBgImg frame. // the following three steps are the OC standard code, because OC does not allow users to directly repair the Member values of the struct attribute in this object, the temporary struct variable CGRect frame = _ contentBgImgFrame; frame must be passed. size. height = contentH + kMargin * 3; _ contentBgImgFrame = frame;} // 8. In this case, you can calculate the maximum value of Y, that is, if (headImgH> _ contentBgImgFrame. size. height) {_ maxY = CGRectGetMaxY (_ headImgFrame) + kMargin;} else {_ maxY = CGRectGetMaxY (_ contentBgImgFrame) + kMargin ;}} @ end
Controller
//// BeyondViewController. m // 29_imitation chat /// Created by beyond on 14-9-2. // Copyright (c) 2014 com. beyond. all rights reserved. // # import "BeyondViewController. h "# import" Msg. h "# import" BeyondCellFrame. h "# import" BeyondCell. h "@ interface BeyondViewController () {// All weiboFrames loaded from the plist file (because it already contains a weibo member ), returns the NSMutableArray * _ msgFrames array composed of all objects;} @ end @ implementation BeyondViewController-(void) viewDidLoad {[super viewDidLoad]; // initialize object array _ msgFrames = [NSMutableArray array];} # pragma mark-UITextField proxy, send request-(BOOL) textFieldShouldReturn :( UITextField *) textField {if (textField. text. length = 0) {return NO;} BeyondCellFrame * frame = [[BeyondCellFrame alloc] init]; // ************ the WeiboFrames member weibo is configured with complicated calculations and fills in the frames of WeiboFrames. msg = [Msg msgWithName: @ "jackey" content: textField. text recordFilePath: @ "NoRecord"]; // Add it to the object array [_ msgFrames addObject: frame]; [self. tableView reloadData]; return YES;} # pragma mark-UITableView proxy method-(NSInteger) tableView :( UITableView *) tableView numberOfRowsInSection :( NSInteger) section {// remove the cell interval line tableView. separatorStyle = UITableViewCellSeparatorStyleNone; // return the length of the object array return _ msgFrames. count;} // generate a custom cell and pass the cellFrame to it. After the cell is set, tableView (UITableViewCell *) tableView :( UITableView *) tableView cellForRowAtIndexPath :( NSIndexPath *) is returned *) indexPath {// 1, get BeyondCell * cell = [tableView dequeueReusableCellWithIdentifier: [BeyondCell cellID] from the pool; // 2, when no result is obtained, create a pure WeiboCell if (cell = nil) {cell = [[BeyondCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: [BeyondCell cellID];} // 3, set the unique data BeyondCellFrame * frame = [_ msgFrames objectAtIndex: indexPath. row]; cell = [cell cellWithCellFrame: frame]; return cell;} // The cellFrame object array contains the row Height of each row, which has been calculated internally-(CGFloat) tableView :( UITableView *) tableView heightForRowAtIndexPath :( NSIndexPath *) indexPath {// cellFrame contains the Msg data model object and all frames calculated based on the data model, and the largest Y is the Row Height BeyondCellFrame * frame = [_ msgFrames objectAtIndex: indexPath. row]; return frame. maxY;} // restore the full screen view and exit the keyboard-(void) exitKeyboard {[UIView animateWithDuration: 0.2 animations: ^ {self. view. frame = CGRectMake (0, 0, self. view. frame. size. width, [[UIScreen mainScreen] bounds]. size. height);} completion: ^ (BOOL finished) {}]; [_ chatInput resignFirstResponder];} // scroll to the last row of the table-(void) scrollToLastCell; {if (_ msgFrames. count> 1) {[self. chatTableView scrollToRowAtIndexPath: [NSIndexPath indexPathForRow: _ msgFrames. count-1 inSection: 0] atScrollPosition: UITableViewScrollPositionBottom animated: YES] ;}}
Why scatter a ring on the chat interface?
This seems to be a version issue or related to festivals. During the Spring Festival, when "financial resources are widely used", money bags will slowly fall in the background; if you press "go home ", there will be a small train in the background.
I have never met a ring. It may be a chat with words like "love.
How does Java implement the layout of a bubble-style interface like Android/IOS text message interface chat QQ space reply?
In fact, there are two la S, the Avatar inside, the android: id of the dialog box control is the same, and then getview () in the adapter selects different loads based on the user's judgment. The code is similar
If (judgement ){
View = LayoutInflater. from (activity). inflate (
R. layout. left, null); // left layout
} Else {
View = LayoutInflater. from (activity). inflate (
R. layout. right, null); // layout on the right
}
ImageView avatar = (ImageView) view. findViewById (); // avatar
TextView msg = (TextView) view. findViewById (R. id.); // dialog box