ios7 uitableviewcell image left offset - ios

In iOS 6 and earlier a uitableviewcell's imageView was positioned all the way over to the left with a 0 offset. In iOS 7 though this has been changed and there is now a 15 point space now. I would like to position the imageView like it is in iOS 6. I'm already subclassing the uitableviewcell with AKHighlightableAttributedCell to deal with attributed text not being highlighted. So based on some searching I added:
- (void) layoutSubviews
{
[super layoutSubviews];
// Makes imageView get placed in the corner
self.imageView.frame = CGRectMake( 0, 0, 80, 80 );
}
The issue is everything else still doesn't get repositioned and so I'm thinking there must be a better way to do this. I'd read some people mentioning using a negative offset to move everything over but I wasn't sure how this would work with constraints as it needs to scale properly for each orientation. Is there an easier solution to this that I'm missing? Thank you.

It appears I was doing it the correct way. The missing piece regarding the divider between fields was setting the inset on iOS 7. You can do this in the viewdidload or viewwillload and set self.tableView.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0);
You will need to add a check if running iOS 7 or newer as this is a new property I believe. A better option might be setting it in the storyboard by selecting the table view and then setting separator insets from default to custom.
Here is the layoutSubviews method that repositions imageView and textLabel. If you have a description add that as well.
- (void) layoutSubviews
{
[super layoutSubviews];
// Makes imageView get placed in the corner
self.imageView.frame = CGRectMake( 0, 0, 80, 80 );
// Get textlabel frame
//self.textLabel.backgroundColor = [UIColor blackColor];
CGRect textlabelFrame = self.textLabel.frame;
// Figure out new width
textlabelFrame.size.width = textlabelFrame.size.width + textlabelFrame.origin.x - 90;
// Change origin to what we want
textlabelFrame.origin.x = 90;
// Assign the the new frame to textLabel
self.textLabel.frame = textlabelFrame;
}

Related

Access the UIImageView of the background image of a UIButton

I have a UIButton, and I would like to access the UIImageView of its background image so that I can make the image circular. I know that I can affect the image itself but I would prefer to do this more elegantly. I also know that I can use the button.currentBackgroundImage property to get the UIImage in the background, but I want the view itself. Once I have the view I intend to use this code:
buttonImageView.layer.cornerRadius = buttonImageView.frame.size.width / 2;
buttonImageView.clipsToBounds = YES;
How can I access the buttonImageView?
EDIT:
Due to #vhristoskov's suggestions, I tried cropping the button itself with this code:
self.button.layer.cornerRadius = self.button.frame.size.width/2;
self.button.clipsToBounds = YES;
And it made this shape:
After debugging I found that frame.size.width was 46, when it should have been 100. So I tried this code instead:
self.button.layer.cornerRadius = self.button.currentBackgroundImage.size.width/2;
self.button.clipsToBounds = YES;
And that produced this shape:
And this time, the cornerRadius was being set to 65. So it actually seems like my problem is that I don't have the correct width at the moment. Which property should I access to get the correct number?
Well as I guessed and as you've already found - the problem is in the button size. To be sure that your button's size at runtime is what you expected to be - review your constraints. In the example below the button has vertical and horizontal central alignment and fixed width and height.
Constraints:
To have perfectly circular button you should have button.width == button.height. If this condition is met your code should work like a charm:
self.button.layer.cornerRadius = CGRectGetWidth(self.button.frame) / 2;
self.button.clipsToBounds = YES;
Assuming that you called something like:
[self.myButton setBackgroundImage:[UIImage imageNamed:#"image"] forState:UIControlStateNormal];
in viewDidLoad or earlier, you can then call the following in viewDidAppear:
if (self.myButton.subviews.count > 0 && [self.myButton.subviews[0] isKindOfClass:[UIImageView class]]) {
UIImageView *imageView = self.myButton.subviews[0];
imageView.layer.cornerRadius = imageView.frame.size.width / 2;
imageView.clipsToBounds = YES;
}
but it is not more elegant as the subview ordering is an implementation detail of UIButton and may change at any time.

UIButton's text is not centered

Hi I have an simple application where I am supposed to change the frame of a UIButton based on its super view and based on its frame the title size should get change.
I am using Autolayout to change the frame of that UIButton. But not getting any idea how to change the font size of that UIButton.
Here is the code I have tried so far.
1. [self.cButton sizeToFit] ;
2. [self.cButton.titleLabel sizeToFit] ;
3. self.cButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter ;
4. self.cButton.titleLabel.adjustsFontSizeToFitWidth = YES;
5. self.cButton.titleLabel.textAlignment = NSTextAlignmentCenter ;
6. self.cButton.contentEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
Like I have tried many things.
Can anyone tell me if I am missing something here and I am doing something wrong.
I was having this issue and it turned out that I was overriding layoutSubviews and had forgotten to call [super layoutSubviews].

Add left/right horizontal padding to UILabel

I need to create a UILabel with a background color, and I'd like to add some left/right leading/trailing horizontal padding.
But every solution I've found seems like a nasty hack.
What is the 'standard' way to achieve this from iOS 5 forward?
A screenshot to illustrate my scenario:
For a full list of available solutions, see this answer: UILabel text margin
Try subclassing UILabel, like #Tommy Herbert suggests in the answer to [this question][1]. Copied and pasted for your convenience:
I solved this by subclassing UILabel and overriding drawTextInRect: like this:
- (void)drawTextInRect:(CGRect)rect {
UIEdgeInsets insets = {0, 5, 0, 5};
[super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}
The most important part is that you must override both intrinsicContentSize() and drawTextInRect() in order to account for AutoLayout:
var contentInset: UIEdgeInsets = .zero {
didSet {
setNeedsDisplay()
}
}
override public var intrinsicContentSize: CGSize {
let size = super.intrinsicContentSize
return CGSize(width: size.width + contentInset.left + contentInset.right, height: size.height + contentInset.top + contentInset.bottom)
}
override public func drawText(in rect: CGRect) {
super.drawText(in: UIEdgeInsetsInsetRect(rect, contentInset))
}
add a space character too the string. that's poor man's padding :)
OR
I would go with a custom background view but if you don't want that, the space is the only other easy options I see...
OR write a custom label. render the text via coretext
#define PADDING 5
#interface MyLabel : UILabel
#end
#implementation MyLabel
- (void)drawTextInRect:(CGRect)rect {
UIEdgeInsets insets = UIEdgeInsetsMake(0, PADDING, 0, PADDING);
CGRect rect = UIEdgeInsetsInsetRect(rect, insets);
return [super drawTextInRect:rect];
}
- (CGRect)textRectForBounds:(CGRect)bounds
limitedToNumberOfLines:(NSInteger)numberOfLines
{
CGSize size = CGSizeMake(999, 999);
CGRect rect = [self.attributedText
boundingRectWithSize:size
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
return CGRectInset(rect, -PADDING, 0);
}
#end
UIView* bg = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width, 70)];
bg.backgroundColor = [UIColor blackColor];
UILabel* yourLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, y, yourWidth, yourHeight)];
[bg addSubview:yourLabel];
[self addSubview:bg];
Sometimes it's convenient to use UNICODE partial spaces to achieve alignment while prototyping. This can be handy in prototyping, proof-of-concept, or just to defer implementation of graphics algorithms.
If you use UNICODE spaces for convenience, be aware that at least one of the UNICODE spaces has a size based on the font it is displayed from, specifically the actual space character itself (U+0020, ASCII 32)
If you're using the default iOS system font in a UILabel, the default System font characteristics could change in a subsequent iOS release and suddenly introduce an unwanted misalignment by changing your app's precise spacing. This can and does happen, for example the "San Francisco" font replaced a previous iOS system font in an iOS release.
UNICODE easy to specify in Swift, for example:
let six_per_em_space = "\u{2006}"
Alternatively, cut/paste the space from an HTML page directly into the UILabel's text field in Interface Builder.
Note: Attached pic is a screenshot, not HTML, so visit the linked page if you want to cut/paste the space.
I had a couple of issues with the answers here, such as when you added in the padding, the width of the content was overflowing the box and that I wanted some corner radius. I solved this using the following subclass of UILabel:
#import "MyLabel.h"
#define PADDING 8.0
#define CORNER_RADIUS 4.0
#implementation MyLabel
- (void)drawRect:(CGRect)rect {
self.layer.masksToBounds = YES;
self.layer.cornerRadius = CORNER_RADIUS;
UIEdgeInsets insets = {0, PADDING, 0, PADDING};
return [super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}
- (CGSize) intrinsicContentSize {
CGSize intrinsicSuperViewContentSize = [super intrinsicContentSize] ;
intrinsicSuperViewContentSize.width += PADDING * 2 ;
return intrinsicSuperViewContentSize ;
}
#end
Hope that's helpful to someone! Note that if you wanted padding on the top and bottom, you would need to change this lines:
UIEdgeInsets insets = {0, PADDING, 0, PADDING};
To this:
UIEdgeInsets insets = {PADDING, PADDING, PADDING, PADDING};
And add this line underneath the similar one for width:
intrinsicSuperViewContentSize.height += PADDING * 2 ;
Swift 5
Create below class file and set it to your label as custom class name through storyboard. That's it.
class PaddingLabel: UILabel {
override func drawText(in rect: CGRect) {
let insets = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 0)//CGRect.inset(by:)
super.drawText(in: rect.inset(by: insets))
}
}
If you want to add padding to UILabel but not want to subclass it you can put your label in a UIView and give paddings with autolayout like:
Result:
One thing I did to overcome this issue was to use a UIButton instead of a UILabel. Then in the Attributes Inspector of the Interface Builder, I used the Edge for the Title as the padding.
If you do not attach the button to an action, when clicked it will not get selected but it will still show the highlight.
You can also do this programmatically with the following code:
UIButton *mButton = [[UIButton alloc] init];
[mButton setTitleEdgeInsets:UIEdgeInsetsMake(top, left, bottom, right)];
[mButton setTitle:#"Title" forState:UIControlStateNormal];
[self.view addSubView:mButton];
This approach gives the same result but sometimes it did not work for some reason that I did not investigate since if possible I use the Interface Builder.
This is still a workaround but it works quite nicely if the highlight doesn't bother you. Hope it is useful
Subclass UILabel and override drawTextInRect: like this:
- (void)drawTextInRect:(CGRect)rect
{
UIEdgeInsets insets = {0, 10, 0, 0};
return [super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}
Installation with CocoaPods
pod 'PaddingLabel', '1.2'
Change your UILabel class to PaddingLabel ###
Specify padding
If you need a more specific text alignment than what adding spaces to the left of the text provides, you can always add a second blank label of exactly how much of an indent you need.
I've got buttons with text aligned left with an indent of 10px and needed a label below to look in line.
It gave the label with text and left alignment and put it at x=10 and then made a small second label of the same background color with a width = 10, and lined it up next to the real label.
Minimal code and looks good.
Just makes AutoLayout a little more of a hassle to get everything working.

ios create 'readmore'. Let superview be dependent of subview

gaaah designing in ios gives me headache!!
So please, help me out and maby explain to me how one should think trying to come up with the solution.
I have:
As you can see the UITextField has its frame being set in storyboard to be smaller than its actual content.
Everything above the prototypecell is within a UIView that is set to be tableHeader programatically.
I want to:
Press the read more btn so that the UITextField get its actual size. No problem, I can do that with getting the contentSize programmatically. It works but it ofc overflows the tableHeader
So I thought, good. Then all I have to do is set the tableHeader to be the size of the 'new' calculated height of UITextField + height of the 2 UIImageViews.
But nope. it only resizes to the existing height set in storyboard insted. In other word, it does one or the other.
And using autolayout it totally breaks but not giving me any errors about constraints.
This seems so easy wich makes me feel so stupid haha
this is what I have i code
- (IBAction)toggleReadMore:(id)sender{
_toggleReadMoreBtn.hidden = YES;
CGRect textFrame = _cityDescription.frame;
_cityDescription.frame = textFrame;
CGRect tableHeaderViewFrame = CGRectMake(0, 0, self.tableView.tableHeaderView.frame.size.width, _cityDescription.contentSize.height + 218.0f ); //textFrame.size.height
self.tableView.tableHeaderView.frame = tableHeaderViewFrame;
textFrame.size.height = _cityDescription.contentSize.height;
[self.tableView setTableHeaderView:self.viewForTableHeader];
please, guide me how to think
- (IBAction)readMoreBtnClicked:(UIButton *)sender
{
NSLog(#"Read more Btn Clicked");
NSString *stringToBeDisplayed = #"Any Text Here";
CGSize textSize=[stringToBeDisplayed sizeWithFont:[UIFont systemFontOfSize:30]
constrainedToSize:CGSizeMake(270, 500)
lineBreakMode:NSLineBreakByWordWrapping];
NSLog(#"textSize = %#",NSStringFromCGSize(textSize));
[self.textView setFrame:CGRectMake(self.textView.frame.origin.x,self.textView.frame.origin.y, textSize.width, textSize.height)];
NSLog(#"self.textView.frame = %#",NSStringFromCGRect(self.textView.frame));
[self.textView setText:stringToBeDisplayed];
[self.headerView setFrame:CGRectMake(self.headerView.frame.origin.x,self.headerView.frame.origin.y, 320, dynamicHeightCalculatedAfterTextSize)];
[self.tableView reloadData];
}

Applying transform to UITextView - prevent content resizing

When I apply a rotation transform to a UITextView and then click inside to begin editing, it appears that the content size is automatically being made wider. The new width of the content view is the width of the rotated view's bounding box. For example, given a text box of width 500 and height 400, and rotated by 30 degrees, the new content width would be:
(500 * cos(30)) + (400 * sin(30)) = 633
Or graphically:
Interestingly, if you are already editing the text view and THEN apply the transform, then it appears that no modification is made to the content size. So it appears that sometime around the start of text editing, the text view looks at its frame property and adjusts the content size based on the frame width. I imagine the solution to this is to tell it to use the bounds property instead, however I don't know where to do this, as I'm not sure exactly where the text view is deciding to modify the content size.
I have googled but can't seem to find any references to using transformed UITextViews. Does anybody have any ideas about this?
EDIT (button action from test project):
- (IBAction)rotateButtonTapped:(id)sender {
if (CGAffineTransformIsIdentity(self.textView.transform)) {
self.textView.transform = CGAffineTransformMakeRotation(30.0 * M_PI / 180.0);
}
else {
self.textView.transform = CGAffineTransformIdentity;
}
NSLog(#"contentsize: %.0f, %.0f", textView.contentSize.width, textView.contentSize.height);
}
I was also stuck with this problem.
The only solution which I found was to create an instance of UIView and add the UITextView as a subview. Then you can rotate the instance of UIView and UITextView will work just fine.
UITextView *myTextView = [[UITextView alloc] init];
[myTextView setFrame:CGRectMake(0, 0, 100, 100)];
UIView *myRotateView = [[UIView alloc] init];
[myRotateView setFrame:CGRectMake(20, 20, 100, 100)];
[myRotateView setBackgroundColor:[UIColor clearColor]];
[myRotateView addSubview:myTextView];
myRotateView.transform = CGAffineTransformMakeRotation(0.8);
[[self view] addSubview:myRotateView];
Have you tried applying the rotation by doing a layer transform rather than a transform on the view?
#import <QuartzCore/QuartzCore.h>
mytextField.layer.transform = CATransform3DMakeRotation (angle, 0, 0, 1);
This might be enough to trick whatever broken logic exists inside the core text field code.

Resources