How to create a small button with a large tappable area - objective-c

I want to create a close button which will look like a circle with an x in the middle. In x code I set the button's size and width to be large so that the touchable area is larger (50 x 50 with a font of just 22).
I create a button, change the title to X and then set the following:
[self.closeButton.layer setBorderWidth:2.0f];
[self.closeButton.layer setBorderColor:[[UIColor whiteColor] CGColor]];
[self.closeButton.layer setCornerRadius:self.closeButton.bounds.size.width/2];
The circle border is too far from the X. How would I bring the borders in tighter to the X but not decrease the size of the clickable area?

assign image to a button. and make tappable area as you want. then set image location in button by setting inset value of that button as top, bottom, left, right. change the value of this according to your requirements. You can set inset value from interface builder as shown in image here. change the value and see the difference to place your image in button at exact location you want.
exactly like this image

I'd suggest exactly what Max has done. He has shown how to do this via IB, this is how you do it through code:
myButton.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 25, 25);// UIButton
myBarButtonItem.imageInsets = UIEdgeInsetsMake(0, 0, 25, 25);// UIBarButtonItem
EDIT:
Sorry for not reading your question properly the first time. I think you will run into the same issue with this approach : the border/cornerRadius of the button will not respect any insets. It will be drawn according to the frame of the button. Only (easy) workaround at the top of my head, is to create an image with the border and corners in it, and then set it as the image. The image will respect the insets, and you will have your desired tappable area, with the borders exactly where you want them.
There might be a more elegant workaround through subclassing, but unless you change the border width/color, or corner radius of your button at any stage, I'd suggest sticking with custom image.
EDIT 2:
Instead of using an image you might want to use this unicode character.

Related

UIButton width doesn't increase based on text if insets are given

I have given trailing, top and height constraints to the button.
As you can see in the attached screenshot, if I remove all the insets given, then button looks perfect and button fits based on text length.
But I want to give right-left title insets as well as left image inset.
Then button is not displaying text properly as shown in the attached screenshot.
Auto-layout can be a little tricky when adjusting the Title Label of a UIButton.
From Apple's docs for titleEdgeInsets:
This property is used only for positioning the title during layout. The button does not use this property to determine intrinsicContentSize and sizeThatFits(_:).
You have a couple options...
One is to subclass UIButton and override .intrinsicContentSize.
Another option, which may be better for your case, is to adjust the Content Insets instead of the Title Insets.
As you described, this button has Top / Trailing / Height constraints:
Note that the Left value for the Image Inset is a negative value. You may / probably will want to tweak the values I used.

Change Button Width and Height Programmatically Xcocde

I have an app that you tap a button and at certain points you get time added. I want to add to the app that whenever the certain point is met, the button height and width get smaller. How would I go about doing that?
If your button is named, say, button, this will make it 5 pixels smaller in all directions:
[button setFrame:CGRectInset(button.frame, 5, 5);
You can have more freedom by using any CGRect value you wish; but setFrame is the way to go.

How to set an image to a NSButton to be resized along with the button?

I have an image (3width x 15height, the first and last pixels are rounded on the corners), and I want to create a button (the height of the button is always the same, 15px, but the width changes) that uses this image no matter what size it is, kinda like UIEdgeInsets on iOS.
I've tried to use [[button cell] setImageScaling:NSImageScaleAxesIndependently]; but the image gets distorted and loses quality.
How can I do this on OSX? Thanks!
You could probably create a custom subclass of NSButtonCell and use the Application Kit's NSDrawThreePartImage() function in the cell's drawInteriorWithFrame:inView: method.
For more info on how to use NSDrawThreePartImage(), see Cocoa Drawing Guide: Drawing Resizable Textures Using Images.
If it's possible to set this in graphical interface > Attribute Inspection > Button section Background

Using resizableImageWithCapInsets: image for button only works for the state set, other states show a "gap"

When using resizableImageWithCapInsets: to create an image for a UIButton only the normal state (the state set the image with using setBackgroundImage:forState:) works. All other states show a gap instead of the drawn image. UIButton says that if no image is set for a particular state, the normal state image will be used with an overlay for disabled and selected states.
Here is the normal state:
Here is the selected state:
And here is the source image:
It clearly is using the resizable image I provided, but the image is not drawing the resized area. (You can see the left and right edges but the middle area that is to be stretched just isn't drawn).
Interestingly, stretchableImageWithLeftCapWidth:topCapHeight: does work. Now this is a deprecated method in iOS 5, but with the gap being shown in the new API, I may be stuck using it.
I do recognize that I can provide more images for each state but that defeats the purpose I'm trying to achieve of reducing memory footprint plus adds extra dependency on my graphics designer which I'd like to avoid.
// This is the gist of the code being used
UIImage* image = [UIImage imageNamed:#"button.png"];
UIEdgeInsets insets = UIEdgeInsetsMake(image.size.height/2, image.size.width/2, image.size.height/2, image.size.width/2);
image = [image resizableImageWithCapInsets:insets];
[self.button setBackgroundImage:image forState:UIControlStateNormal];
// Even doing the following results in the same behaviour
[self.button setBackgroundImage:image forState:UIControlStateSelected];
You aren't creating your insets properly for the image capping. I've reproduced your issue and corrected it by using the correct insets.
With your current code, you are creating caps of half of the image height and width - this leaves you with a "stretchable" area of 0x0 pixels - so you get nothing in the middle.
Why this isn't showing up as wrong in the normal state of the button I'm not sure - perhaps there is some optimisation built in to UIButton to fix things or auto-strectch if you don't supply a stretchable image, and this is not applied to the other states.
The caps are supposed to define the area of the image that must not be stretched. In the case of your button.png image, this is 6 pixels on the left and right sides, and 16 pixels in from the top and bottom. This isn't quite standard, you should tell your graphics designer that (at least for left-right which is the most common stretching) you should only have a 1px area in the centre, however this does not affect the outcome. If you do have a 1px stretchable area then you can standardise your code by deriving the caps from the image size as you have tried to do in your question (each cap is then (image.size.height - 1) / 2 for top/bottom, same but with width for left/right).
To get the correct images on your button, use the following code for creating the stretchable image:
UIEdgeInsets insets = UIEdgeInsetsMake(16, 6, 16, 6);
image = [image resizableImageWithCapInsets:insets];
I was experiencing problems while using resizable images on iOS5 too. It turns out that if your button is of type "RountedRect" and you manipulate the background images, the resizable images will not behave as expected. (iOS6 handles this ok, presumably by assuming your new button type and adjusting as needed.)

What is the "Mode" property in Interface Builder which offers "Scale to fill", "Aspect fit" etc.?

I'm wondering what the dropdown "Mode" is about? It contains "Scale to fill", "Aspect fit" and so on. I never had to change it so far, still I'm curious what it can be used for. Can somebody explain?
The content mode property of a view tells how its content should be laid out. In the Interface Builder, the various modes can be selected in the Attributes Inspector.
Let's use two image views to see how the various modes work.
Scale to Fill
The image heights and widths are stretched to match the size of the UIImageView.
Aspect Fit
The longest side (either height or width) of the image is stretched to match the view. This makes the image as big as possible while still showing the entire image and not distorting the height or width. (I set the UIImageView background to blue so that its size is clear.)
Aspect Fill
The shortest side (either height or width) of the image is stretched to match the view. Like "Aspect Fit", the proportions of the image are not distorted from their original aspect ratio.
Redraw
Redraw is only for custom views that need to do their own scaling and resizing. We aren't using a custom view, so we shouldn't use Redraw. Notice that here UIImageView just gives us the same result as Scale to Fill, but it is doing more work behind the scenes.
About Redraw, the documentation says:
Content modes are good for recycling the contents of your view, but you can also set the content mode to the UIViewContentModeRedraw value when you specifically want your custom views to redraw themselves during scaling and resizing operations. Setting your view’s content mode to this value forces the system to call your view’s drawRect: method in response to geometry changes. In general, you should avoid using this value whenever possible, and you should certainly not use it with the standard system views.
Center
The image is centered in the view, but the length and width of the image are not stretched.
Top
The top edge of the image is centered horizontally at the top of the view, and the length and width of the image are not stretched.
Bottom
The bottom edge of the image is centered horizontally at the bottom of the view, and the length and width of the image are not stretched.
Left
The left edge of the image is centered vertically at the left of the view, and the length and width of the image are not stretched.
Right
The right edge of the image is centered vertically at the right of the view, and the length and width of the image are not stretched.
Top Left
The top left corner of the image is placed at the top left corner of the view. The length and width of the image are not stretched.
Top Right
The top right corner of the image is placed at the top right corner of the view. The length and width of the image are not stretched.
Bottom Left
The bottom left corner of the image is placed at the bottom left corner of the view. The length and width of the image are not stretched.
Bottom Right
The bottom right corner of the image is placed at the bottom right corner of the view. The length and width of the image are not stretched.
Notes
If the content (in our case the image) is the same size as the view (in our case the UIImageView), then changing the content mode will make no noticeable difference.
See this and this question for a discussion about content modes for views other than UIImageView.
In Swift, to set to set the content mode programmatically you do the following:
imageView.contentMode = UIViewContentMode.ScaleToFill
imageView.contentMode = UIViewContentMode.ScaleAspectFit
imageView.contentMode = UIViewContentMode.ScaleAspectFill
imageView.contentMode = UIViewContentMode.Redraw
imageView.contentMode = UIViewContentMode.Center
imageView.contentMode = UIViewContentMode.Top
imageView.contentMode = UIViewContentMode.Bottom
imageView.contentMode = UIViewContentMode.Left
imageView.contentMode = UIViewContentMode.Right
imageView.contentMode = UIViewContentMode.TopLeft
imageView.contentMode = UIViewContentMode.TopRight
imageView.contentMode = UIViewContentMode.BottomLeft
imageView.contentMode = UIViewContentMode.BottomRight
View Programming Guide goes into details of what you're asking about. If you scroll down to the section called "Content Modes" you'd find what you're looking for.
Basically according to Apple:
"Each view has a content mode that controls how the view recycles its content in response to changes in the view’s geometry [...] the value in the contentMode property determines whether the bitmap should be scaled to fit the new bounds or simply pinned to one corner or edge of the view."
http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/
should give you the basic ideas very well.