Implementing Button Text (titleLabel) and Image (imageView) Vertical Alignment#
- The method I initially used to implement this is as follows:
Create a custom view with two properties, label and imageView. Then, set the position layout and add a tap gesture recognizer to pass the click method using a delegate.
- The second method:
Create a custom Button that inherits from Button, with two properties, label and imageView. Then, set the layout. This way, there is no need to add a tap gesture recognizer.
- The third method:
Simply use the titleLabel and imageView provided by Button, and write a Category to set the arrangement of the label and image, e.g. vertical or horizontal.
Clearly, the first two methods are not ideal, so let's only discuss the third method here:
Button has two properties: titleEdgeInsets and imageEdgeInsets. By setting these two, we can achieve all the desired styles for the Button, such as image on top, image on bottom, image on left, and image on right.
Before setting these two, we need to understand the relationship between the titleLabel and imageView on the Button (imagine the default display of image and label on the Button):
- titleEdgeInsets is the inset of the titleLabel relative to its top, bottom, left, and right, similar to tableView's contentInset;
- If there is only a title, then the titleLabel's top, bottom, left, and right are all relative to the Button;
- If there is only an image, then the imageView's top, bottom, left, and right are all relative to the Button;
- If there is both an image and a label, then the image's top, bottom, and left are relative to the Button, and the right is relative to the label. The label's top, bottom, and right are relative to the Button, and the left is relative to the label.
The above paragraph is very important#
Once we understand this, we can understand the code below:
- Create a Category for Button, the .h file is as follows, defining an Enum to determine the style of the image and label, and a method to call the settings.
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSUInteger, MKButtonEdgeInsetsStyle) {
MKButtonEdgeInsetsStyleTop, // image on top, label on bottom
MKButtonEdgeInsetsStyleLeft, // image on left, label on right
MKButtonEdgeInsetsStyleBottom, // image on bottom, label on top
MKButtonEdgeInsetsStyleRight // image on right, label on left
};
@interface UIButton (ImageTitleSpacing)
/**
* Set the layout style and spacing between the button's titleLabel and imageView
*
* @param style The layout style of the titleLabel and imageView
* @param space The spacing between the titleLabel and imageView
*/
- (void)layoutButtonWithEdgeInsetsStyle:(MKButtonEdgeInsetsStyle)style
imageTitleSpace:(CGFloat)space;
- The .m file is as follows, implementing the method
#import "UIButton+ImageTitleSpacing.h"
@implementation UIButton (ImageTitleSpacing)
- (void)layoutButtonWithEdgeInsetsStyle:(MKButtonEdgeInsetsStyle)style
imageTitleSpace:(CGFloat)space
{
// 1. Get the width and height of the imageView and titleLabel
CGFloat imageWith = self.imageView.frame.size.width;
CGFloat imageHeight = self.imageView.frame.size.height;
CGFloat labelWidth = 0.0;
CGFloat labelHeight = 0.0;
if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
// For iOS 8 and above, use the following setting since titleLabel's size is 0
labelWidth = self.titleLabel.intrinsicContentSize.width;
labelHeight = self.titleLabel.intrinsicContentSize.height;
} else {
labelWidth = self.titleLabel.frame.size.width;
labelHeight = self.titleLabel.frame.size.height;
}
// 2. Declare global imageEdgeInsets and labelEdgeInsets
UIEdgeInsets imageEdgeInsets = UIEdgeInsetsZero;
UIEdgeInsets labelEdgeInsets = UIEdgeInsetsZero;
// 3. Get the values of imageEdgeInsets and labelEdgeInsets based on style and space
switch (style) {
case MKButtonEdgeInsetsStyleTop:
{
imageEdgeInsets = UIEdgeInsetsMake(-labelHeight-space/2.0, 0, 0, -labelWidth);
labelEdgeInsets = UIEdgeInsetsMake(0, -imageWith, -imageHeight-space/2.0, 0);
}
break;
case MKButtonEdgeInsetsStyleLeft:
{
imageEdgeInsets = UIEdgeInsetsMake(0, -space/2.0, 0, space/2.0);
labelEdgeInsets = UIEdgeInsetsMake(0, space/2.0, 0, -space/2.0);
}
break;
case MKButtonEdgeInsetsStyleBottom:
{
imageEdgeInsets = UIEdgeInsetsMake(0, 0, -labelHeight-space/2.0, -labelWidth);
labelEdgeInsets = UIEdgeInsetsMake(-imageHeight-space/2.0, -imageWith, 0, 0);
}
break;
case MKButtonEdgeInsetsStyleRight:
{
imageEdgeInsets = UIEdgeInsetsMake(0, labelWidth+space/2.0, 0, -labelWidth-space/2.0);
labelEdgeInsets = UIEdgeInsetsMake(0, -imageWith-space/2.0, 0, imageWith+space/2.0);
}
break;
default:
break;
}
// 4. Assign values
self.titleEdgeInsets = labelEdgeInsets;
self.imageEdgeInsets = imageEdgeInsets;
}
I have created a demo on GitHub, link: Custom Button
References#
- UIButton's titleEdgeInsets and imageEdgeInsets properties to achieve the desired arrangement of images and text, this blog explains the principles mentioned above, it is recommended to read it carefully to understand it.
- UIButton's imageEdgeInsets and titleEdgeInsets, this blog has a GitHub link at the end. When I was writing, I didn't understand the principles, so when setting it up, I referred to their code.
- How to layout a UIButton with both Image and Title, this was the reference I initially used, it only has code without principles.