Okay I'm not really sure how to explain this. But here goes. I have a UITextView with content that is dynamically populated. I have worked out how to resize automatically depending on the amount of text within it. It could be one line it could be 10.
Now I have a UIView that I have customised which has a rounded Rect code below.
The .h file
#interface roundedEdges : UIView
{
}
The .m file
- (void) drawRect:(CGRect)rect
{
CGRect frame = self.bounds;
UIBezierPath* path = [UIBezierPath bezierPathWithRoundedRect:frame cornerRadius:8.0];
[[UIColor whiteColor] setFill];
[path fill];
}
What I would like to do is make the rounded UIView to be constrained to the height of the UITextView.
Currently the UITextView is sitting on top of the UIView. This way it provides a rounded box effect.
IS there a way to resize the above code (UIView) to be constrained depending on how much text is coming into the UITextView?
If so how?
Thanks in advance!
Jeremy
To dynamic change in height or width of textView or label depends upon the text size this code is working fine........
I have used this code for both UITextView and UILabel
CGFloat heightTXT = [[txtView text] sizeWithFont:txtView.font constrainedToSize:CGSizeMake(txtView.frame.size.width,INFINITY) lineBreakMode:UILineBreakModeWordWrap].height;
[txtView setFrame:CGRectMake(txtView.frame.origin.x,txtView.frame.origin.y,txtView.frame.size.width,heightTXT];
Related
It's been EXTREMELY frustrating trying to vertically align UILabel text to the top. I've search google for hours, and everything I've found has been deprecated.
What is the best way to do this? I've used numberOfLines=0 & sizeToFit... but this doesn't work upon initial loading of the UILabel on a custom TVCell.
Does anyone have a code snippet that works for align UILabel text to the top on a custom cell?
Calculate height of text and set UILabel frame again.
try this-
CGSize maxSize = CGSizeMake(label.frame.size.width, label.frame.size.height);
CGSize labelSize = [label.text boundingRectWithSize:maxSize
options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:label.font}
context:nil].size;
[label setFrame:CGRectMake(label.frame.origin.x, label.frame.origin.y, label.frame.size.width, labelSize.height)];
I'm trying to resize a UITextView to the size the text within it.
The problem is that Im using a custom font and it the text doesnt fit within the UITextView.
NSString *textToFit = #"pretty long text";
UIFont *customFont = [UIFont fontWithName:#"Museo-100" size:15];
CGSize sizeText = [textToFit sizeWithFont:customFont constrainedToSize:CGSizeMake(textFrame.size.width, 1000)];
Where textFrame is the frame of the UITextView I want to adjust its height.
Im trying different fonts and also different files of the same font and still it never adjusts its height to the height that the text fills.
I've been searching and I dont find a solution. I've tried a workaround using a UILabel and the method textRectForBounds, but still no success, something on this lines.
UILabel *auxLabel = [[UILabel alloc]init];
auxLabel.numberOfLines = 0;
auxLabel.font = [UIFont fontWithName:#"Museo-100" size:15];
auxLabel.text = //THE TEXT I WANT TO FIT IN
CGRect textSize = CGRectMake(0.0, 0.0, textDescription.frame.size.width, FLT_MAX);
CGRect frame = [auxLabel textRectForBounds:textSize limitedToNumberOfLines:0];
I think
UIView : sizeToFit
Should solve your problem.
sizeToFit Resizes and moves the receiver view so it just encloses its
subviews.
Discussion: Call this method when you want to resize the current view so that it uses the most appropriate amount of space.
Specific UIKit views resize themselves according to their own internal
needs. In some cases, if a view does not have a superview, it may size
itself to the screen bounds. Thus, if you want a given view to size
itself to its parent view, you should add it to the parent view before
calling this method.
https://developer.apple.com/library/ios/documentation/uikit/reference/uiview_class/uiview/uiview.html#//apple_ref/occ/instm/UIView/sizeToFit
This is what I want to do:
As you can see i want to:
Decrease the width of the tableView (I want more margin on the sides than the grouped tableView provides)
Corner radius (bigger radius than the default for grouped tableView)
Drop shadow around the table and a special shadow beneath the last cell
You can do this by "drawing" the backgroundView of the cells yourself.
I'd recommend getting an image to use as the background (if the cells are all the same height).
You'll need three images.
A "top" image with the top corners rounded.
A "bottom" image with the bottom corners rounded and the drop shadow how you want it.
And a "middle" image with no rounded corners.
If the cells don't have any texture or gradient within them then you can use stretchable images to reduce the memory footprint of them.
Then I would subclass the UITableViewCell and override the backgroundView to add a UIImageView. I'd also provide an accessor method to change the type (top, middle, bottom) of the cell.
Each cell can then have three placeHolder properties of a UIImage (topImage, bottomImage and middleImage). When the type of the cell is changed these can be accessed (use lazy instantiation to make sure they are only loaded once and only when needed) and then set the backgroundVIew image to be the required image.
Something like this...
In the UITableViewCell subclass define a type enum...
typedef enum {
CellTypeTop,
CellTypeMiddle,
CellTypeBottom
} cellType;
Then a property for the type...
#property (nonatomic) cellType cellType
Then in the .m ...
Define some more internal properties...
#property UIImageView *bgImageView;
#property UIImage *topImage;
#property UIImage *middleImage;
#property UIImage *bottomImage;
Then add the imageView (only once)...
- (void)awakeFromNib //or in the init depends how you are initialising the cell
{
self.bgImageView = [[UIImageView alloc] initWithFrame:blah];
[self.backgroundView addSubView:self.bgImageView];
}
Now when the type is changed...
- (void)setCellType:(cellType)cellType
{
switch(cellType) {
case CellTypeTop:
self.bgImageView.image = self.topImage;
break;
case CellTypeMiddle:
self.bgImageView.image = self.middleImage;
break;
case CellTypeBottom:
self.bgImageView.image = self.bottomImage;
break;
}
}
Finally a lazy instantiation of the images...
- (UIImage *)topImage
{
if (_topImage == nil) {
_topImage = [UIImage imageNamed:#"topImage"];
//alternatively...
_topImage = [[UIImage imageNamed:#"topImage"] stretchableImageWith...
}
return _topImage;
}
Now repeat these for the other images.
This will be more performant (by a long way) than using a CALayer alternative and, especially if using the stretchable images, will have a very small memory footprint.
Several other users have said that this is not good for performance, memory, design, whatever, but it really is the best way to get the best performance for UserExperience than CALayers. Yes, it will use more memory than CALayers but only marginally and it will get to a limit as there are only a few dequeueable cells created.
A couple of links explaining performance issues when using CALayers in scrollViews...
http://www.quora.com/iOS-Development/What-is-the-best-way-to-optimize-the-performance-of-a-non-paging-but-view-recycling-UIScrollView-involving-loading-potentially-caching-and-displaying-bundled-images
Bad performance on scroll view loaded with 3 view controllers, drawn with CALayer
::EDIT:: Edit to answer Michael's question.
In the storyboard create a UITableViewController (rename the Class in the inspector so that it matches your subclass UITableViewController - I'll call it MyTableViewController).
Create a subclass of UITableViewCell (I'll call mine MyTableViewCell) in the code (i.e. the .h and .m).
Add the above code to do with properties and types and imageViews to your MyTableViewCell.h file.
In the storyboard select the cell in the TableViewController and rename the class to MyTableViewCell. Also set the reuse identifier on it.
In the MyTableViewController code you will need a function like this...
-(UITableViewCell*)tableView:(UITabelView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
MyTableViewCell *cell = [tableView dequeueCellWithReuseIdentifier:#"Cell"];
cell.cellType = CellTypeTop; //or whichever it needs to be
cell.textLabel.text = #"Blah";
return cell;
}
Oh, another thing, in the storyboard you will be able to layout your cell how you want it to look and link up all the labels and imageviews etc... Make sure you add IBOutlet to the UIImageView so that you can link it up in the storyboard.
make sure you have #import <QuartzCore/QuartzCore.h> imported, then you can start accessing the layers of the UITableView like.
UITableView *yourTable = [[UITableView alloc] initWithStyle:UITableViewStyleGrouped];
[[yourTable layer] setCornerRadius:10.0f];
[[yourTable layer] setShadowColor:[[UIColor blackColor] CGColor]];
[[yourTable layer] setShadowOffset:CGSizeMake([CALayer ShadowOffSetWidthWithFloat:10.0f], [CALayer ShadowOffSetWidthWithFloat:10.0f])];
[[yourTable layer] setShadowOpacity:[CALayer ShadowOpacity:1]];
[[yourTable layer] setMasksToBounds:NO];
UIBezierPath *path = [UIBezierPAth bezierPathWithRect:yourTable.bounds];
[[yourTable layer] setShadowPath:[path CGPath]];
This will add shadow affect to your table view with the shadow not masked to the bounds of the UITableView, at setCornerRadius you can set the corners of the table to whatever you want. You can also set the frame of the UITableView by doing
[yourTable setFrame:CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)];
EDIT
As another user has tried to point out that CALayer is very slow, this is not the case
CALayer was introduced to help performance issues around animation. Please read documentation. Loading an image straight in may seem like a good idea but in the long run will take up more memory. Please this question about memory allocation for images. As you can see it may seem faster, but it takes up 2.25 MByte of memory per image which after loading each image so many times your app will start to become slow.
I'm looking for a way to draw a fade effect on a table view (and outline view, but I think it will be the same) when the content is scrolled. Here is an example from the Fantastical app:
Also a video of a similar fade on QuickLook windows here.
To make this I tried subclassing the scrollview of a tableview with this code:
#define kFadeEffectHeight 15
#implementation FadingScrollView
- (void)drawRect: (NSRect)dirtyRect
{
[super drawRect: dirtyRect];
NSGradient* g = [[NSGradient alloc] initWithStartingColor: [NSColor blackColor] endingColor: [NSColor clearColor]];
NSRect topRect = self.bounds;
topRect.origin.y = self.bounds.size.height - kFadeEffectHeight;
topRect.size.height = kFadeEffectHeight;
NSRect botRect = self.bounds;
botRect.size.height = kFadeEffectHeight;
[NSGraphicsContext saveGraphicsState];
[[NSGraphicsContext currentContext] setCompositingOperation: NSCompositeDestinationAtop];
// Tried every compositing operation and none worked. Please specify wich one I should use if you do it this way
[g drawInRect: topRect angle: 90];
[g drawInRect: botRect angle: 270];
[NSGraphicsContext restoreGraphicsState];
}
...but this didn't fade anything, probably because this is called before the actual table view is drawn. I have no idea on how to do this :(
By the way, both the tableview and the outlineview I want to have this effect are view-based, and the app is 10.7 only.
In Mac OS X (as your question is tagged), there are several gotchas that make this difficult. This especially true on Lion with elastic scrolling.
I've (just today) put together what I think is a better approach than working on the table or outline views directly: a custom NSScrollView subclass, which keeps two "fade views" tiled in the correct place atop its clip view. JLNFadingScrollView can be configured with the desired fade height and color and is free/open source on Github. Please respect the license and enjoy. :-)
I want to sub-class a UIView and place four UILabels over top one another ; top label will be the MASK, 2nd label will be a normal label with text, the 3rd label is a label with solid background with no text. the bottom label will the same as the top 2nd label with a different color font. when i sent the width of the third label it will cover up the bottom label showing a partial view of the text. I want to have the 2nd text be one color while the uncoverd bottom label display another color font.
Is this possibe? If someone can explain how to mask in objective-C that will help too.
I trying to build a UIView that acts like a progress bar, as the bar fill to 60%, I want to top text to show in white font color, when the bottom text shows in a different color.
You could do it with two UILabels, one on the bottom, and one embedded in another view on top.
UILabel *bottomLabel = ...;
[self.view addSubview:bottomLabel];
UIView *topContainer = [[UIView alloc] initWithFrame:bottomLabel.frame];
topContainer.clipsToBounds = YES;
topContainer.opaque = NO;
topContainer.backgroundColor = [UIColor clearColor];
UILabel *topLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, bottomLabel.frame.size.width, bottomLabel.frame.size.height)];
topLabel.text = bottomLabel.text;
topLabel.opaque = NO;
topLabel.backgroundColor = [UIColor clearColor];
[topContainer addSubview:topLabel];
[self.view addSubview:topContainer];
Then, when you want to change the progress, you'd set the width of topContainer. This should clip topLabel.
Rather than using four UILabels, why not subclass UILabel and draw it yourself in the drawRect: method? It would look something like:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
// Set the mask
CGContextClipToMask(context, self.bounds, /* mask image */);
// Draw the text in a different font
[self.text drawInRect:rect withFont:/* alternate font */];
// Draw a solid background
CGContextSetRGBFillColor(context, ...);
CGContextFillRect(context, rect);
// Draw the text normally
[super drawRect:rect];
}
You could make the masking image and the alternate font properties of your subclass, for convenience.