Position image in UIButton for all states [duplicate] - iphone

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
UIButton: how to center an image and a text using imageEdgeInsets and titleEdgeInsets?
I'm customizing the placement of the image and label of my UIButton but it's only set on the initial state. What the hack, how do I ensure the positioning for all 4 button states?
This is the code I'm using. The poisoning works for the first state but gets reset on the other states.
CGRect imgRect = reviewsButton.imageView.frame;
imgRect.origin.x = 10;
imgRect.origin.y += 4;
reviewsButton.imageView.frame = imgRect;
CGRect lblrect = reviewsButton.titleLabel.frame;
lblrect.origin.x = 85;
reviewsButton.titleLabel.frame = lblrect;
[reviewsButton setBackgroundColor:[UIColor colorWithRed:0.192 green:0.198 blue:0.206 alpha:0.15]];

There are UIButton properties which have been made specially for this
#property(nonatomic) UIEdgeInsets contentEdgeInsets
#property(nonatomic) UIEdgeInsets imageEdgeInsets
#property(nonatomic) UIEdgeInsets titleEdgeInsets
Use this property to resize and reposition the effective drawing rectangle for the button image. You can specify a different value for each of the four insets (top, left, bottom, right). A positive value shrinks, or insets, that edge—moving it closer to the center of the button. A negative value expands, or outsets, that edge. Use the UIEdgeInsetsMake function to construct a value for this property. The default value is UIEdgeInsetsZero.

#jspooner Settings the button frame after you are finished altering the imageview frame and label frame might do the trick.

You should create your image and then apply it to the button states:
UIImage* reviewButtonImage = [UIImage initWithContentsOfFile:/*path*/];
[reviewButton setImage:reviewButtonImage forState:UIControlStateNormal|UIControlStateHighlighted|UIControlStateDisabled|UIControlStateSelected];

I was never able to get the desired layout to work with UIButton so I created a custom UIView and handled touches there.

Related

AutoLayout is not working after resized controls programmatically - iOS [duplicate]

This question already has answers here:
Can I use setFrame and autolayout on the same view?
(5 answers)
Closed 9 years ago.
I have been using AutoLayout feature. Everything works properly, however if I resize any controls programmatically, others subviews or controls are not arranging accordingly.
How do I update the constraint after resized any controls programmatically.
or
Will AutoLayout works after resized the control in code?
Edit:
Here I am resizing text view, based on string, but it is overlapping with below subviews.
- (void)textViewDidChange:(UITextView *)textView
{
if (textView == pupose_txt_view) {
CGSize maximumLabelSize = CGSizeMake(self.topic_text_view.frame.size.width,
FLT_MAX);
UILabel *label = [[UILabel alloc] initWithFrame:pupose_txt_view.frame];
CGSize expectedLabelSize = [pupose_txt_view.text sizeWithFont:pupose_txt_view.font
constrainedToSize:maximumLabelSize
lineBreakMode:label.lineBreakMode];
CGRect newFrame = pupose_txt_view.frame;
newFrame.size.height = expectedLabelSize.height;
pupose_txt_view.frame = newFrame;
}
}
You cannot use setFrame: to update the position or size of a view if you are using auto layout. Instead you have to update your constraints to set the new size so the layout system can update the positions of all the views.
To do this you create an outlet for the height constraint of your text size and set it's constant property whenever you want to change the height. You also could remove the constraints for your text view and create new ones, but updating the constants is the preferred way as it requires less code and is more efficient at runtime.

UIView positioning related questions (iOS)

I have a bunch of questions:
How do I position a UIView so that it is on the bottom of the view I am adding it to?
How can I add a subview to a view so that it is positioned in the corner of the superview with a small gap (Like if I want a 'x' cross sign for closing something)
Is their a utility class for easy UIView positioning (and rotation)?
Any references, open source tutorials etc. will be more then welcome!
(a) How do I position a UIView so that it is on the bottom of the view I am adding it to?
OK, let's say you want to position button as a subview at the bottom of view form, you calculate the origin.y of the subview button by subtracting button's height from the height of the form
CGRect buttonFrame = button.frame;
buttonFrame.origin.y = form.bounds.size.height - buttonFrame.size.height;
button.frame = buttonFrame;
[form addSubview:button];
You can change origin horizontal position as well. You want it on the bottom left of form?
buttonFrame.origin.x = 0;
Or on the right edge of form?
buttonFrame.origin.x = form.bounds.size.width - buttonFrame.size.width;
Or in the middle (horizontally) of form?
buttonFrame.origin.x = (form.bounds.size.width - buttonFrame.size.width) / 2;
or another way using CGRectGetMidX (found in CGGeometry utility methods):
buttonFrame.origin.x = CGRectGetMidX(form.bounds) - buttonFrame.size.width/2;
Autoresizing handles adjusting the frame when the parent view's size changes. But you still have to position it first.
int xOffset = 20;
int yOffset = 20;
CGRect BottomRight_NewFrame = CGRectMake((superview.frame.size.width - subview.frame.size.width-xOffset), (superview.frame.size.height - subview.frame.size.height-yOffset), subview.frame.size.width, subview.frame.size.height);
subview.frame = BottomFrame;
You can use the new Autolayout feature of iOS 6 or the old Struts & Springs in the Interface Builder to achieve this.
This tutorial explains both:
http://msmvps.com/blogs/kevinmcneish/archive/2012/12/10/tutorial-ios-6-auto-layout-versus-springs-and-struts.aspx
Or you can set the autoresizing mask programatically. It is explained pretty well here:
UIView autoresizingMask - Interface Builder to Code - Programmatically create struts and springs - Swift or Objective-C
It's easy enough to just set the frame, e.g. (untested code )
subview.frame = CGRectMake((superview.frame.origin.x - subview.frame.origin.size.width/2)-20, (superview.view.frame.origin.y - subview.frame.origin.size.height/2)-20, subview.view.frame.size.width, subview.view.frame.size.height);
if you'll be doing a lot of this then create a utility class or method.
Autolayout will help you position the views and maintain those positions if the size of the superview changes. If the superview isn't going to change, you don't really need to mess with constraints -- you can just set the position of the subview appropra
If you're adding view viewB to view viewA:
a) To position viewB so that it's bottom edge corresponds to the bottom edge of viewA:
viewB.frame.origin.y = viewA.bounds.size.height - viewB.bounds.size.height;
b) You don't say which corner, but it's just a matter of doing the math. For example, the upper right corner of viewA is at {viewA.bounds.size.x, 0} in viewA's coordinate system. If you want to put viewB there, set it's origin to:
{viewA.bounds.size.x-viewB.bounds.size.x, 0}
If you want to add a margin, you can add that to the computation:
int margin = 10;
{viewA.bounds.size.x-viewB.bounds.size.x-margin, margin}
d) Use NSLayoutConstraint to access the autolayout system's constraints programmatically. There's a nice visual format language, so that for your question (a) you could set the constraint for viewA to:
V:|-[viewB]-0-|
The V means that you're working in the vertical direction, |'s represent the edges (top and bottom, thanks to the V) of the superview (that's viewA), and the 0 means that the distance between viewB and the bottom of its superview should be 0.
You can setup constraints in iOS6 but if you want to work on older os's you need to position them manually. Math.

Is UILabel Inset effect Possible? [duplicate]

This question already has answers here:
UILabel text margin [duplicate]
(38 answers)
Closed 9 years ago.
I am giving border to UILabel with
Label.text = lbltext;
Label.layer.borderColor = [[UIColor grayColor] CGColor];
Label.layer.borderWidth = 2;
But There is no space between text and border.
so how can i set inset effect like UIButton in my Label?
Put the label in a container view and apply the border to the container.
You can subclass UILabel, and override a couple of methods:
The first gives you rounded corners and a border. You can tweak the border width, color etc. as needed.
- (void)drawRect:(CGRect)rect
{
self.layer.cornerRadius = 4.0;
self.layer.borderWidth = 1;
[super drawRect:rect];
}
The second lets you specify insets to position the label text away from the left border.
- (void) drawTextInRect:(CGRect)rect
{
UIEdgeInsets insets = {0,5,0,5};
[super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}
Alternatively, without using a label, you could use NSString method sizeWithFont:forWidth:lineBreakMode:, which returns the size of the text. Then, you could call NSString drawInRect:withFont:lineBreakMode: method, where your rect would be the one obtained from the sizeWithFont method, increased by the desired margin.
You can also add a space in the Text for a very simple solution:
ObjC code (added by s1m0n as comment)
[label setText:[NSString stringWithFormat:#" %# ", text]];
Monotouch (C#) code:
Label.text = " "+lbltext;
#Downvoting:
If you're down voting, show at least some respect by giving a reason so we can all learn why this is a bad solution. While it is certainly not a general solution for all cases, it might be a very simple solution in some cases. Because the border is created inside the Button, the text is "sticked" to the border (or there is even an overlap) and adding a space can easily fix this.

Set UIView.frame.size.height to zero to hide content?

UIView *stateView = [getSomeUIView thisOne];
CGRect currentFrame = stateView.frame;
if(currentFrame.size.height == 0.0) {
currentFrame.size = CGSizeMake(260, 60);
}
else {
currentFrame.size = CGSizeMake(260, 0);
}
stateView.frame = currentFrame;
I would expect all the subviews would be hidden when the height of the frame is set to zero however this does not happen (in the iPhone 4.0.1 Simulator).
Any suggestions why or alternatives?
I was planing to later animate the frame so it's a sliding effect. I can not use the y position and move it off screen nor can I create a element to hide it behind since I'm working with a background image and everything on top is transparent/alpha layer.
I've got the same problem. Solved it with clipsToBounds property:
stateView.clipsToBounds = YES
Subviews will only change size if you set their springs and struts to do so.
By default, they are set to "stay the SAME width and height, and stay the same distance from top left corner of the parent view".
You can set the springs/struts in Interface Builder, or in code. e.g.:
aSubView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
Use UIScrollView instead of UIView. UIScrollView is made to hide "overflow" and works perfectly.

When UIButton content mode is "center," background image is pixelated

Here's how I'm setting the background image and content mode:
[btn setBackgroundImage:[UIImage imageNamed:#"dots_game_horiz_blue.png"]
forState:UIControlStateNormal];
[btn setContentMode:UIViewContentModeCenter];
Is there a reason that the background image would be pixelated? The frame is slightly larger than the image size, and I just want the image to be centered.
I guess a background image is not considered to be "content" by the UIButton, so the content mode did not apply to the background image. Instead, I set the image of the button and it worked just fine:
[btn setImage:[[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"dots_game_horiz_blue" ofType:#"png"]] forState:UIControlStateNormal];
[btn setContentMode:UIViewContentModeCenter];
In your xib / storyboard, in the Attributes inspector, you need to:
Set your UIButton type to Custom
Set your image in the property Image, not Background
Validating step 2, you can see the button frame changed according to the image set. Set the frame as you want it to be, the image will resize itself to fit in
Select Image for the property Edge in order to apply inset to the button image
Enter inset values you need. If you set 5 to Top, Bottom, Left, Right, the image will be centered inside the button, with a border of 5
You can see the changes in the xib / storyboard view, no need to launch a debug.
Tip: Inset is the same for every images of the button (State Config)
You could also implement - (CGRect)backgroundRectForBounds:(CGRect)bounds to control how the background is drawn.
The correct solution is to change the type from System to Custom. Then the background image will honor the content type instead of just centering. In my case I set it to Aspect Fill and apply a 45 degree corner radius to round it. Simple and works perfectly.
I needed to create rounded buttons for avatar photos and found the answers to this question to help but they did not get me all of the way there. I implemented the backgroundRectForBounds method and scaled the image to fit and it works well.
I have the code on GitHub.
https://github.com/brennanMKE/CircleButton
The method is also listed below. It is important to set the background image and not the image for the button which does not work with this method.
- (CGRect)backgroundRectForBounds:(CGRect)bounds {
UIImage *backgroundImage = [self backgroundImageForState:self.state];
if (backgroundImage) {
CGFloat maxWidth = CGRectGetWidth(self.frame);
CGFloat xDelta = maxWidth / backgroundImage.size.width;
CGFloat yDelta = maxWidth / backgroundImage.size.height;
CGFloat delta = xDelta > yDelta ? xDelta : yDelta;
CGFloat x = floorf((self.bounds.size.width - (backgroundImage.size.width * delta)) / 2);
CGFloat y = floorf((self.bounds.size.height - (backgroundImage.size.height * delta)) / 2);
return CGRectMake(x, y, backgroundImage.size.width * delta, backgroundImage.size.height * delta);
}
else {
return [super backgroundRectForBounds:bounds];
}
}