ios 使用 imageEdgeInsets 和 titleEdgeInsets 对齐 UIButton 上的文本和图像
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4564621/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Aligning text and image on UIButton with imageEdgeInsets and titleEdgeInsets
提问by Justin Galzic
I would like to place an icon left of the two lines of text such that there's about 2-3 pixels of space between the image and the start of text. The control itself is Center aligned horizontally (set through Interface Builder)
我想在两行文本的左侧放置一个图标,以便图像和文本开头之间有大约 2-3 个像素的空间。控件本身水平居中对齐(通过界面生成器设置)
The button would resemble something like this:
该按钮将类似于以下内容:
| |
|[Image] Add To |
| Favorites |
I'm trying to configure this with contentEdgeInset, imageEdgeInsets and titleEdgeInsets to no avail. I understand that a negative value expands the edge while a positive value shrinks it to move it closer to the center.
我正在尝试使用 contentEdgeInset、imageEdgeInsets 和 titleEdgeInsets 对其进行配置,但无济于事。我知道负值会扩大边缘,而正值会缩小边缘以使其更靠近中心。
I tried:
我试过:
[button setTitleEdgeInsets:UIEdgeInsetsMake(0, -image.size.width, 0, 0)];
[button setImageEdgeInsets:UIEdgeInsetsMake(0, button.titleLabel.bounds.size.width, 0, 0)];
but this doesn't display it correctly. I've been tweaking the values but going from say -5 to -10 on the left inset value doesn't appear to move it in expected manner. -10 will scoot the text all the way to the left so I expected -5 to scoot it half way from the left side but it doesn't.
但这不能正确显示。我一直在调整这些值,但是从左边插入值的 -5 到 -10 似乎并没有以预期的方式移动它。-10 会将文本一直向左移动,所以我希望 -5 将它从左侧移动到一半,但事实并非如此。
What's the logic behind insets? I'm not familiar with image placements and related terminology.
插入背后的逻辑是什么?我不熟悉图像放置和相关术语。
I used this SO question as a reference but something about my values isn't right. UIButton: how to center an image and a text using imageEdgeInsets and titleEdgeInsets?
我使用this SO question作为参考,但我的价值观有些不对。 UIButton:如何使用 imageEdgeInsets 和 titleEdgeInsets 将图像和文本居中?
回答by Kekoa
I agree the documentation on imageEdgeInsets
and titleEdgeInsets
should be better, but I figured out how to get the correct positioning without resorting to trial and error.
我同意文档imageEdgeInsets
并且titleEdgeInsets
应该更好,但我想出了如何在不诉诸试验和错误的情况下获得正确的定位。
The general idea is here at this question, but that was if you wanted both text and image centered. We don't want the image and text to be centered individually, we want the image and the text to be centered together as a single entity. This is in fact what UIButton already does so we simply need to adjust the spacing.
这个问题的一般想法在这里,但如果你想要文本和图像都居中。我们不希望图像和文本单独居中,我们希望图像和文本作为单个实体一起居中。这实际上是 UIButton 已经做到的,所以我们只需要调整间距。
CGFloat spacing = 10; // the amount of spacing to appear between image and title
tabBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
tabBtn.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);
I also turned this into a category for UIButton so it will be easy to use:
我还把它变成了 UIButton 的一个类别,所以它很容易使用:
UIButton+Position.h
UIButton+Position.h
@interface UIButton(ImageTitleCentering)
-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing;
@end
UIButton+Position.m
UIButton+Position.m
@implementation UIButton(ImageTitleCentering)
-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing {
self.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
self.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);
}
@end
So now all I have to do is:
所以现在我要做的就是:
[button centerButtonAndImageWithSpacing:10];
And I get what I need every time. No more messing with the edge insets manually.
我每次都能得到我需要的东西。不再手动弄乱边缘插入物。
EDIT: Swapping Image and Text
编辑:交换图像和文本
In response to @Javal in comments
在评论中回应@Javal
Using this same mechanism, we can swap the image and the text. To accomplish the swap, simply use a negative spacing but also include the width of the text and the image. This will require frames to be known and layout performed already.
使用相同的机制,我们可以交换图像和文本。要完成交换,只需使用负间距,但也要包括文本和图像的宽度。这将需要已知框架并已执行布局。
[self.view layoutIfNeeded];
CGFloat flippedSpacing = -(desiredSpacing + button.currentImage.size.width + button.titleLabel.frame.size.width);
[button centerButtonAndImageWithSpacing:flippedSpacing];
Of course you will probably want to make a nice method for this, potentially adding a second category method, this is left as an exercise to the reader.
当然,您可能希望为此创建一个很好的方法,可能会添加第二类方法,这留给读者作为练习。
回答by ravron
I'm a little late to this party, but I think I have something useful to add.
我参加这个派对有点晚了,但我想我有一些有用的东西要补充。
Kekoa's answer is great but, as RonLugge mentions, it can make the button no longer respect sizeToFit
or, more importantly, can cause the button to clip its content when it is intrinsically sized. Yikes!
Kekoa 的回答很好,但是,正如 RonLugge 所提到的,它可以使按钮不再受尊重,sizeToFit
或者更重要的是,当按钮本身具有大小时,它会导致其内容被剪裁。哎呀!
First, though,
不过首先,
A brief explanation of how I believe imageEdgeInsets
and titleEdgeInsets
work:
简要说明我的信仰imageEdgeInsets
和titleEdgeInsets
工作方式:
The docs for imageEdgeInsets
have the following to say, in part:
在对文档imageEdgeInsets
有以下的说法,部分内容如下:
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.
使用此属性可以调整按钮图像的有效绘图矩形的大小和位置。您可以为四个插图(顶部、左侧、底部、右侧)中的每一个指定不同的值。正值会缩小或插入该边缘 - 将其移近按钮的中心。负值会扩展或开始该边缘。
I believe that this documentation was written imagining that the button has no title, just an image. It makes a lot more sense thought of this way, and behaves how UIEdgeInsets
usually do. Basically, the frame of the image (or the title, with titleEdgeInsets
) is moved inwards for positive insets and outwards for negative insets.
我相信这个文档是在想象按钮没有标题,只有一个图像的情况下编写的。以这种方式思考更有意义,并且表现得像往常UIEdgeInsets
一样。基本上,图像的框架(或标题,带有titleEdgeInsets
)向内移动以表示正插图,向外移动表示负插图。
OK, so what?
好的,那又怎样?
I'm getting there! Here's what you have by default, setting an image and a title (the button border is green just to show where it is):
我快到那里了!这是默认情况下,设置图像和标题(按钮边框为绿色只是为了显示它的位置):
When you want spacing between an image and a title, without causing either to be crushed, you need to set four different insets, two on each of the image and title. That's because you don't want to change the sizesof those elements' frames, but just their positions. When you start thinking this way, the needed change to Kekoa's excellent category becomes clear:
如果您希望在图像和标题之间留出间距,而不会导致任何一个被压碎,您需要设置四个不同的插图,每个图像和标题上都有两个。那是因为您不想更改这些元素框架的大小,而只想更改它们的位置。当你开始这样思考时,对 Kekoa 优秀类别的必要改变就变得很清楚了:
@implementation UIButton(ImageTitleCentering)
- (void)centerButtonAndImageWithSpacing:(CGFloat)spacing {
CGFloat insetAmount = spacing / 2.0;
self.imageEdgeInsets = UIEdgeInsetsMake(0, -insetAmount, 0, insetAmount);
self.titleEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, -insetAmount);
}
@end
But wait, you say, when I do that, I get this:
但是等等,你说,当我这样做时,我得到了这个:
Oh yeah! I forgot, the docswarned me about this. They say, in part:
哦耶!我忘了,文档警告过我这一点。他们说,部分:
This property is used only for positioning the image during layout. The button does not use this property to determine
intrinsicContentSize
andsizeThatFits:
.
此属性仅用于在布局期间定位图像。该按钮不使用此属性来确定
intrinsicContentSize
和sizeThatFits:
。
But there isa property that can help, and that's contentEdgeInsets
. The docsfor that say, in part:
但有是一个属性,它可以帮助,这就是contentEdgeInsets
。文档部分说:
The button uses this property to determine
intrinsicContentSize
andsizeThatFits:
.
该按钮使用此属性来确定
intrinsicContentSize
和sizeThatFits:
。
That sounds good. So let's tweak the category once more:
听起来不错。因此,让我们再次调整类别:
@implementation UIButton(ImageTitleCentering)
- (void)centerButtonAndImageWithSpacing:(CGFloat)spacing {
CGFloat insetAmount = spacing / 2.0;
self.imageEdgeInsets = UIEdgeInsetsMake(0, -insetAmount, 0, insetAmount);
self.titleEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, -insetAmount);
self.contentEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, insetAmount);
}
@end
And what do you get?
你会得到什么?
Looks like a winner to me.
对我来说似乎是赢家。
Working in Swift and don't want to do any thinking at all? Here's the final version of the extension in Swift:
在 Swift 工作,根本不想做任何思考?这是 Swift 中扩展的最终版本:
extension UIButton {
func centerTextAndImage(spacing: CGFloat) {
let insetAmount = spacing / 2
imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount, bottom: 0, right: insetAmount)
titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: -insetAmount)
contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
}
}
回答by Freeman
In interface Builder. Select the UIButton -> Attributes Inspector -> Edge=Title and modify the edge insets
在界面生成器中。选择 UIButton -> Attributes Inspector -> Edge=Title 并修改边缘插入
回答by gbk
Also if you want to make something similar to
另外如果你想做类似的东西
You need
你需要
1.Set horizontal and vertical alignment for button to
1.设置按钮的水平和垂直对齐方式
Find all required values and set
UIImageEdgeInsets
CGSize buttonSize = button.frame.size; NSString *buttonTitle = button.titleLabel.text; CGSize titleSize = [buttonTitle sizeWithAttributes:@{ NSFontAttributeName : [UIFont camFontZonaProBoldWithSize:12.f] }]; UIImage *buttonImage = button.imageView.image; CGSize buttonImageSize = buttonImage.size; CGFloat offsetBetweenImageAndText = 10; //vertical space between image and text [button setImageEdgeInsets:UIEdgeInsetsMake((buttonSize.height - (titleSize.height + buttonImageSize.height)) / 2 - offsetBetweenImageAndText, (buttonSize.width - buttonImageSize.width) / 2, 0,0)]; [button setTitleEdgeInsets:UIEdgeInsetsMake((buttonSize.height - (titleSize.height + buttonImageSize.height)) / 2 + buttonImageSize.height + offsetBetweenImageAndText, titleSize.width + [button imageEdgeInsets].left > buttonSize.width ? -buttonImage.size.width + (buttonSize.width - titleSize.width) / 2 : (buttonSize.width - titleSize.width) / 2 - buttonImage.size.width, 0,0)];
找到所有需要的值并设置
UIImageEdgeInsets
CGSize buttonSize = button.frame.size; NSString *buttonTitle = button.titleLabel.text; CGSize titleSize = [buttonTitle sizeWithAttributes:@{ NSFontAttributeName : [UIFont camFontZonaProBoldWithSize:12.f] }]; UIImage *buttonImage = button.imageView.image; CGSize buttonImageSize = buttonImage.size; CGFloat offsetBetweenImageAndText = 10; //vertical space between image and text [button setImageEdgeInsets:UIEdgeInsetsMake((buttonSize.height - (titleSize.height + buttonImageSize.height)) / 2 - offsetBetweenImageAndText, (buttonSize.width - buttonImageSize.width) / 2, 0,0)]; [button setTitleEdgeInsets:UIEdgeInsetsMake((buttonSize.height - (titleSize.height + buttonImageSize.height)) / 2 + buttonImageSize.height + offsetBetweenImageAndText, titleSize.width + [button imageEdgeInsets].left > buttonSize.width ? -buttonImage.size.width + (buttonSize.width - titleSize.width) / 2 : (buttonSize.width - titleSize.width) / 2 - buttonImage.size.width, 0,0)];
This will arrange your title and image on button.
这将在按钮上排列您的标题和图像。
Also please note update this on each relayout
另请注意在每次重新布局时更新此内容
Swift
迅速
import UIKit
extension UIButton {
// MARK: - UIButton+Aligment
func alignContentVerticallyByCenter(offset:CGFloat = 10) {
let buttonSize = frame.size
if let titleLabel = titleLabel,
let imageView = imageView {
if let buttonTitle = titleLabel.text,
let image = imageView.image {
let titleString:NSString = NSString(string: buttonTitle)
let titleSize = titleString.sizeWithAttributes([
NSFontAttributeName : titleLabel.font
])
let buttonImageSize = image.size
let topImageOffset = (buttonSize.height - (titleSize.height + buttonImageSize.height + offset)) / 2
let leftImageOffset = (buttonSize.width - buttonImageSize.width) / 2
imageEdgeInsets = UIEdgeInsetsMake(topImageOffset,
leftImageOffset,
0,0)
let titleTopOffset = topImageOffset + offset + buttonImageSize.height
let leftTitleOffset = (buttonSize.width - titleSize.width) / 2 - image.size.width
titleEdgeInsets = UIEdgeInsetsMake(titleTopOffset,
leftTitleOffset,
0,0)
}
}
}
}
回答by Nishant
You can avoid much trouble by using this --
使用这个可以避免很多麻烦——
myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
myButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
This will align all your content automatically to left (or wherever you want it)
这将自动将您的所有内容对齐到左侧(或您想要的任何位置)
Swift 3:
斯威夫特 3:
myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left;
myButton.contentVerticalAlignment = UIControlContentVerticalAlignment.center;
回答by Sahil
In Xcode 8.0you can simply do it by changing insets
in size inspector.
在Xcode 8.0 中,您可以通过更改insets
大小检查器来简单地做到这一点。
Select the UIButton -> Attributes Inspector -> go to size inspector and modify the content, image and title insets.
选择 UIButton -> Attributes Inspector -> go to size inspector 并修改内容、图像和标题插入。
And if you want to change image on right side you can simply change the semantic property to Force Right-to-left
in Attribute inspector .
如果您想更改右侧的图像,您可以简单地将语义属性更改为Force Right-to-left
in Attribute inspector 。
回答by gbitaudeau
I'm a little late to this party too, but I think I have something useful to add :o).
我参加这个聚会也有点晚了,但我想我有一些有用的东西要补充:o)。
I created a UIButton
subclass whose purpose is to be able to choose where the button's image is layout, either vertically or horizontally.
我创建了一个UIButton
子类,其目的是能够选择按钮图像的布局位置,垂直或水平。
It means that you can make this kind of buttons :
Here the details about how to create these buttons with my class :
这是有关如何使用我的课程创建这些按钮的详细信息:
func makeButton (imageVerticalAlignment:LayoutableButton.VerticalAlignment, imageHorizontalAlignment:LayoutableButton.HorizontalAlignment, title:String) -> LayoutableButton {
let button = LayoutableButton ()
button.imageVerticalAlignment = imageVerticalAlignment
button.imageHorizontalAlignment = imageHorizontalAlignment
button.setTitle(title, for: .normal)
// add image, border, ...
return button
}
let button1 = makeButton(imageVerticalAlignment: .center, imageHorizontalAlignment: .left, title: "button1")
let button2 = makeButton(imageVerticalAlignment: .center, imageHorizontalAlignment: .right, title: "button2")
let button3 = makeButton(imageVerticalAlignment: .top, imageHorizontalAlignment: .center, title: "button3")
let button4 = makeButton(imageVerticalAlignment: .bottom, imageHorizontalAlignment: .center, title: "button4")
let button5 = makeButton(imageVerticalAlignment: .bottom, imageHorizontalAlignment: .center, title: "button5")
button5.contentEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
To do that, I added 2 attributes : imageVerticalAlignment
and imageHorizontalAlignment
. Off course, If your button only have an image or a title ... don't use this class at all !
为此,我添加了 2 个属性 :imageVerticalAlignment
和imageHorizontalAlignment
. 当然,如果你的按钮只有一个图像或一个标题......根本不要使用这个类!
I also added an attribute named imageToTitleSpacing
which allow you to adjust space between title and image.
我还添加了一个名为的属性imageToTitleSpacing
,它允许您调整标题和图像之间的空间。
This class try his best to be compatible if you want to use imageEdgeInsets
, titleEdgeInsets
and contentEdgeInsets
directly or in combinaison with the new layout attributes.
这个类尽量兼容,如果你想直接使用imageEdgeInsets
,titleEdgeInsets
和contentEdgeInsets
直接或结合新的布局属性。
As @ravron explains us, I try my best to make the button content edge correct (as you can see with the red borders).
正如@ravron 向我们解释的那样,我尽力使按钮内容边缘正确(如红色边框所示)。
You can also use it in Interface Builder :
您也可以在 Interface Builder 中使用它:
- Create a UIButton
- Change the button class
- Adjust Layoutable Attributes using "center", "top", "bottom", "left" or "right"
Here the code (gist) :
这里的代码(要点):
@IBDesignable
class LayoutableButton: UIButton {
enum VerticalAlignment : String {
case center, top, bottom, unset
}
enum HorizontalAlignment : String {
case center, left, right, unset
}
@IBInspectable
var imageToTitleSpacing: CGFloat = 8.0 {
didSet {
setNeedsLayout()
}
}
var imageVerticalAlignment: VerticalAlignment = .unset {
didSet {
setNeedsLayout()
}
}
var imageHorizontalAlignment: HorizontalAlignment = .unset {
didSet {
setNeedsLayout()
}
}
@available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'imageVerticalAlignment' instead.")
@IBInspectable
var imageVerticalAlignmentName: String {
get {
return imageVerticalAlignment.rawValue
}
set {
if let value = VerticalAlignment(rawValue: newValue) {
imageVerticalAlignment = value
} else {
imageVerticalAlignment = .unset
}
}
}
@available(*, unavailable, message: "This property is reserved for Interface Builder. Use 'imageHorizontalAlignment' instead.")
@IBInspectable
var imageHorizontalAlignmentName: String {
get {
return imageHorizontalAlignment.rawValue
}
set {
if let value = HorizontalAlignment(rawValue: newValue) {
imageHorizontalAlignment = value
} else {
imageHorizontalAlignment = .unset
}
}
}
var extraContentEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero
override var contentEdgeInsets: UIEdgeInsets {
get {
return super.contentEdgeInsets
}
set {
super.contentEdgeInsets = newValue
self.extraContentEdgeInsets = newValue
}
}
var extraImageEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero
override var imageEdgeInsets: UIEdgeInsets {
get {
return super.imageEdgeInsets
}
set {
super.imageEdgeInsets = newValue
self.extraImageEdgeInsets = newValue
}
}
var extraTitleEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero
override var titleEdgeInsets: UIEdgeInsets {
get {
return super.titleEdgeInsets
}
set {
super.titleEdgeInsets = newValue
self.extraTitleEdgeInsets = newValue
}
}
//Needed to avoid IB crash during autolayout
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.imageEdgeInsets = super.imageEdgeInsets
self.titleEdgeInsets = super.titleEdgeInsets
self.contentEdgeInsets = super.contentEdgeInsets
}
override func layoutSubviews() {
if let imageSize = self.imageView?.image?.size,
let font = self.titleLabel?.font,
let textSize = self.titleLabel?.attributedText?.size() ?? self.titleLabel?.text?.size(attributes: [NSFontAttributeName: font]) {
var _imageEdgeInsets = UIEdgeInsets.zero
var _titleEdgeInsets = UIEdgeInsets.zero
var _contentEdgeInsets = UIEdgeInsets.zero
let halfImageToTitleSpacing = imageToTitleSpacing / 2.0
switch imageVerticalAlignment {
case .bottom:
_imageEdgeInsets.top = (textSize.height + imageToTitleSpacing) / 2.0
_imageEdgeInsets.bottom = (-textSize.height - imageToTitleSpacing) / 2.0
_titleEdgeInsets.top = (-imageSize.height - imageToTitleSpacing) / 2.0
_titleEdgeInsets.bottom = (imageSize.height + imageToTitleSpacing) / 2.0
_contentEdgeInsets.top = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
_contentEdgeInsets.bottom = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
//only works with contentVerticalAlignment = .center
contentVerticalAlignment = .center
case .top:
_imageEdgeInsets.top = (-textSize.height - imageToTitleSpacing) / 2.0
_imageEdgeInsets.bottom = (textSize.height + imageToTitleSpacing) / 2.0
_titleEdgeInsets.top = (imageSize.height + imageToTitleSpacing) / 2.0
_titleEdgeInsets.bottom = (-imageSize.height - imageToTitleSpacing) / 2.0
_contentEdgeInsets.top = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
_contentEdgeInsets.bottom = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
//only works with contentVerticalAlignment = .center
contentVerticalAlignment = .center
case .center:
//only works with contentVerticalAlignment = .center
contentVerticalAlignment = .center
break
case .unset:
break
}
switch imageHorizontalAlignment {
case .left:
_imageEdgeInsets.left = -halfImageToTitleSpacing
_imageEdgeInsets.right = halfImageToTitleSpacing
_titleEdgeInsets.left = halfImageToTitleSpacing
_titleEdgeInsets.right = -halfImageToTitleSpacing
_contentEdgeInsets.left = halfImageToTitleSpacing
_contentEdgeInsets.right = halfImageToTitleSpacing
case .right:
_imageEdgeInsets.left = textSize.width + halfImageToTitleSpacing
_imageEdgeInsets.right = -textSize.width - halfImageToTitleSpacing
_titleEdgeInsets.left = -imageSize.width - halfImageToTitleSpacing
_titleEdgeInsets.right = imageSize.width + halfImageToTitleSpacing
_contentEdgeInsets.left = halfImageToTitleSpacing
_contentEdgeInsets.right = halfImageToTitleSpacing
case .center:
_imageEdgeInsets.left = textSize.width / 2.0
_imageEdgeInsets.right = -textSize.width / 2.0
_titleEdgeInsets.left = -imageSize.width / 2.0
_titleEdgeInsets.right = imageSize.width / 2.0
_contentEdgeInsets.left = -((imageSize.width + textSize.width) - max (imageSize.width, textSize.width)) / 2.0
_contentEdgeInsets.right = -((imageSize.width + textSize.width) - max (imageSize.width, textSize.width)) / 2.0
case .unset:
break
}
_contentEdgeInsets.top += extraContentEdgeInsets.top
_contentEdgeInsets.bottom += extraContentEdgeInsets.bottom
_contentEdgeInsets.left += extraContentEdgeInsets.left
_contentEdgeInsets.right += extraContentEdgeInsets.right
_imageEdgeInsets.top += extraImageEdgeInsets.top
_imageEdgeInsets.bottom += extraImageEdgeInsets.bottom
_imageEdgeInsets.left += extraImageEdgeInsets.left
_imageEdgeInsets.right += extraImageEdgeInsets.right
_titleEdgeInsets.top += extraTitleEdgeInsets.top
_titleEdgeInsets.bottom += extraTitleEdgeInsets.bottom
_titleEdgeInsets.left += extraTitleEdgeInsets.left
_titleEdgeInsets.right += extraTitleEdgeInsets.right
super.imageEdgeInsets = _imageEdgeInsets
super.titleEdgeInsets = _titleEdgeInsets
super.contentEdgeInsets = _contentEdgeInsets
} else {
super.imageEdgeInsets = extraImageEdgeInsets
super.titleEdgeInsets = extraTitleEdgeInsets
super.contentEdgeInsets = extraContentEdgeInsets
}
super.layoutSubviews()
}
}
回答by orxelm
A small addition to Riley Avron answer to account locale changes:
Riley Avron 对帐户语言环境更改的回答的一个小补充:
extension UIButton {
func centerTextAndImage(spacing: CGFloat) {
let insetAmount = spacing / 2
let writingDirection = UIApplication.sharedApplication().userInterfaceLayoutDirection
let factor: CGFloat = writingDirection == .LeftToRight ? 1 : -1
self.imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount*factor, bottom: 0, right: insetAmount*factor)
self.titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount*factor, bottom: 0, right: -insetAmount*factor)
self.contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
}
}
回答by Hemang
Swift 4.x
斯威夫特 4.x
extension UIButton {
func centerTextAndImage(spacing: CGFloat) {
let insetAmount = spacing / 2
let writingDirection = UIApplication.shared.userInterfaceLayoutDirection
let factor: CGFloat = writingDirection == .leftToRight ? 1 : -1
self.imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount*factor, bottom: 0, right: insetAmount*factor)
self.titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount*factor, bottom: 0, right: -insetAmount*factor)
self.contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
}
}
Usage:
用法:
button.centerTextAndImage(spacing: 10.0)
回答by Jules
I write code bewlow. It works well in product version. Supprot Swift 4.2 +
我在下面写代码。它在产品版本中运行良好。Supprot雨燕4.2 +
extension UIButton{
enum ImageTitleRelativeLocation {
case imageUpTitleDown
case imageDownTitleUp
case imageLeftTitleRight
case imageRightTitleLeft
}
func centerContentRelativeLocation(_ relativeLocation:
ImageTitleRelativeLocation,
spacing: CGFloat = 0) {
assert(contentVerticalAlignment == .center,
"only works with contentVerticalAlignment = .center !!!")
guard (title(for: .normal) != nil) || (attributedTitle(for: .normal) != nil) else {
assert(false, "TITLE IS NIL! SET TITTLE FIRST!")
return
}
guard let imageSize = self.currentImage?.size else {
assert(false, "IMGAGE IS NIL! SET IMAGE FIRST!!!")
return
}
guard let titleSize = titleLabel?
.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) else {
assert(false, "TITLELABEL IS NIL!")
return
}
let horizontalResistent: CGFloat
// extend contenArea in case of title is shrink
if frame.width < titleSize.width + imageSize.width {
horizontalResistent = titleSize.width + imageSize.width - frame.width
print("horizontalResistent", horizontalResistent)
} else {
horizontalResistent = 0
}
var adjustImageEdgeInsets: UIEdgeInsets = .zero
var adjustTitleEdgeInsets: UIEdgeInsets = .zero
var adjustContentEdgeInsets: UIEdgeInsets = .zero
let verticalImageAbsOffset = abs((titleSize.height + spacing) / 2)
let verticalTitleAbsOffset = abs((imageSize.height + spacing) / 2)
switch relativeLocation {
case .imageUpTitleDown:
adjustImageEdgeInsets.top = -verticalImageAbsOffset
adjustImageEdgeInsets.bottom = verticalImageAbsOffset
adjustImageEdgeInsets.left = titleSize.width / 2 + horizontalResistent / 2
adjustImageEdgeInsets.right = -titleSize.width / 2 - horizontalResistent / 2
adjustTitleEdgeInsets.top = verticalTitleAbsOffset
adjustTitleEdgeInsets.bottom = -verticalTitleAbsOffset
adjustTitleEdgeInsets.left = -imageSize.width / 2 + horizontalResistent / 2
adjustTitleEdgeInsets.right = imageSize.width / 2 - horizontalResistent / 2
adjustContentEdgeInsets.top = spacing
adjustContentEdgeInsets.bottom = spacing
adjustContentEdgeInsets.left = -horizontalResistent
adjustContentEdgeInsets.right = -horizontalResistent
case .imageDownTitleUp:
adjustImageEdgeInsets.top = verticalImageAbsOffset
adjustImageEdgeInsets.bottom = -verticalImageAbsOffset
adjustImageEdgeInsets.left = titleSize.width / 2 + horizontalResistent / 2
adjustImageEdgeInsets.right = -titleSize.width / 2 - horizontalResistent / 2
adjustTitleEdgeInsets.top = -verticalTitleAbsOffset
adjustTitleEdgeInsets.bottom = verticalTitleAbsOffset
adjustTitleEdgeInsets.left = -imageSize.width / 2 + horizontalResistent / 2
adjustTitleEdgeInsets.right = imageSize.width / 2 - horizontalResistent / 2
adjustContentEdgeInsets.top = spacing
adjustContentEdgeInsets.bottom = spacing
adjustContentEdgeInsets.left = -horizontalResistent
adjustContentEdgeInsets.right = -horizontalResistent
case .imageLeftTitleRight:
adjustImageEdgeInsets.left = -spacing / 2
adjustImageEdgeInsets.right = spacing / 2
adjustTitleEdgeInsets.left = spacing / 2
adjustTitleEdgeInsets.right = -spacing / 2
adjustContentEdgeInsets.left = spacing
adjustContentEdgeInsets.right = spacing
case .imageRightTitleLeft:
adjustImageEdgeInsets.left = titleSize.width + spacing / 2
adjustImageEdgeInsets.right = -titleSize.width - spacing / 2
adjustTitleEdgeInsets.left = -imageSize.width - spacing / 2
adjustTitleEdgeInsets.right = imageSize.width + spacing / 2
adjustContentEdgeInsets.left = spacing
adjustContentEdgeInsets.right = spacing
}
imageEdgeInsets = adjustImageEdgeInsets
titleEdgeInsets = adjustTitleEdgeInsets
contentEdgeInsets = adjustContentEdgeInsets
setNeedsLayout()
}
}