Many times, the system default UIButton can not meet the demand, each time is a lot of information, and finally in the most complex way to modify the button title and the location of the picture, today, take some time to comb this knowledge ...
UIButton default layout is: Title in the right, image on the left;
Many times we need is the title on the left, or the title below, then need to adjust the position of the UIButton Titlelabel and ImageView, check a lot of information, or fragmented introduction, or is particularly complex implementation; After a period of study, Here to summarize the way of implementation;
One is to set the following two properties of UIButton:
@property (nonatomic) uiedgeinsets titleedgeinsets; Default is Uiedgeinsetszero@property (nonatomic) uiedgeinsets imageedgeinsets; Default is Uiedgeinsetszero
Another is that the custom button, inherited from UIButton, overrides the following two methods of UIButton:
-(CGRect) Titlerectforcontentrect: (CGRect) contentrect;-(CGRect) Imagerectforcontentrect: (CGRect) ContentRect;
Here are two ways to implement these:
One, set properties
1. Change to title on left, picture in right style
The type of the property is Uiedgeinsets, which is a struct:
typedef struct UIEDGEINSETS { cgfloat top, left, bottom, right; Specify amount to inset (positive) for each of the edges. Values can is negative to ' outset '} uiedgeinsets;
Represents the offset of the top left and bottom right, explaining the meaning of these four quantities:
Top: When it is positive, it is shifted downward and is shifted upward when negative.
Left: The right offset for positive numbers, and a negative number for the time of the shift.
Bottom: When a positive number is shifted upward, the negative is shifted downward;
Right: When the positive number is shifted to the left, and the negative number is shifted to starboard;
When you set these two properties for UIButton, the first question you encounter is what is the offset set to? A lot of the use of this method is fixed value, when the button frame changes, need to change a lot of places, see a little foggy;
After some research, it is found that there are some common things that can be used:
The first thought was UIButton's title Titlelabel frame and ImageView frame, so get the size of Titlelabel and ImageView first:
Cgsize titlesize = button.titleLabel.bounds.size; Cgsize imageSize = button.imageView.bounds.size;
Then set the properties of the UIButton:
Button.imageedgeinsets = Uiedgeinsetsmake (0,titlesize.width, 0,-titlesize.width); button.titleedgeinsets = Uiedgeinsetsmake (0,-imagesize.width, 0, ImageSize.Width);
Because the default value for both of these properties is 0, the offset is set to 0 in a direction that does not need to be offset, so how do you know which direction needs to be offset, and which direction does not need to be offset? In fact, it's very simple, just to look carefully, the offset before (the system default layout) and after the offset (you want
For Image: Moved from the left to the right, we can know, the upper and lower, the left shift, that is, the image of the leftmost and change;
For the title: moved from the right to the left, the same is the same up and down, the left side of the offset, that is, the title of the Ieft and right changes;
The following explains the meaning of the direction offset setting that needs to be changed:
Because to move the image to the right of the button, you need to move to the right, so the offset from the left edge of the imageedgeinsets is set to the width of the caption, namely: Titlesize.width, the right offset is also titlesize.width, But it should be negative, the other direction does not move, directly set to the default value of 0;
Similarly, the title needs to be moved to the left, and you need to set the width of the image with a negative offset from the left edge of the titleedgeinsets, that is:-imagesize.width
Thus, at this point, the title distance from the right edge of the offset is not 0, but should be the width of the image, that is: imagesize.width;
This is done, but the result seems to be less than ideal:
After careful search, we find that the Titlesize is 0:
Looked up some information, did not find the relevant explanations, temporarily did not know what the reason, if you know, also please leave a message to inform, thank!
However, by accident, as long as you use the Titlelabel and ImageView of the button once before acquiring the titlesize, you can get to his size, set the Titlelabel and ImageView any of the properties are OK, If you don't need to set these properties, you can set the background color to match the button as I do (just to use it one time in advance):
Button.titleLabel.backgroundColor = Button.backgroundcolor;button.imageview.backgroundcolor = Button.backgroundcolor;
PS: Although this can get to titlesize, but more such an operation, it is not normal, if you have a better way to get, also please message to inform, thanks!!
After this setup, the basic ability to implement the requirements, but there is a gap between the child controls, here I set the width of 1 pixels:
CGFloat interval = 1.0;
Then set the two properties of the button:
Button.imageedgeinsets = Uiedgeinsetsmake (0,titlesize.width + interval, 0,-(titlesize.width + interval)); Button.titleedgeinsets = Uiedgeinsetsmake (0,-(imagesize.width + interval), 0, imagesize.width + interval);
The effect is as follows:
Will find, almost the same as the system default;
The final implementation of the complete setup (mainly the time to get the size) is:
Button.titleLabel.backgroundColor = Button.backgroundcolor;button.imageview.backgroundcolor = button.backgroundcolor;//Titlelabel and ImageView are used once to get titlesize cgsize titlesize correctly Button.titleLabel.bounds.size; Cgsize imageSize = button.imageView.bounds.size; CGFloat interval = 1.0; Button.imageedgeinsets = Uiedgeinsetsmake (0,titlesize.width + interval, 0,-(titlesize.width + interval)); Button.titleedgeinsets = Uiedgeinsetsmake (0,-(imagesize.width + interval), 0, imagesize.width + interval);
Eventually:
2. Change to, picture on, title in next style
The process is basically the same, but at the end of the last setting, the main setup code is given here:
Button.titleLabel.backgroundColor = Button.backgroundcolor;button.imageview.backgroundcolor = Button.backgroundcolor; Cgsize titlesize = button.titleLabel.bounds.size; Cgsize imageSize = button.imageView.bounds.size; CGFloat interval = 1.0; [Button Setimageedgeinsets:uiedgeinsetsmake (0,0, Titlesize.height + interval,-(titlesize.width + interval)]; [Button Settitleedgeinsets:uiedgeinsetsmake (imagesize.height + interval,-(imagesize.width + interval), 0, 0)];
:
At the time of setting the offset, the error is still some, after testing, the best solution is that the button size setting, to be just right to allow the title and picture, for the pursuit of perfect person, you can modify the offset parameters;
For this method, I wrote a UIButton Category:demo address, the inside of the class can be directly used, simple call a method can be;
Second, by customizing the button
The method, by customizing a button, inherits from UIButton, and then overrides the method:
-(CGRect) Titlerectforcontentrect: (CGRect) contentrect;-(CGRect) Imagerectforcontentrect: (CGRect) ContentRect;
For these two methods, some of the online introduction really had to spit groove, vague; later, according to individual attempts, personal understanding is: The method parameter Contentrect, that is, the content of the frame, its value and button bounds is the same, This parameter allows you to get the size of the current button, the return value is the CGRect type, which is the absolute coordinate value of the title or image in the button, in other words, this returns an absolute coordinate, that is, the absolute layout of the button's child control on the button, Here you can return a dead frame (found using this method is also written dead frame), but note, do not exceed the range of contentrect;
One thing to note: These two methods are not only called once, will be called multiple times, as long as the button's title change, will call this method, the last call, the return frame value, is the final layout of the frame, so, here, you can get the button by the title, Dynamically modify its frame to make the title and image display compact;
Now that you understand these two methods, start using it:
1. Title on the left, image on the right
This layout is generally different than the width of a lot of tall, so, here I use the height of the button to set the height of ImageView and Titlelabel, namely:
CGFloat inteval = cgrectgetheight (contentrect)/8.0; Set the width height of the picture to 3/4 of the button height; CGFloat Imageh = cgrectgetheight (contentrect)-2 * inteval;
This interval can be modified according to their own needs;
Then set the ImageView frame:
CGRect rect = CGRectMake (Cgrectgetwidth (contentrect)-Imageh-inteval, Inteval, Imageh, Imageh);
That
-(CGRect) Imagerectforcontentrect: (CGRect) contentrect { CGFloat inteval = cgrectgetheight (contentRect)/8.0; Sets the width height of the picture as the 3/4 of the button height; CGFloat Imageh = cgrectgetheight (contentrect)-2 * inteval; CGRect rect = CGRectMake (Cgrectgetwidth (contentrect)-Imageh-inteval, Inteval, Imageh, Imageh); return rect;
Below to set the Titlelabel frame:
-(CGRect) Titlerectforcontentrect: (CGRect) contentrect { CGFloat inteval = cgrectgetheight (contentRect)/8.0; Sets the width height of the picture as the 3/4 of the button height; CGFloat Imageh = cgrectgetheight (contentrect)-2 * inteval; CGRect rect = CGRectMake (Inteval, Inteval, Cgrectgetwidth (contentrect)-Imageh-2*inteval, Cgrectgetheight (contentRect )-2*inteval); return rect;
:
The advantage of this setup is that you can manually control the frame of the Titlelabel and ImageView, but the disadvantage is that you cannot set the frame size according to the size of the picture's scale and title string as the system does.
When the button frame can contain the title and image well, the effect is almost the same, when the button's frame does not fit the difference is obvious:
As can be seen, the main difference is: The system by default can dynamically modify the child control frame, although the display effect is not ideal;
2. Title at bottom, image on top
The idea is basically the same, here directly to the Setup code:
-(CGRect) Imagerectforcontentrect: (CGRect) contentrect { CGFloat inteval = cgrectgetwidth (contentrect)/16.0; Inteval = MIN (Inteval, 6); Sets the width height of the picture to be the 7/8 of the button width; CGFloat Imagew = cgrectgetwidth (contentrect)-2 * inteval; CGRect rect = CGRectMake (Inteval, Inteval, Imagew, Imagew); return rect;
-(CGRect) Titlerectforcontentrect: (CGRect) contentrect { CGFloat inteval = cgrectgetwidth (contentrect)/16.0; Inteval = MIN (Inteval, 6); Sets the width height of the picture to be the 7/8 of the button width; CGFloat Imagew = cgrectgetwidth (contentrect)-2 * inteval; CGRect rect = CGRectMake (0, inteval*2 + imagew, Cgrectgetwidth (Contentrect), Cgrectgetheight (contentrect)-3*inteval-i MAGEW); return rect;
:
Here is a note: is the title of the alignment, the above is set the center alignment, the system default is left, when to change this setting?
I did this because I added a custom attribute:
#import <uikit/uikit.h>typedef Ns_enum (nsinteger,lzrelayoutbuttontype) { lzrelayoutbuttontypenomal = 0,//default lzrelayoutbuttontypeleft = 1,//title in left Lzrelayoutbuttontypebottom = 2,//title in the next}; @interface Lzrelayoutbutton:uibutton@property (assign,nonatomic) lzrelayoutbuttontype Lztype; @end
I rewrote its setter method:
-(void) Setlztype: (Lzrelayoutbuttontype) lztype { _lztype = Lztype; if (lztype! = lzrelayoutbuttontypenomal) { self.titleLabel.textAlignment = Nstextalignmentcenter; }}
This way of setting, I wrote a Demo:github address, the inside of the custom button can be used directly, if it is helpful to you, also please star support, thank!!!
Summary: The above two methods can realize the effect of re-layout UIButton sub-control, each has advantages and disadvantages:
The first way, you need to set the exact offset, but some of the amount is not available, can only be adjusted when used, especially when the title at the bottom, the total feeling image of the left and right distance button left and right gap is inconsistent;
The second way, the control of the frame is more free, it is necessary to pay attention to the interval control, the use of this way there is no first way problem;
Whether it's the system default or the one we've modified, the button's frame setting is important, and the inappropriate frame makes the button look uncomfortable ...
The distance between the picture and text inside the IOS button