This article was transferred from Jian Shu 2016.09.04 14:35:01

# UIButtonRelated attributes of

UIButton provides methods to set title and image, default is image on the left and text on the right. The diagram below:

During development, we often have to adjust to text on the left and picture on the right, or text on top and picture on bottom.

EdgeInsets are also provided to set the position of images and text

@property(nonatomic)          UIEdgeInsets contentEdgeInsets UI_APPEARANCE_SELECTOR; // default is UIEdgeInsetsZero
@property(nonatomic)          UIEdgeInsets titleEdgeInsets;                // default is UIEdgeInsetsZero
@property(nonatomic)          UIEdgeInsets imageEdgeInsets;                // default is UIEdgeInsetsZero
Copy the code

Tip:UI_APPEARANCE_SELECTORThe attributes of the tag are customizable through the appearance proxy.

So we can adjust the relative position of the image and text by setting titleEdgeInsets and imageEdgeInsets;

# Let’s seeUIEdgeInsetsThe interpretation of the

  1. type

    typedef struct UIEdgeInsets {
    
        CGFloat top, left, bottom, right;  // specify amount to inset (positive) for each of the edges. values can be negative to 'outset'
    
    } UIEdgeInsets;
    Copy the code
  2. Set each value meaning

    //UIEdgeInsetsMake(<#T##top: CGFloat##CGFloat#>, <#T##left: CGFloat##CGFloat#>, <#T##bottom: CGFloat##CGFloat#>, <#T##right: CGFloat##CGFloat#>)
    testBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 10, 40, 10); //10 means that the left border has moved 10 to the right (similarly -10 means that the left border has moved 10 to the left) //40 means that the bottom border has moved up 40 //10 means that the right border has moved 10 to the left (similarly -10 means that the right border has moved 10 to the right)Copy the code

    In short: the positive values of these parameters are the corresponding distance to move in the opposite direction (for example, a positive value for top means move down, a negative value for move up) so that we can easily set the desired style outside the UIButton

# start implementing

Let’s now pull out the relevant Settings and make an extension method (below, set the text on the left and the image on the right).

1. Create a new swift file called Button_Extension and add the following code;

import UIKit

extension UIButton {
    /// Set text to left and image to right. The default spacing is' 0.0 '
    func setupImageAtRight(space: CGFloat = 0.0) {
        / * 1 * /
        DRPrint("Get imageWidth")
        guard letimageWidth = imageView? .frame.size.widthelse {
            DRPrint("noImage")
            return
        }
        / * 2 * /
        DRPrint("Get titleWidth")
        guard lettitleWidth = titleLabel? .frame.size.widthelse {
            DRPrint("noTitle")
            return
        }

        //(Note: 'button' does not act as' navigationItem.titleView 'is the default' titleLabel 'and' imageView 'have a gap between the boundary)
        titleEdgeInsets = UIEdgeInsetsMake(0.0, -(imageWidth + space * 0.5), 0, imageWidth + space * 0.5)
        imageEdgeInsets = UIEdgeInsetsMake(0.0, titleWidth + space * 0.5.0.0, -(space * 0.5 + titleWidth))
        // Open the comment to see that the normal 'button' default 'titleLabel' and 'imageView' distance boundary is' 0 '
        //backgroundColor = UIColor.greenColor()}}Copy the code

The above code is all operations, but the first encapsulation put /*2*/ before /*1*/ and never got the right effect.

# Doubt & Clarification

Here in question: Why is titleWidth not 0.0 when titlelabel. text and titlelabel. font are available when titlelabel. font is available when titleWidth is available when imageWidth is available , the correct titleWidth can be obtained?

The study found that:

Discovered by customizing a DRButton rewrite -LayoutSubViews method, calling imageView? TitleLabel?. Frame does not call -layoutSubviews, so getting the titleWidth first does not get the correct value 0.0.

You can also write it yourself

import UIKit

class TestBtn: UIButton {

    override func layoutSubviews(a) {
        super.layoutSubviews()
        DRPrint("button.layoutSubiews")}}Copy the code

Try the printout

  1. First get the print result of imageWidth

    Button_extension.swift-setupImageAtRight-14: get imageWidthTestBtn.swift-layoutSubviews()-15:button.layoutSubiews
    TestBtn.swift-layoutSubviews()-15:button.layoutSubiews
    Button_extension.swift-setupImageAtRight-19: get titleWidthTestBtn.swift-layoutSubviews()-15:button.layoutSubiews
    TestBtn.swift-layoutSubviews()-15:button.layoutSubiews
    Copy the code
  2. Get the printed titleWidth first

    Button_extension.swift-setupImageAtRight-14: get titleWidthButton_extension.swift-setupImageAtRight-19: get imageWidthTestBtn.swift-layoutSubviews()-15:button.layoutSubiews
    TestBtn.swift-layoutSubviews()-15:button.layoutSubiews
    TestBtn.swift-layoutSubviews()-15:button.layoutSubiews
    TestBtn.swift-layoutSubviews()-15:button.layoutSubiews
    Copy the code

# call

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad(a) {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        addButton()
        //addButton("testTitle")
        //addButton("testLongLongTitle")
    }

    override func didReceiveMemoryWarning(a) {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.}}// MARK:- Set up UI
extension ViewController {
    func addButton(title: String = "78987fded") {
        view.backgroundColor = UIColor.lightGrayColor()
        let button = TestBtn()
        button.setTitle(title, forState: .Normal)
        button.setImage(UIImage(named: "navigationbar_arrow_down"), forState: .Normal)
        button.setImage(UIImage(named: "navigationbar_arrow_up"), forState: .Selected)
        //button.setTitleColor(UIColor.grayColor(), forState: .Normal)button.titleLabel? .font =UIFont.systemFontOfSize(14);
        button.sizeToFit()
        button.center = view.center
        // Set the position of the image and caption
        button.setupImageAtRight()
        button.backgroundColor = UIColor.greenColor()
        view.addSubview(button)
    }
}
Copy the code

Effect:

Complete code with comments at the end

/// Set the image to the right with the default spacing of '0.0'
func setupImageAtRight(space: CGFloat = 0.0) {
    // First method: adjust by calculating the length of the string
    /* let titleString = currentTitle! as NSString let size = CGSizeMake(CGFloat(MAXFLOAT), bounds.size.height) let atttibutes = [NSFontAttributeName:titleLabel!.font] let titleWidth = titleString.boundingRectWithSize(size, options: .UsesLineFragmentOrigin, attributes: atttibutes, context: nil).size.width */
    /* where: Why is' titleWidth 'always not' 0.0 'when' titlelabel. text 'and' titlelabel. font 'are available, but when' imageWidth 'is available first, TitleWidth: 🐷 find the correct 'titleWidth' by customizinga 'DRButton' rewrite '-layoutSubviews' method and calling' imageView? Frame will call '-layoutSubviews' first to get' imageWidth ', while 'titleLabel?. Frame' will not call '-layoutSubviews', so getting' titleWidth 'first will not get the correct value, but will get' 0.0 ` * /
    // Adjust by getting 'titleLabel' width
    guard letimageWidth = imageView? .frame.size.widthelse {
        return
    }
    guard lettitleWidth = titleLabel? .frame.size.widthelse {
        return
    }
    /* DRPrint("titleWidth = \(titleWidth)") DRPrint("bounds.size = \(bounds.size)") DRPrint(" titlelabel.frame = \(titleLabel! .frame)") DRPrint(" imageView.frame = \(imageView! .frame)") DRPrint(titleLabel?.frame.size.width) */

    /* testBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 10, 40, 10); 0 indicates that the top is 0. 10 indicates that the left border is moved 10 to the right (similarly, -10 indicates that the left border is moved 10 to the left). 40 Indicates that the bottom border is moved up 40 Move the corresponding distance in the opposite direction */
    titleEdgeInsets = UIEdgeInsetsMake(0.0, -(imageWidth + space * 0.5), 0, imageWidth + space * 0.5)
    imageEdgeInsets = UIEdgeInsetsMake(0.0, titleWidth + space * 0.5.0.0, -(space * 0.5 + titleWidth))
}
Copy the code
// MARK:- Simple print
func DRPrint<T>(message: T,file: NSString = #file,lineNum: Int = #line,funcName:String = #function) ->  Void{#if DEBUG
    let fileName = (file as NSString).lastPathComponent
    print("\(fileName)-\(funcName)-\(lineNum):\(message)")
    #endif
}
Copy the code

If you can’t print out information, please#ifStatement to remove