iOS development-How to customize controls and how to care

Source: Internet
Author: User

In a way that uses pure code
  1. In general, our custom classes inherit from UIView, first adding the required child controls to the view in the initWithFrame: method. Note that this is only added to the view, and the dimensions of each child control are not set.

    Why do I do this in initWithFrame: method instead of Init method?

    Because a custom class is created using pure code, it may be created using the init method at a later time, or it may be created using the initWithFrame: method, Either way, the initWithFrame: method is called at the end. Creating child controls in this method guarantees that either method can be created successfully.

    Why do you want to add a child control to a view without setting the size in the initWithFrame: Method?

    As previously mentioned, both methods are eventually called to initWithFrame: method. If created using the init method, then the view frame may be indeterminate:

    cylview *view = [[ Cylview alloc] Init];view.frame = CGRectMake (0, 0, 100, 100) ...      

    If this is the case, the frame is indeterminate in the init method, and if you set the size in the initWithFrame: method, the dimensions of each child control will be 0. Because the frame of the view is not set yet. (You can see that it was set after the INIT message was sent)

    So we should ensure that the frame of view is set to the size of its child controls.

  2. layoutSubviewsthis can be achieved in the method. This method is called when the first view__ will show __, and then when the size of the view (not the position) changes.

    So it's a good idea to initWithFrame: create a child control in a method, noting that at this point the child control might be just a local variable, so if you want layoutSubviews to access it, you typically need to create the corresponding property of the child control to point to it.

    @property (Nonatomic,Weakuibutton *button; //note that it is possible to use weak here, because the button has been added to the self.view.subviews array. ...-(instancetype) initWithFrame: (cgrect) frame{if (self = [super Initwithframe:frame]) { UIButton *button = ... //Create a button [button settitle: ...] //set the properties of the button [self.view Addsubview:button]; //adds a button to the view, does not set the size self//will Self.button point to this button to ensure access to Layoutsubviews //Other child controls similarly}}            

    This allows us to layoutSubviews access the child controls in, setting the dimensions of the child controls, because the frame of the view is now determined.

    - (void)layoutSubviews {    [super layoutSubviews]; // 注意,一定不要忘记调用父类的layoutSubviews方法!      self.button.frame = ... // 设置button的frame self.label.frame = ... // 设置label的frame}

    After the steps above, you can implement a custom control.

  3. At the same time, we also want to be able to give our custom control data to let it display.

    In general, you will first convert the resulting data into model data , and then pass the custom control to the model data for display.

    So in this header file of the custom control, we need to set up the interface to get the data that someone else passed in. For example, we currently have a book class that has a Name property for the display name, and a like property to show how many people prefer it. Now we need to display the name of book to the label child control of the custom class, displaying the like of book to the button child control of the custom class.

    First, in the header file of the custom class:

    ...@property (nonatomic, strong) Book *book;...

    Here we receive a book as the data that needs to be displayed.

    Then rewrite the book's setter method in the custom implementation file:

    - (void)setBook: (Book *)book {    _book = book; // 注意在这个方法中,不写这句也是没有问题的,因为在下面的语句使用的是book而非self.book或_book,但是如果在其他的方法中也想要访问book这个属性,那么就需要写上,否则self.book或_book会一直是nil(因为出了这个方法的作用域,book就销毁了,如果再想访问需要有其他的引用指向它)。所以建议,要写上这句。 [self.button setTitle: book.like forState...]; self.label = book.name;}

    Thus, when we want to display data using a custom class:

    // 在控制器类的某个方法中:Book *book = self.books[index]; // 这里指拿到books这个数据中的某个数据用于显示CYLView *view = [[CYLView alloc] initWithFrame: ...];[self.view addSubview: view]; // 将自定义类加到view中view.book = book; // 设置book的数据,此时会调用setter方法给各个控件设置数据

    This enables the ability to implement custom classes to display data. And the child control is encapsulated in the custom, the controller only need to create a custom class and give it data, without worrying about how the class inside is designed, what controls, how the data is arranged, so when the requirements change, our controller may be completely unchanged, just change the internal of the custom class can be.

    ?

Summarize:

    1. initWithFrame:To add child controls to the.

    2. layoutSubviewsSet the child control in frame.

    3. Set the data interface externally, overriding the setter method to set the display data to the child controls.

    4. Use the Init/initwithframe: Method inside the view controller to create a custom class and assign a value to the frame of the custom class.

    5. Assign values to the data interfaces exposed by the custom class.

      ?

Using the Xib method
  1. Using Xib, you can omit initWithFrame: and layoutSubviews add child controls and set the size of the child controls, as well as the frame that sets the view inside the view controller, because the dimensions of adding child controls and setting child controls, and the dimensions of the entire view, are already completed in Xib. (Note that the location of the entire view is not set yet, it needs to be set inside the controller.) )

  2. We just need to provide the data interface externally, and rewrite the setter method to display the data.

  3. Note that you want to set the class in Xib to our custom class, so that the custom class is created instead of the default parent class.

  4. Of course, using xib this way is required to load the Xib file. There are two ways to load a Xib file:

    //first Method (more commonly) cylview *view = [[[ nsbundle Mainbundle] loadnibnamed:@ "CYLView" Owner:nil options:nil] firstobject]; //Cylview represents Cylview.xib, representing Cylview files of this class. This method returns a Nsarray, we take the first object or the last (because the array has only one cylview and no other objects) is the cylview that needs to be loaded. //the second method uinib *nib = [UINib Nibwithnibname:@ "Cylview" Bundle:nil]; Nsarray *objectarray = [nib Instantiatewithowner:nil options: NIL]; Cylview *view = [Objectarray firstobject];            
  5. The controls in the Xib file can be wired in Cylview by Control-drag, so that the controls can be accessed by Cylview. (You can assign values to these controls in the setter method to display the data)

Summarize:

    1. Create a Xib, drag the controls you want to add in the Xib, and set the dimensions. And to set this xib class to our custom classes.

    2. The control in Xib is associated with a custom class by means of Iboutlet.

    3. Set the data interface externally, overriding the setter method to set the display data to the child controls.

    4. Loading the Xib file inside the View controller class will give you the corresponding class (you don't need to set the frame of the custom class here, because Xib already has the entire view size.) You only need to set the location. ), you can then assign values to the data interfaces of the class.

      ?

Add
  1. If you create a control by using code, you must call the method when you create it, and if you create the initWithFrame: control using Xib/storyboard, you must call the method when you create it initWithCoder: .

  2. Accesses the property in Initwithcoder: , such as Self.button , and finds it nil because the custom control is initializing , Self.button may not have been assigned a value (Self.button is a iboutlet,iboutlet essentially equivalent to Xcode finding this corresponding property, and then UIButton button = ..., [self.view Addsubview:button] Such operations, and all of this is equivalent to cylview view = [[Cylview alloc] Initwithcoder:nil] method after the execution. The code above is equivalent to using the code to implement Xcode loading Cylview in storyboard, so it is possible that initialization in this method will fail.

    It is recommended that additional actions be initialized in the awakefromnib method. because awakefromnib is called after initialization, accessing the property (Iboutlet) In this method guarantees that it is not nil.

  3. In fact, using Xib to create a custom control, we can encapsulate the process of loading xib into a custom class, exposing only one initialization method so that the outside world does not know how the custom control is created internally.

    For example, provide a class factory method in CYLView.h:

    + ( Instancetype) viewwithbook: (book * ) book;      

    Then implement this method in CYLVIEW.M:

    + (instancetype) Viewwithbook: (book *) book{CYLView *view = [[[ nsbundle Mainbundle] loadnibnamed: NSStringFromClass ( Span class= "Hljs-keyword" >self) Owner: nil opetions: nil] Firstobject]; View.book = Book; return View;}         

    So that the outside world just use Viewwithbook: method to pass in a book, you can create a Cylview object, and how to create it, only Cylview know.

  4. If we want to initialize some values either by code or by Xib, then we can draw the initialized code into a method and initWithFrame: invoke it separately in the methods and methods of the method awakeFromNib .

    about why the awakeFromNib front has been said:

    Custom controls created by Xib need to set the Iboutlet property, although the method is called, initWithCoder: but the Iboutlet property is not set when calling this method, so accessing the property in this method will be nil. In the awakeFromNib middle, the Iboutlet has been initialized, so initialization in this method will not fail.

    If you pass initWithFrame: a method that describes a custom control that was created through code, its properties are not iboutlet, so a property that does not have an unfinished iboutlet is not initialized. Therefore, initWithFrame: it is no problem to access some properties in the method. It should be noted, however, that if a init custom control created by a method also invokes a initWithFrame: method, it is not assigned at this time (the size of the self.frame control is not set when the method is dropped), and if used in this case self.frame there is no value. Note the situation.



Wen/foreveryoung21 (author of Jane's book)
Original link: http://www.jianshu.com/p/7e47da62899c
Copyright belongs to the author, please contact the author to obtain authorization, and Mark "book author".

iOS development-How to customize controls and how to care

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.