Tap area ridiculously small for UIButton - ios

I have a UIButton that I created like this:
let closeButton = UIButton(type: .System)
closeButton.backgroundColor = UIColor(r: 92, g: 92, b: 118, alpha: 1)
closeButton.setImage(UIImage(named: "closeCross")?.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate), forState: .Normal)
closeButton.tintColor = UIColor.whiteColor()
closeButton.imageEdgeInsets = UIEdgeInsets(top: -10, left: -10, bottom: -10, right: -10)
closeButton.addTarget(self, action: "close", forControlEvents: .TouchUpInside)
closeButton.frame = CGRectMake(messageView.frame.maxX - 30, 0, 20, 20)
closeButton.center.y = messageView.bounds.midY
The problem is that the tap is triggered only if you are a pixel away from the center of the UIButton. The image I set is a png that is a cross X.
Even if I tap on the cross (but not exactly on the middle, thanks the simulator the precision), it doesn't work.
I don't understand. The background isn't clear. Whether or not I change the content/image edge insets doesn't change a thing. Whether or not I use an image rendering mode doesn't change a thing.

Its best practice to keep UIbuttons at least 44x44 in size. https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/LayoutandAppearance.html
Make it easy for people to interact with content and controls by giving each interactive element ample spacing. Give tappable controls a hit target of about 44 x 44 points.
So I would set your frame to be bigger then 20pts, also what size is your image 20pts? Could it be clipping outside of the button, check that clipToBounds is set to yes.
There also a more radical approach, and that's to create a subclass of UIButton with a touch area of at least 44.
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
CGFloat widthDelta = 44.0 - self.bounds.size.width;
CGFloat heightDelta = 44.0 - self.bounds.size.width;
CGRect largerBounds = CGRectInset(self.bounds, -0.5 * widthDelta, -0.5 * heightDelta);
return CGRectContainsPoint(largerBounds, point);
}
Another thing to do is investigate the button using reveal( http://revealapp.com/)

Here is actually how I fixed it:
closeButton.imageEdgeInsets = UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15)
closeButton.frame = CGRectMake(noConnectionMessageView.frame.maxX - 40, 0, 40, 40)

It only happens when there is no title along with image on UIButton. If you don't want to add a title, there is a hack...
Just add a space as title text. Whole area of your button would start responding.
It miraculously worked for me.

Related

How to add circle image on left navigation bar item

I wanted to add circle image on left navigation bar item as button. I could added, but it is not circle it is ellipse. Here is my code.
let button = UIButton();
button.downloaded(from: user?.Image);
button.frame = CGRect(x: 0, y: 0, width: 36, height:36);
button.layer.cornerRadius = button.frame.width / 2;
button.layer.masksToBounds = true;
button.imageView?.contentMode = .scaleAspectFill;
let barBtn = UIBarButtonItem(customView: button);
self.navigationItem.leftBarButtonItem = barBtn;
You can check my screen shot. Can you help me?
Issue arises when downloaded image is larger than (36, 36) it resets the frame of imageView and as result UIbutton's frame is also reset. You need to resize the image before assigning it to imageView making it smaller than (36,36).
Also don't make UIButton round, make imageView round. Otherwise touchable area of button will be reduced.
use:
button.imageView.layer.cornerRadius = button.imageView.frame.width / 2;
button.imageView.layer.masksToBounds = true;
Instead of:
button.layer.cornerRadius = button.frame.width / 2;
button.layer.masksToBounds = true;
Refer to following answer for resizing images.
How to Resize image in Swift?

How to add Image on UIButton on right side and contentMode don't working with image?

When i added image (by storyboard) to a button image content Mode not working .When i fix it(iPhone) by image insets and title insets on another device (iPad) its lose expect ratio ? how can i fix it ??
You can set Semantic to Force Right-To-Left of UIButton to set image at right side. Default Semantic value Unspecified.
The property "Semantic" in the storyboard is a rule which allows the iOS to know if the view should be flipped or not. - Apple's Documentations
Try this code and modify EdgeInset as you want, and assign your outlet as DropdownButton instead of IUButton
class DropdownButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
self.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left
if self.imageView?.image != nil {
// Move icon to right side
self.imageEdgeInsets = UIEdgeInsets(
top: 0,
left: self.bounds.size.width - self.imageView!.image!.size.width - 10,
bottom: 0,
right: 0)
// Move title to left side
self.titleEdgeInsets = UIEdgeInsetsMake(5, -self.imageView!.frame.size.width + 10, 5, 5)
}
}
}
You may try to set it programmatically. For example if the device is iPad or iPhone set the insets programatically. For example button.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0). try this code in viewWillAppear or viewDidLoad. I am using 0 just for the sake of understanding, use your own measured values.

clipsToBounds on UILabel not working

I have a UILabel, that I am setting up like this:
class someSuperclass {
var firstLetterLabel = UILabel(frame: CGRect(x: 58, y: 0, width: 81, height: 120))
func commonInit() {
firstLetterLabel.font = UIFont(name: "MuseoSans-500", size: 110.0)
firstLetterLabel.textColor = UIColor.museumRed
firstLetterLabel.textAlignment = .center
firstLetterLabel.numberOfLines = 1
firstLetterLabel.lineBreakMode = .byClipping
firstLetterLabel.clipsToBounds = false
addSubview(firstLetterLabel)
}
}
But it is still being clipped by its bounds
Since clipsToBounds does not seem to apply to the content of a label. How can I stop label content from being clipped by it's frame/bounds?
ClipsToBounds allows subviews or sub layers to spill out of a view or prevent that but it does not do that for drawn content by a view and in this case it is a UILabel. You cannot draw past the bounds of the view/label. That is why it is clipped. This difference always clips drawn content.
possible solutions
1) let intrinsic size of the single letter labels keep it from clipping. Place all the the labels in a horizontal stack view.
2) enable minimum font scale on the label to allow it to fit.
3) lastly it appears it is not drawing centered. Not really sure why as you have given very little to look at.
You can use UIButton instead, and setting button.userInteractionEnabled = false.

UITextView - Setting max lines hides the cursor

This is what I am doing to set max number of lines :
self.text_description.textContainer.maximumNumberOfLines = 2
self.text_description.layoutManager.textContainerChangedGeometry(self.text_description.textContainer)
When 3rd line is about to get started, the cursor disappears. To put it back I have to tap backspace.
Assuming, in the text view cursor doesn't stays behind the keyboard. I have written a helper method that makes UITextField text scroll to end of text.
- (void)scrollToCaretInTextView:(UITextView *)textView animated:(BOOL)animated
{
CGRect rect = [textView caretRectForPosition:textView.selectedTextRange.end]; //Get the content size of textview
rect.size.height += textView.textContainerInset.bottom;
[textView scrollRectToVisible:rect animated:animated];
}
I don't quite sure what you are expecting. If you want two lines max, there should be no 3rd line.
Use this:
self.text_description.textContainer.maximumNumberOfLines = 2
self.text_description.textContainer.lineBreakMode = .byTruncatingTail
Limit the number of lines for UITextview
It seems what you actually want is a textview with two lines height? If that is true, try this in you view controller.
self.text_description = UITextView(frame: CGRect(x: 100.0, y: 100.0, width: 200.0, height: 28.0))
self.text_description.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
self.view.addSubview(self.text_description)

How can I set the title of a UIButton as left-aligned?

I need to display an email address on the left side of a UIButton, but it is being positioned to the centre.
Is there any way to set the alignment to the left side of a UIButton?
This is my current code:
UIButton* emailBtn = [[UIButton alloc] initWithFrame:CGRectMake(5,30,250,height+15)];
emailBtn.backgroundColor = [UIColor clearColor];
[emailBtn setTitle:obj2.customerEmail forState:UIControlStateNormal];
emailBtn.titleLabel.font = [UIFont systemFontOfSize:12.5];
[emailBtn setTitleColor:[[[UIColor alloc]initWithRed:0.121 green:0.472 blue:0.823 alpha:1]autorelease] forState:UIControlStateNormal];
[emailBtn addTarget:self action:#selector(emailAction:) forControlEvents:UIControlEventTouchUpInside];
[elementView addSubview:emailBtn];
[emailBtn release];
Set the contentHorizontalAlignment:
// Swift
emailBtn.contentHorizontalAlignment = .left;
// Objective-C
emailBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
You might also want to adjust the content left inset otherwise the text will touch the left border:
// Swift 3 and up:
emailBtn.contentEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0);
// Objective-C
emailBtn.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
You can also use interface builder if you don't want to make the adjustments in code.
Here I left align the text and also indent it some:
Don't forget you can also align an image in the button too.:
In Swift 3+:
button.contentHorizontalAlignment = .left
Swift 4+
button.contentHorizontalAlignment = .left
button.contentVerticalAlignment = .top
button.contentEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
UIButton *btn;
btn.contentVerticalAlignment = UIControlContentVerticalAlignmentTop;
btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
Using emailBtn.titleEdgeInsets is better than contentEdgeInsets, in case you don't want to change the whole content position inside the button.
Here is explained how to do it and why it works so:
http://cocoathings.blogspot.com/2013/03/how-to-make-uibutton-text-left-or-right.html
in xcode 8.2.1 in the interface builder it moves to:
There is a small error in the code of #DyingCactus.
Here is the correct solution to add an UILabel to an UIButton to align the button text to better control the button 'title':
NSString *myLabelText = #"Hello World";
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeCustom];
// position in the parent view and set the size of the button
myButton.frame = CGRectMake(myX, myY, myWidth, myHeight);
CGRect myButtonRect = myButton.bounds;
UILabel *myLabel = [[UILabel alloc] initWithFrame: myButtonRect];
myLabel.text = myLabelText;
myLabel.backgroundColor = [UIColor clearColor];
myLabel.textColor = [UIColor redColor];
myLabel.font = [UIFont fontWithName:#"Helvetica Neue" size:14.0];
myLabel.textAlignment = UITextAlignmentLeft;
[myButton addSubview:myLabel];
[myLabel release];
Hope this helps....
Al
For Swift 2.0:
emailBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignment.Left
This can help if any one needed.
In Swift 5.0 and Xcode 10.2
You have two ways to approaches
1) Direct approach
btn.contentHorizontalAlignment = .left
2) SharedClass example (write once and use every ware)
This is your shared class(like this you access all components properties)
import UIKit
class SharedClass: NSObject {
static let sharedInstance = SharedClass()
private override init() {
}
}
//UIButton extension
extension UIButton {
func btnProperties() {
contentHorizontalAlignment = .left
}
}
In your ViewController call like this
button.btnProperties()//This is your button
Try
button.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
tl;dr: Using UIButton.Configuration - do titleAlignment = .center but also add a subtitle and make its font microscopic.
So, we're on iOS 15+, we're using the new UIButton.Configuration APIs, buttons now go multi-line by default and you're trying to figure out - how do I make the button's title be centered or trailing aligned, as opposed to the default (leading). For example you have an image and a button title underneath and and you want it centered.
Seems reasonable to try this:
configuration.titleAlignment = .center
But it doesn't change anything.
By trying thing out in Interface Builder, I noticed the following: titleAlignment only has an effect if there is a subtitle along with the title.
I am not sure if this is an omission on Apple's side (which might be fixed later) or if there is a good reason for it. In any case, we need a way to make it work without a subtitle. Perhaps some clever contentInset or UIControl.contentHorizontalAlignment can do the trick, but I'd be worried to use these in cases where we have to think about other languages, dynamic type etc.
Here's a solution which is still hacky, but would do the job:
Add a subtitle which contains just a space, then make the font microscopic, e.g. 0.01.
This is how to do it in code, assuming you are already working with a UIButton.Configuration:
configuration.titleAlignment = .center
configuration.title = "Hello hi"
configuration.subtitle = " "
configuration.subtitleTextAttributesTransformer = UIConfigurationTextAttributesTransformer({ input in
var output = input
output.font = .systemFont(ofSize: 0.01)
return output
})
Not an ideal solution and it might break in the future, but for some use cases the best available solution at the moment.
if you use button.contentEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10), you will get an warning that states 'contentEdgeInsets' was deprecated in iOS 15.0: This property is ignored when using UIButtonConfiguration. An alternative solution is:
iOS 15.0+
var button: UIButton = {
let button = UIButton(configuration: .filled())
button.configuration?.contentInsets = NSDirectionalEdgeInsets(top: 16, leading: 20, bottom: 16, trailing: 20)
button.contentHorizontalAlignment = .leading
return button
}()
SwiftUI
You should change the alignment property of the .frame modifier applied to the Text. Additionally, set the multiline text alignment to .leading.
Button {
// handler for tapping on the button
} label: {
Text("Label")
.frame(width: 200, alignment: .leading)
.multilineTextAlignment(.leading)
}

Resources