Second day tasks:

After the main framework of the project is built, the project can be completed from each module, starting from the simplest module of concern.

  1. Attention page setup
  2. Setting up the login interface
  3. Method extraction and knowledge summary

A. Focus on page construction

Attention page we only do not log in here. Because after logging in, you can see which users or channels you follow.




Login page effect picture

The best way is to set the position of the middle label first, and then determine the position of the image above and the button below according to the position of the middle label. I won’t go into details here, but there is only one point to note. When we want to wrap the text of the label in the XIB, Use the option+ Enter key combination for line breaking. “\n” does not work.




Label a newline

In addition, if the XIB is not created when we create the controller, we need to do two steps to create the association with the previously created controller. The first step:




The first step is to create an association with the controller

The second step:




Create an association with the View

If the XIB is created at the same time as the controller is created, the system will automatically do both for us.

Two. Login interface construction

First of all, it involves the color of the status bar of the login interface. We need to change the color of the status bar to white, so that the method change can be implemented in the controller

- (UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}Copy the code

For more information about changing the color of the status bar, see Status Bar Management

Since landing interface in many places are needed, such as check the attention need to log in, add the attention also need to login first, publish updates to login, the login interface does not belong to any one module, in many places at the same time also want to use it, so it is written in the Other folder, another login interface must be Mode, Once you determine that you need to log in to perform operations, Mode out of the login interface. By observing the login interface, we find that the background image is provided, so we need to use UIImageVIew to set the background image. In addition, we can divide the login interface into three parts, and each part is stored with UIView as the carrier. As long as the controls inside the View are laid out, we only need to manage the position and size of the three views. Convenient for our layout and management.




Login Page Layout

1. Layout of the quick login button

First of all, the two lines for quick login are pictures, you just need to set the frame, the next three quick login lines are obviously buttons, but we know that UIButton defaults to UIImage on the left, titleLabel on the right, so we need to change the default layout to UIImage on top, TitleLabel is down here. Method 1: You can adjust the position of UIImage and titleLabel by setting their contentInset, but this method is tedious and takes a long time to adjust slowly. ContentInset is usually used to simply change the position of content in the control. Not recommended for use here. Method 2: Customize button and rewrite layoutSubviews. If a button is loaded from a storyboard or xiB, the AWeakFromNib method is called. We can set some uniform Settings for the control in AWeakFromNib, and set the position of the content in the control in layoutSubviews.

-(void)awakeFromNib { [super awakeFromNib]; / / button here for some unified set text center self. The titleLabel. TextAlignment = NSTextAlignmentCenter; } -(void)layoutSubviews { [super layoutSubviews]; // Change the imageView and titleLabel positions self.imageView.cl_y = 0; Self. ImageView. Cl_centerX = self. Cl_width * 0.5; self.titleLabel.cl_x = 0; self.titleLabel.cl_width = self.cl_width; self.titleLabel.cl_y = self.imageView.cl_height; self.titleLabel.cl_height = self.cl_height - self.imageView.cl_height; }Copy the code

Note: Remember to call the corresponding method of the parent class. Add constraint on three buttons: You can set the middle button constraint first, and then restrict the space between the three buttons to 0. The distance between the left button and the left side of the screen is 0, and the right button is 0 and the right side of the screen is the same height. Finally, the three buttons are constrained to split the screen width. There are many ways to add constraints, as long as you determine the width and height of the control position can be successful constraints, need to carefully step by step, even if the constraint failure does not matter, delete the re-constraints, as long as a few more try slowly will master.

2. Layout of ❌ number and registered account

The first part of the layout is very simple, there is one note: UIButton when only one image is displayed, it is recommended to use image instead of setting the background image, because the background image will be stretched to a large size depending on the size of the button, and the image will be stretched. The image will not be distorted when set to image, and the button’s click range can be enlarged. So the ❌ option here is to set UIButton’s image, not backgroundImage.

3. Layout of login buttons in the account and password input box

The layout of this part is also very simple, here the image provides the background image of the TextField, so here we first use UIImageView to display the background image, and then add a transparent TextField on the image, so the style of the TextField needs to be blank and invisible




Textfield style selection

In addition, the Type of the login button needs to be set as Custom. If it is System, it will be processed automatically when we press the button as shown below, and the font will be rendered blue automatically




SystemButton

Setting it to Custom will show the background image we set in highlight and will not render the font color.

Set the rounded corner of the button button

self.loginBtn.layer.cornerRadius = 5;
self.loginBtn.layer.masksToBounds = YES;Copy the code

It can also be set by KVC assignment

[self.loginBtn setValue:@5 forKeyPath:@"layer.cornerRadius"];
[self.loginBtn setValue:@YES forKeyPath:@"layer.masksToBunds"];Copy the code

It is also possible to assign values via KVC in xiB




Xib is assigned by KVC

Since the animation effect of switching between existing account and registered account interfaces is required, the two input interfaces are spliced together, as shown in the figure




Login registration splicing

If we want to animate the button, we need to change the constraint between the left side of the view and the left side of the screen, obtain the constraint property, change the distance between the left side of the view and the left side of the screen from 0 to negative one screen width, and of course add the distance between the right side of the view and the left side of the view to 0. Also change the title of the button.

- (IBAction)showLogionOrRegister:(UIButton *)sender { [self.view endEditing:YES]; if (self.leftMargin.constant) { self.leftMargin.constant = 0; [sender setTitle: @ "accounts" forState: UIControlStateNormal]; }else{ self.leftMargin.constant = -self.view.cl_width; [sender setTitle: @ "existing account?" forState: UIControlStateNormal]; } [UIView animateWithDuration:0.5 animations:^{[self.view layoutIfNeeded];}]; }Copy the code

The difficulty here lies in the addition and modification of constraints. Careful modification will succeed, of course, you can also modify the frame of the two views by code to achieve the effect of animation replacement.

Textfield cursor color change and placeholder text color change

First of all, there are four TextFields, each of which needs to set the cursor color and placeholder text color, so we can do this by customizing textField, and then setting awakeFromNib once. Textfield’s cursor color can be set by setting tintColor

self.tintColor = [UIColor whiteColor];Copy the code

Placeholder text color modification method 1: use rich text to modify placeholder text color

NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
attributes[NSForegroundColorAttributeName] = [UIColor whiteColor];
self.attributedPlaceholder = [[NSAttributedString alloc]initWithString:self.placeholder attributes:attributes];Copy the code

Method 2: Rewrite the drawRect method to redraw the station text and change the station text color

-(void)drawPlaceholderInRect:(CGRect)rect { NSMutableDictionary *attributes = [NSMutableDictionary dictionary]; attributes[NSFontAttributeName] = self.font; attributes[NSForegroundColorAttributeName] = [UIColor whiteColor]; // placeholderPoint = CGPointMake(0, (self.cl_height - self. lineHeight)*0.5); [self.placeholder drawAtPoint:placeholderPoint withAttributes:attributes]; // self.placeholder drawInRect:<#(CGRect)#> withAttributes:<#(NSDictionary *)#>}Copy the code

An overlay Label is used to display placeholder text when the tagtag is empty. We can see the internal structure of the TextField in the graphical debugging tool




Internal structure of textField

// UILabel *label = [self valueForKeyPath:@"placeholderLabel"]; // label.textColor = [UIColor whiteColor]; / / or directly set colors [self setValue: [UIColor grayColor] forKeyPath: @ "placeholderLabel. TextColor"].Copy the code

The placeholderLabel is a private placeholderLabel inside the TextField

// Use the runtime to find the private property unsigned int count; Ivar *ivarList = class_copyIvarList([UITextField class], &count); for (int i = 0; i < count; i ++) { Ivar ivar = ivarList[i]; NSLog(@"%s",ivar_getName(ivar)); } free(ivarList);Copy the code

The placeholderLabel can be found using the runtime to print all the properties of the TextField




PlaceholderLabel properties

5. Switch the placeholder text color

The placeholder text color is gray when the TextField is unedited, and white when the TextField is edited




Placeholder text in different states in different colors

Method 1: addTarget Because TextField inherits from UIControl, you can use addTarget to listen for changes in the editing state of textField

[self addTarget:self action:@selector(editingDidBegin) forControlEvents:UIControlEventEditingDidBegin];
[self addTarget:self action:@selector(editingDidEnd) forControlEvents:UIControlEventEditingDidEnd];Copy the code

Then change the placeholder text color in the method

-(void)editingDidBegin
{
[self setValue:[UIColor whiteColor] forKeyPath:@"placeholderLabel.textColor"];
}
-(void)editingDidEnd
{
[self setValue:[UIColor grayColor] forKeyPath:@"placeholderLabel.textColor"];
}Copy the code

Using a proxy is risky, and an error occurs when we set the proxy for textField again in the controller

textField.delegate = self; # pragma mark - (void) textFieldDidBeginEditing: (textField UITextField at *) {/ / edit} - (void)textField didendediting :(UITextField *)textField {// finish editing}Copy the code

Method 3: Use notifications

/ / object: the self object UITextFieldTextDidBeginEditingNotification notice call self (listeners) editingDidBegin method [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(editingDidBegin) name:UITextFieldTextDidBeginEditingNotification object:self]; [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(editingDidEnd) name:UITextFieldTextDidEndEditingNotification object:self];Copy the code

Notification also has a way of writing the action to be performed directly in a block

// object:self sends a notification with the name of the block, and executes the code inside the block. You can modify the thread in which the block is executed. Release self.observer = [[NSNotificationCenter defaultCenter]addObserverForName:UITextFieldTextDidBeginEditingNotification object:self queue:[NSOperationQueue MainQueue] usingBlock:^(NSNotification * _Nonnull note) {// Listen to the notification to execute the operation}];Copy the code

Notification needs to be removed

-(void)dealloc { [[NSNotificationCenter defaultCenter]removeObserver:self]; / / use the block removed in a process monitoring method to monitor the [[NSNotificationCenter defaultCenter] removeObserver: self. The observer]; }Copy the code

Method 4: Rewrite the becomeFirstResponder and resignFirstResponder methods of UITextField

// call time: becomeFirstResponder (start editing \ pop up keyboard \ get focus) - (BOOL)becomeFirstResponder {return [super becomeFirstResponder]; } // call time: do not do first responder (end edit, exit keyboard, lose focus) - (BOOL)resignFirstResponder {return [super resignFirstResponder]; }Copy the code

6. Some events are added and implemented

Now that the basic layout of the interface is complete, it’s time to add click events to the buttons. Click the ❌ button to log in to the interface

/ / close button click event - (IBAction) closeBtn {[self dismissViewControllerAnimated: YES completion: nil]; }Copy the code

Click on the blank area to exit the textField as the first responder

// (void) Touch Began:(NSSet *) Touches withEvent:(UIEvent *) Event {[self.view endEditing:YES]; }Copy the code

Three. Method extraction and some knowledge summary

1. Uitextfield adds categories and directly changes the color of station text.

As mentioned earlier, in order to avoid repeatedly setting the cursor color and placeholder text color for textField, we use a custom TextField, which can be set uniformly in awakeFromNib. In addition, set the placeholder text color, which may be frequently used in other modules or other projects in the future, so add classification to textField to make the setting of placeholder text more convenient.

#import "UITextField+CLExtension.h" static NSString * const CLPlaceholderColorKey = @"placeholderLabel.textColor"; @implementation UITextField (CLExtension) -(void) setmetagcolor :(UIColor *) metagcolor { The overlay label is empty when the placeholderLabel is empty when the overlay label is empty when the overlay label is empty when the overlay label is empty when the overlay label is empty when the overlay label is empty // We need to determine whether the placeholder has a value, if not, we need to create it in advance. // We can leave the current placeholder in the placeholder. When the current placeholder is empty, we will save it and set it to @" ", and then the placeholder color will also be set. // NSString *oldplaceholder = self.placeholder; // NSString *oldplaceholder = self.placeholder; // NSString *oldplaceholder = self.placeholder; // self.placeholder = @" "; // self.placeholder = oldplaceholder; Placeholder label if (self.placeholder. Length == 0) {self.placeholder = @" "; self.placeholder = nil; } // return the value of meas color as an empty placeholdervalue GRB value meas color = [UIColor colorWithRed:0 green:0 Alpha blue: 0.0980392, 0.22]; } [self setValue:placeholderColor forKeyPath:CLPlaceholderColorKey]; } -(UIColor *)placeholderColor { return [self valueForKeyPath:CLPlaceholderColorKey]; }Copy the code

At this point it’s very easy to set the color of the placeholder text

Textfield. TintColor = [UIColor whiteColor]; textfield.placeholderColor = [UIColor grayColor];Copy the code

2. Supplement some knowledge points

Difference between Frame and bounds First we need to understand that each control consists of a rectangular box and content. By default, the rectangle and the content overlap

  • frame
    • Calculates the position and size of the control’s own rectangular box with the upper-left corner of the parent control’s content as the coordinate origin
  • bounds
    • With the upper left corner of the control’s own content as the origin of coordinates, calculate the position and size of the control’s own rectangular box

NSAttributensstring and NSMutableAttributensstring simple practical NSAttributensstring string with attribute inheritance NSObject, consists of two parts

  • Text content: NSString

  • Text attributes:

    • Text color NSForegroundColorAttributeName
    • Font size NSFontAttributeName
    • The underline NSUnderlineStyleAttributeName
    • The background color NSBackgroundColorAttributeName
@property(Nullable, nonatomic,copy) NSAttributedString *attributedPlaceholderCopy the code
NSMutableDictionary *attributes = [NSMutableDictionary dictionary]; attributes[NSForegroundColorAttributeName] = [UIColor darkGrayColor]; / / initializes the textfield. AttributedPlaceholder = [[NSAttributedString alloc] initWithString: self. The placeholder attributes:attributes];Copy the code
NSMutableAttributensstring inherited from NSAttributensstring

NSMutableAttributensstring common way

// Set the properties of the same range. - (void)setAttributes (nullable NSDictionary *)attrs range (NSRange)range; - (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range; - (void)addAttributes:(NSDictionary *)attrs range:(NSRange)range;Copy the code

Generally speaking, as long as it involves the display text, you can use rich text to do some display optimization. Let’s look at some examples of use

UILabel *label = [[UILabel alloc] init]; label.frame = CGRectMake(100, 100, 200, 25); label.backgroundColor = [UIColor redColor]; label.font = [UIFont systemFontOfSize:14]; [self.view addSubview:label]; / / by mixed NSMutableAttributedString * attributedText = [[NSMutableAttributedString alloc] init]; NSAttributedString *first = [[NSAttributedString alloc] initWithString:@" hello "]; [attributedText appendAttributedString:first]; NSTextAttachment *attachment = [[NSTextAttachment alloc] init]; attachment.image = [UIImage imageNamed:@"header_cry_icon"]; CGFloat lineH = label.font.lineHeight; Attachment. Bounds = CGRectMake(0, - ((label.xmg_height - lineH) * 0.1-1), lineH, lineH); / / attachment packing into a text attribute NSAttributedString * second = [NSAttributedString attributedStringWithAttachment: attachment]; [attributedText appendAttributedString:second]; NSAttributedString *third = [[NSAttributedString alloc] initWithString:@" ha ha ha "]; [attributedText appendAttributedString:third]; label.attributedText = attributedText;Copy the code
UILabel *label = [[UILabel alloc] init]; // set the attribute text NSString *text = @" hello \n hahaha "; NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text]; [attributedText addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:10] range:NSMakeRange(0, text.length)]; [attributedText addAttribute:NSFontAttributeName value:[UIFont boldSystemFontOfSize:13] range:NSMakeRange(3, 3)]; label.attributedText = attributedText; // Other Settings label.numberOfLines = 0; label.textAlignment = NSTextAlignmentCenter; label.frame = CGRectMake(0, 0, 100, 40); [self.view addSubview:label]; self.navigationItem.titleView = label;Copy the code

4. To summarize

Today’s task has been completed, we have completed the construction of the attention and login interface, and made some details on the login interface. The effect of the second day is as follows




Second day effect

Today’s main content is some processing of textfield, pay attention to textfield more detailed knowledge can see ios-ui textfield comprehensive parsing

Welcome to point out any mistakes in the article. I am XX_CC, a long grown but not enough of a guy.