I'm creating a chat view, and currently trying to design the cell based on autolayout. My main problem is that, there is an image view and just below there's a label for chat text which go multiple line, and if there's no image only text should display and if there's no text only image should display. Image should be 60% of cell width and 40% in height. Below is my cell design, I've added background color to each view for clarity.
But by giving proportional height, I'm not able to set its height programatically. So currently I tried giving a fixed height for image view and manage it programmatically in the code. Below is my code where I adjust imageview and chat text height.
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell : ChatViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("chatCell", forIndexPath: indexPath) as! ChatViewCell
cell.fullNameLabel.text = tempArray[indexPath.row].0
cell.fullDateLabel.text = tempArray[indexPath.row].1
cell.chatSentStatusLabel.text = tempArray[indexPath.row].2
cell.chatTimeLabel.text = tempArray[indexPath.row].3
let chatBubbleData1 = tempArray[indexPath.row].4
if (chatBubbleData1.image == nil)
{
cell.chatImageHeightConstraint.constant = 0
}
else
{
cell.chatImageHeightConstraint.constant = 150
}
cell.chatTextContainerView?.layer.cornerRadius = 10.0
cell.chatTextContainerView?.layer.masksToBounds = true
cell.chatBubbleView?.layer.cornerRadius = 10.0
cell.chatBubbleView?.layer.masksToBounds = true
cell.chatImageView.image = chatBubbleData1.image
cell.userPointerView.colors = (0.0, 0.0, 1.0, 1.0)
cell.userPointerView.backgroundColor = .clearColor()
cell.chatImageView?.layer.cornerRadius = 10.0
cell.chatImageView?.layer.masksToBounds = true
if (chatBubbleData1.text?.characters.count > 0)
{
cell.chatText?.numberOfLines = 0 // Making it multiline
cell.chatText?.text = chatBubbleData1.text
cell.chatText?.sizeToFit()
cell.chatTextContainerHeightConstraint.constant = CGRectGetHeight(cell.chatText.frame)+20
}
else
{
cell.chatText?.text = ""
cell.chatTextContainerHeightConstraint.constant = 0
}
cell.setNeedsDisplay()
return cell
}
This is the result now
The multiline doesn't seems to work. I'm not sure if I'm following the best approach. If anybody has any solutions or any suggestions, please let me know.
PS: Please don't suggest any third parties like JSQMessagesViewController. I'm already aware of those. I'm doing this as part of learning.
You just put a bottom constraint for all the components in the cell.
and call delegate methods of table view (EstimatedRowHight and HightForRow).
it will return the exact hight of the cell.and you can also customise whether it display or not..
remember that text labels should had the bottom constrain property with respect the other components.Hope you get what i meant.
If UIImageView and UILabel will never be shown both in the same cell, you could remove all constraints relations between them and make each in relation only with superview. Then with some code you can manage UIImageView or UILabel visibility and calculate proper height for each cell in CollectionView/TableView delegate method.
I think problem is in your line
cell.chatTextContainerHeightConstraint.constant = CGRectGetHeight(cell.chatText.frame)+20
Instead of getting chatText.frame height your should manually calculate the height. I used following function to calculate cell height:
+ (CGFloat)calculateCellHeightForText:(NSString *)text cellWidth:(CGFloat)cellWidth {
CGFloat maxWidth = cellWidth;
CGSize textSize = [text boundingRectWithSize:CGSizeMake(maxWidth, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName : [UIFont fontWithName:#"CALIBRI" size:17]}
context:nil].size;
return textSize.height;
}
Related
Hey I'm trying display a set of "tags" in a view controller using collection view cells but I'm having trouble finding a way to make them be able to dynamically resizable depending on the length of the string.
Right now the individual cells are statically sized so whenever a String that populates the cell with characters exceeding the size of the cell, it goes into the second line. I want it so that the cell can change length depending on the length of the String. So if it's the tag "#Vegan", it will automatically resize so that the tag isn't that big. Likewise, if it's a longer string like "#LaptopFriendly", it will become horizontally longer to accommodate the string and not use the second line. The vertical length can stay fixed. Thank you!
UPDATE (interface builder settings when I run into errors using Rob's code):
Simulator screenshot:
You need unambiguous constraints between your label and the cell (e.g. leading, trailing, top, and bottom constraints):
Then you can use UICollectionViewFlowLayoutAutomaticSize for the itemSize of your collectionViewLayout. Don't forget to set estimatedItemSize, too, which enables automatically resizing cells:
override func viewDidLoad() {
super.viewDidLoad()
let layout = collectionView?.collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = UICollectionViewFlowLayoutAutomaticSize
layout.estimatedItemSize = CGSize(width: 100, height: 40)
}
That yields:
You can calculate the lengths of the texts ahead of time, feed them into an array accessible by your collectionView and use them them to construct the size of the cell.
//Create vars
NSArray * texts = #[#"Short",#"Something Long",#"Something Really Long"];
NSMutableArray * lengths = [NSMutableArray new];
float padding = 30.0f;
//Create dummy label
UILabel * label = [UILabel new];
label.frame = CGRectZero;
label.font = [UIFont systemFontOfSize:20.0f weight:UIFontWeightBold];
//loop through the texts
for (NSString * string in texts){
//set text
label.text = string;
//calculate length + add padding
float length = [label.text boundingRectWithSize:label.frame.size
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:label.font}
context:nil].size.width + padding;
//save value into array as NSNumber
[lengths addObject:#(length)];
}
//drop label
label = nil;
Create the size of the cell using some code like this:
return CGSizeMake(lengths[indexPath.row], 100.0f);
I have a table view, and within that table view I have a cell that contains text and it can also contain an image if the user chooses to. However, I'm trying to make the cell smaller if the user chooses not to include an image. When I do this, its actually stretching my image to make the cell even larger. Does anyone know why this is happening? My code is:
// get main queue to this block of code to communicate back
DispatchQueue.main.async {
cell.textLbl.sizeToFit()
// if no image on the cell
if image.size.width == 0 && image.size.height == 0 {
// move left textLabel if no picture
cell.textLbl.frame.origin.x = self.view.frame.size.width / 50
cell.textLbl.frame.size.width = self.view.frame.size.width - self.view.frame.size.width / 8
tableView.estimatedRowHeight = 120
tableView.rowHeight = UITableViewAutomaticDimension
cell.updateConstraintsIfNeeded()
}
}
I have to create a screen displaying various activity in the user's account such as picture like, uploading images and videos. Just like this-
I thought of using custom TableViewCell for which I need to make two different custom cells in a same table view. I had no problem while making a custom cell for the 2nd activity but am facing problem for the first activity as I have to add an UIImageView for the picture and video. The height of view is not increasing along with UIImage added. Can anyone tell me how can I make two different shapes of custom cells or should I use some other way to show the activities?
You should calculate cell height for different cells. Here is how I do with this:
+(CGFloat)heightForBubbleWithObject:(MessageModel *)object
{
CGSize retSize = object.size;
if (retSize.width == 0 || retSize.height == 0) {
retSize.width = MAX_SIZE;
retSize.height = MAX_SIZE;
}else if (retSize.width > retSize.height) {
CGFloat height = MAX_SIZE / retSize.width * retSize.height;
retSize.height = height;
retSize.width = MAX_SIZE;
}else {
CGFloat width = MAX_SIZE / retSize.height * retSize.width;
retSize.width = width;
retSize.height = MAX_SIZE;
}
return 2 * BUBBLE_VIEW_PADDING + retSize.height;
}
in ios 8 and above put this magical lines and make sure the constraints are properly given
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44.0;
there is a wonderful answer about this please refer it for the details Using Auto Layout in UITableView for dynamic cell layouts & variable row heights
I have UILabel in my Cell Subclass which is suppose to hold a title. The size of the title can be various lengths and therefor I need to resize the UILabel to fit the text and to prevent that the text is not to long I also need to be able to set maxHeight. The width should be the same. How can I create such code in swift in a tableViewCell subclass?
So far I have this in awakeFromNib
theTitleLabel?.font = UIFont(name: "HelveticaNeue", size: 13)
theTitleLabel?.textColor = UIColor(rgba: "#4F4E4F")
theTitleLabel?.numberOfLines = 0
theTitleLabel?.lineBreakMode = NSLineBreakMode.ByTruncatingTail
CGSize maximumLabelSize = CGSizeMake(MAX_WIDTH, MAX_HEIGHT);
CGSize expectedSize = [lbl sizeThatFits:maximumLabelSize];
CGSize s = CGSizeMake(STATIC_WIDTH, expectedSize.height);
yourLabel.frame = CGRectMake(yourLabel.frame.origin.x, nameLbl.frame.origin.y, s.width, s.height);
The easiest way to do that is using autolayout constraints. You are using awakeFromNib, so I assume you have that cell somewhere in your Interface Builder (xib or storyboard file).
If you can avoid it, never set up your views in your code. It's far easier to do it in the Interface Builder.
Find your label and set up its attributes (font, color, line break mode etc.) in the Interface Builder.
Add a width constraint (or constraints to left and right margins, depending on what you want).
Add a height constraint, change its relation from = (equals) to < (less than).
You are done, no code is needed.
Swift 2 version, from Zigglzworth's answer :
let maximumLabelSize = CGSizeMake(maxWidth, maxHeight);
let expectedSize = theLabel.sizeThatFits(maximumLabelSize)
theLabel.frame = CGRectMake(theLabel.frame.origin.x, theLabel.frame.origin.y, expectedSize.width, expectedSize.height)
let lblMassage = UILable()
lblMassage.text ="Resizing the height of UILabel to fit text.................."
lblMassage.numberOfLines = 0
lblMassage.lineBreakMode = NSLineBreakMode.byTruncatingTail
lblMassage.preferredMaxLayoutWidth = 190
lblMassage.sizeToFit()
I need to determine cell height and place in this cell text which has images inside, for example:
some text there
image
sometext there
image
... ect.
How to implement this? Suggest pls.
Thnx.
And I want divide my paragraphs in individual cells like this:
Because the content is dynamic, one way to do it is to calculate the height of the cell ahead of heightForRowAtIndexPath (or equivalent method) being called and store those values in an array.
-(void)calculateCellHeights:(NSArray *)contentArray
{
self.heightArray = [[NSMutableArray alloc] initWithCapacity: contentArray.count];
for( MyCellContent *content in contentArray )
{
CGFloat totalHeight = 0;
totalHeight += content.image.size.height;
CGSize titleSize = [content.title sizeWithFont:self.myTitleFont];
totalHeight += titleSize.height;
CGSize textContentSize = [content.textContent sizeWithFont:self.myTextContentFont];
totalHeight += textContentSize.height;
[self.heightArray addObject:#(totalHeight)];
}
}
-(CGFloat) tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*) indexPath
{
return self.heightArray[[indexPath.row floatValue]];
}
This is assuming only one section and the use of regular text strings instead of NSAttributedStrings, and doesn't handle padding between interface elements but you get the picture.