IOS Development

MacOS Programming Tutorial: Utilizing Customized Views and Cocoa Controls

Good functions have wonderful consumer interfaces and the possibilities of constructing a wonderful interface totally inside views of view controllers in storyboard information are weak. Typically, advanced views are designed in separate Xib (Interface Builder) information. Realizing how you can load content material from customized views is a compulsory talent that each macOS developer will need to have. The sort of separation additionally facilitates upkeep, extensibility, and testing of the appliance. Within the earlier MacOS tutorial, we didn’t create any customized views as a result of the main target was on different subjects, however now could be the time to debate them.

The answer we’ll implement as we speak to load customized views will likely be reusable code that may be utilized to any macOS undertaking. Because of this when leaving as we speak, you’ll get a small instrument that may automate and velocity up your work when creating your individual functions.

As well as, on this tutorial we’ll evaluate a few of the widespread Cocoa instructions discovered on macOS, and focus on their properties, how they are often configured, and the way we will acquire or outline them graphically. . in code. I wager you can see some fascinating issues amongst them.

With out additional ado, let's begin by having a look at our demo app.

The demonstration software

Not like earlier tutorials, the demonstration software that we are going to be creating as we speak is not going to be practical. As a substitute, it’ll solely current the consumer interface that will likely be designed in customized views. To be extra particular, we’ll create an software that, in a hypothetical state of affairs, can be utilized by a technical jobseeker (developer, designer) to supply private data and work-related data. We are going to current two completely different factors of view for this function:

And:

The 2 views above are customized views that may finally be loaded and displayed in a tabbed view (a management with tabs as you’ll be able to see within the photographs above). What’s fascinating right here is the number of controls (Cocoa controls) that they’re comprehensively contained in each views, and we’ll focus on this within the following sections. In abstract, we’ll meet the next parts:

Label
Textual content discipline
Popup button
Date picker
Colour properly
Combo field
Radio buttons
Field
Sliders
Examine field
Segmented management
Stage indicator
View tab

As there are lots of issues to debate as we speak, we is not going to begin from scratch, please obtain this startup undertaking with which to work. Open it and familiarize your self with it. You'll discover a group known as "Customized Views" with 4 information: PersonalInfoView.swift, PersonalInfoView.xib, WorkInfoView.swift, and WorkInfoView.xib. These will include the design and implementation of customized views. Some codes, in addition to some components of the consumer interface in Xib information, exist already. .Swift information implement each a way known as applyConstraints (). The purpose is to set the structure constraints programmatically, so that you shouldn’t have to use the constraints manually whereas we add Cocoa controls to the views. It could even be a waste of time. Nonetheless, every time I introduce a brand new management, I may even provide the body it is advisable set in order that it has a place and a measurement in Interface Builder. You should use the Dimension Inspector in Interface Builder to set the picture values.

Word: Don’t be bothered by the errors displayed in Xcode after downloading the startup undertaking. That is regular as a result of a property is at the moment lacking. We are going to clear up this drawback on the finish of this tutorial.

So, let's begin!

Including Cocoa controls to the primary customized view

We'll begin by discussing Cocoa controls by including a few of them to the PersonalInfoView.xib file. Open it by clicking on it within the Challenge Browser. The view you can see right here is already resized to 450 × 350 px.

You in all probability already know this, however so as to add a Cocoa management to a view, it’s essential to:

View the library of objects.
Choose or seek for the management you wish to add.
Drag it on the view.

As a reminder, it isn’t essential so as to add presentation constraints for the controls that we are going to use within the following steps. I present them by program, and the one factor to do is to use them. Nevertheless it's for later. So, let's transfer on to some cocoa checks:

Label

A label is without doubt one of the commonest Cocoa controls utilized in MacOS functions. Its function is to show textual content that customers can’t modify whereas the appliance is working. Opposite to what one may anticipate, a label management shouldn’t be an NSLabel object (in accordance with UILabel in iOS). In actuality, there isn’t a such class (NSLabel). As a substitute, a label is an NSTextField (sure, a textual content discipline), non-editable, borderless, and background coloration object.

Within the object library, add a label to the view. Word that there are two kinds of labels when the article library is seen: Single Line and Multiline. Add one right here, however take into accout a number of strains as it could actually wrap a number of strains when there may be lengthy textual content to show.

Within the Dimension Inspector, set the label body to: 20, 313, 70, 17. Subsequent, within the Attributes Inspector, set its title to "Full Title" (with out the citation marks). Within the Attribute inspector, you’ll be able to edit varied properties. The default look of the label is due to this fact modified. For instance, you’ll be able to change the font household, measurement or thickness, textual content coloration, alignment, borders, and so forth. Don’t hesitate to browse these properties and see how the label is affected.

Textual content discipline

With the primary label in place, the second fairly widespread Cocoa management discipline utilized in MacOS functions is the textual content discipline. That is an NSTextField object, whose function is to permit functions receiving consumer enter if wanted. A textual content discipline is a textual content entry management of a single line. Subsequently, if you would like multiple line of textual content, select a textual content view as an alternative.

Within the object library, add a textual content discipline to the view and set its body to: 20, 283, 410, 22. For the reason that label and the textual content discipline are objects of the identical class (NSTextField), the properties you discover within the Inspector attributes are the identical. A textual content discipline is nevertheless editable by default, it has a border and attracts its background. Examine the properties in between and check out altering a few of the textual content discipline properties to see what's happening.

In code, setting the worth of the textual content discipline is as follows:

textField.stringValue = "Hey world!"

textual content discipline.chain worth = "Hello world!"

You may as well assign numeric values ​​on to textual content fields:

textField.intValue = 5
anotherTextField.doubleValue = 22.45

textual content discipline.intValue = 5

anotherTextField.double worth = 22.45

The properties proven above are additionally used to get the worth of a textual content discipline, for instance:

print (textField.stringValue)

impression(textual content discipline.chain worth)

To manage the habits of the edit, the category that implements the textual content discipline should conform to the NSTextFieldDelegate protocol and be outlined as a delegate of the textual content discipline. Discover extra about it right here.

Popup button

A popup button shows the checklist of predefined choices. That is an NSPopUpButton object that inherits from the NSButton class, so it brings the properties of the button. By default, three parts are contained when including a popup button to a view, an merchandise being really a menu merchandise (NSMenuItem), one other Cocoa management. If the contextual parts are identified upfront, you’ll be able to specify them in Interface Builder. In any other case, if they’re created on the fly whereas the appliance is working, their configuration by means of code is the one approach.

Let's be sensible, open the article library so as to add a contextual button to the view (frames: 21, 213, 100, 25). To rename the default gadgets, you’ve the next choices:

Double-click the contextual management, then double-click every aspect or use the Attributes Inspector to edit the title.
Use the doc construction as proven under to entry the menu gadgets, choose them one after the other, and navigate to the Attributes Inspector to rename them.

So as to add different gadgets to the pop-up window, merely open the Object Library, seek for "Menu Objects" objects, after which drag them to the doc construction above or under the doc construction. under the present parts, in accordance with your wants. You may even add separators, a particular menu merchandise that shows a horizontal separator line that separates menu gadgets graphically.

So as to add parts programmatically, nothing is less complicated:

popup.addItems (withTitles: [“One”, “Two”, “Three”])

seem.Add articles(avecTitres: [[[["A", "Two", "Three"])

So as to add a single merchandise along with the present one:

popup.addItem (withTitle: "4")

seem.add an merchandise(avecTitre: "4")

Word that the 2 strategies above add new gadgets with out deleting current gadgets within the pop-up window. So remember to take away all current gadgets if essential (when you have not already achieved so in Interface Builder):

You may as well delete gadgets at a selected index:

In the identical approach, you will get the title of an merchandise at a selected index:

You may as well get an array of titles:

Word that itemTitles is a property, not a way. More often than not, you’ll want to get the title of the chosen merchandise or its index:

// Title of the chosen merchandise
popup.selectedItem

// Index of the chosen aspect
popup.indexOfSelectedItem

// Title of the chosen merchandise

seem.Chosen merchandise

// Index of the chosen aspect

seem.indexOfSelectedItem

Lastly, it’s fairly widespread to pick out gadgets programmatically. To do that, the next two strains use each the index of an merchandise and its title:

popup.selectItem (at: zero)
popup.selectItem (withTitle: "Three")

seem.choose an merchandise(at: zero)

seem.choose an merchandise(avecTitre: "Three")

The easy strategies and properties above are adequate so that you can deal with popups. Word: All the time ensure that the index worth shouldn’t be within the vary while you use indexes to entry gadgets.

Once more in Interface Builder, within the Attributes Inspector, you can see the properties of the popup button, in addition to the NS button generally. An fascinating property is the Kind within the Pop Up Button part.

By default, Pop Up is the chosen worth and the management works like a popup. Nonetheless, should you set this feature to Pull Down, the management will act as a drop-down menu.

In the identical part, you may also select whether or not the arrow will likely be displayed within the pop-up window, which aspect will likely be chosen by default, and so forth. Most often, leaving the remainder of the properties of their preliminary worth is okay, but it surely nonetheless belongs to you.

For our demonstration software right here, set the next values ​​within the pop-up window: "Man", "Lady", "Different" (with out the quotes, after all!).

Date picker

It’s generally essential to let the consumer outline or select a single date (with or with out time) or choose a date vary through the appliance interface. And even when creating such a customized management appears tedious, Cocoa presents a built-in date picker that may be configured fairly simply.

Within the Object Library, discover a "Date Picker" object and drag it to the view (photographs: 310, 212, 120, 27). The Date Picker management offers the next show kinds:

Textual illustration of the date, with or with out stepper on the suitable aspect:

Graphical illustration, which lets you choose date ranges:

The model of the date selector could be set in Type discipline beneath the Date picker part within the attributes inspector. Extra necessary choices will also be specified right here, corresponding to the selection of the time with the date, whether or not a single date or a date vary could be chosen by the customers, date parts (such because the day, the month or the 12 months). must be displayed or not (in case you want to present the time solely), and extra. You may as well set the default date displayed within the selector, in addition to restrict the minimal and most date worth. On the finish, the configuration of the date picker relies upon totally on the appliance. You must select the model that fits or not the UX and the remainder of the consumer interface offered by the appliance.

If you need the date picker to show as we speak's date each time the appliance runs, it’s essential to achieve this programmatically:

datePicker.dateValue = Date ()

date picker.worth date = Date()

The worth of a date picker is a Date object, so we’ve instantiated such an object above. Use the dateValue property proven above to "learn" (get) the selector worth and do no matter it takes to deal with it (information about how you can deal with Date objects is required).

Colour properly

Cocoa offers a pleasing management that permits customers to entry Colours Management Panel and select a coloration to make use of within the software. This management is named Colour Properly and is within the object library together with the remainder of the controls. Go and add such a management to the view (utilizing the frames 20, 60, 100, 100), after which open the Attribute Inspector. You will notice that there usually are not many properties to configure, crucial being the colour displayed by default of the properly.

By program, you’ll be able to outline and get the colour of the colour properly because of its coloration property:

colorWell.coloration = NSColor.lightGray

colorWell.Colour = NSColor.mild gray

This command triggers the looks of the Colours panel, which is acquainted to macOS customers. It’ll enable them to really feel extra snug together with your software.

Last actions within the Private Information view

The primary spherical of the presentation of the cocoa checks is over. Earlier than transferring on to the second customized view the place we’ll meet extra controls, it’s essential to carry out some last actions right here with a purpose to enable the consumer interface to show appropriately once we run this system. ;software.

Within the doc construction, choose the File proprietor object and open the identification inspector. Put it on PersonalInfoView worth to the Class discipline.

With the File Proprietor object nonetheless chosen, open the Connection Inspector. You will discover IBOutlet properties for all controls added to the view. Join every property to the respective management (use their names to match, the names are self-descriptive), in order that presentation constraints could be utilized programmatically. For instance, join the IBOutlet fullnameTextfield to the textual content discipline of the view, the colorWell to the colours, the birthdatePicker to the date picker, and so forth.

Additionally, join the next actions (IBAction strategies) to the suitable controls, as described:

handleColorPick: on the coloration properly.
handleDateChange: to the date picker.
handleGenderSelection: to the style context button.

Including Cocoa controls to the second customized view

Now that we’ve created our first customized view known as PersonalInfoView, let's proceed to design the subsequent one, known as WorkInfoView. On this half, we’ll proceed the presentation of the primary Cocoa controls that can be utilized to create MacOS functions.

WorkInfoView is meant to current a type that a potential job seeker might use to supply data associated to the job and the expertise. No actual logic will likely be utilized, however what we’re going to do is ideal for coaching and studying. On the finish of this half, we could have constructed a view that may appear to be this:

Open the WorkInfoView.xib file and proceed speaking about Cocoa controls.

Combo field

A drop-down checklist appears to be like loads just like the drop-down button (see the popup button earlier) at first look, as a result of it's one other management that may checklist the gadgets. Nonetheless, there are vital variations, the primary and most necessary being that customers can kind textual content within the drop-down checklist simply as they’d in a textual content discipline. In different phrases, a drop-down checklist combines the options of a drop-down button and a textual content discipline. Customers can choose a price from the listed gadgets or enter a brand new worth.

One other distinction is that the gadgets within the drop-down checklist usually are not menu gadgets. To see how gadgets could be added (or deleted) to the drop-down checklist in Interface Builder, open the Object Library and drag a ComboBox object into the view (photographs 20, 285, 200, 26) . Choose it and go to the Attribute Inspector. There’s a discipline known as Objects in which you’ll add new gadgets and rename or delete current ones. You may as well specify the variety of gadgets seen when the drop-down checklist is expanded.

As well as, attributes associated to textual content fields will also be set in order that the combo field could be configured in the identical approach as a textual content discipline. Modify varied properties and alter the variety of gadgets to see how all the things is mirrored on the drop-down checklist. On the finish, you’ll be able to add the next two parts:

On the code stage, use the next methodology so as to add objects programmatically to the drop-down checklist:

comboBox.addItem (withObjectValue: "Single merchandise")

combo field.add an merchandise(avecObjectValue: "One article")

The kind of the parameter within the above methodology is Any, which implies that you could move the specified worth kind. Additionally it is doable to transmit an array of all objects utilizing the next parts:

comboBox.addItems (withObjectValues: [“Hello”, 123, true])

combo field.Add articles(avecObjectValues: [[[["Hey", 123, true])

Word that the array comprises a string worth, an integer, and a boolean. All will likely be displayed within the drop-down checklist.

Getting values ​​is straightforward too; Right here's how you can get the worth of the chosen merchandise:

comboBox.objectValueOfSelectedItem

combo field.objectValueOfSelectedItem

Get the worth at a selected index:

professionCombo.itemObjectValue (at: 2)

professionCombo.itemObjectValue(at: 2)

Lastly, use the property under to get an array of all of the gadgets within the drop-down checklist:

professionCombo.objectValues

professionCombo.objectValues

With regard to the "persona" textual content discipline of the drop-down checklist, all the things you learn in regards to the textual content fields applies right here as properly. For instance, you should utilize the stringValue property to get or set its string worth.

Field

A management discipline is beneficial for grouping different controls that often relate to a typical function or idea. A field might have a customized title or not, and the title might exist on the prime or backside. If you do not need your customers to know that there’s a field management that teams different controls, you may make it clear and they won’t see something. It's all about defining the right properties.

To see all this, drag a Field object from the article library into the view and set its body to 20, 140, 170, 125. Within the Attributes Inspector, you’ll be able to see the few properties that may be outlined for the zone management. For our demonstration right here, set the title worth to "Platform Choice".

Radio button

Radio buttons are helpful in an software to permit customers to pick out a definite worth from a number of conceptally grouped values. When utilizing radio buttons, no a number of choice of values ​​from the identical group of radio buttons is feasible. As well as, a single radio button doesn’t make sense (should you assume you want it, you really need a test field … see later on this part). Word that a radio button management is definitely an NSButton object.

Open the Object Library and add three radio buttons to the field that you simply added simply earlier than (create the sub-view radio buttons within the field view). Choose them one after the other and set the next frames:

20, 76, 70, 16
20, 48, 70, 16
20, 20, 70, 16

Then, go to the Attribute Inspector to see their configurable properties. More often than not, you do not want to alter something besides the title, the standing (enabled or disabled) and doubtless the font attributes. For our demo, set the next titles:

In the event you might launch the appliance now to see the radio buttons work, you’d get an disagreeable outcome. all radio buttons might be enabled and they’d not mutually disable others when is chosen.

And the query right here is how can we group them collectively in order that they really work as supposed? The answer is to attach all of them to the identical IBAction methodology.

To do that, choose the File Proprietor object within the Doc Define view, and within the Id Inspector, set WorkInfoView as the worth of the Class discipline. Then open the connection inspector. You will discover varied actions ready to connect with controls in Interface Builder. Choose the handlePlatformPreference: and join it to the three radio buttons.

It makes them work correctly:

To get or set the state of a radio button programmatically, use the state property:

Most often, merely establish the radio button clicked within the IBAction related methodology to proceed with the logic of the appliance. You will have the worth of the radio button if solely its title has a which means. Use the title property to get it.

Examine field

The checkbox is one other particular kind of button (NSButton). Not like radio buttons, there are a number of checkboxes that don’t disable one another, and even one test field is sensible. For instance, a test field can be utilized to permit customers to point whether or not they wish to allow a setting that permits them to routinely save their work to disk. Consider a test field because the graphical equal of a Boolean worth (true or false).

A test field is kind of just like the radio button for obtainable properties. Open the Object Library and add a checkbox button to the view (frames 303, 20, 130, 14). Then open the Attribute Inspector to view the obtainable properties. You’ll discover that you could set the preliminary state of the checkbox, the title and all the remaining that will also be set on a radio button. Change the title of the test field that you simply simply added to "Able to relocate."

Cursor

A cursor management (NSSlider object) permits customers to tug a digital button on a bar to the left or proper and, due to this fact, to maneuver inside a variety of values. Normally, it’s ample to specify the minimal and most values ​​defining the vary of values ​​that it represents, in addition to the preliminary precise worth. Nonetheless, a slider can optionally show tick marks (you'll see what's subsequent to it), it may be vertical, or it may be introduced in a very completely different approach. as a round slider as an alternative of linear, which is beneficial in particular circumstances. Regardless of the visible model, all the things that will likely be introduced right here stays the identical.

To see the sliders in motion, select one within the object library (search for a horizontal slider object) and add it to the view (frames 250, 212, 180, 19). By default, a horizontal cursor appears to be like like this:

To vary this look and let the cursor show the markers, go to the Attributes inspector and alter the variety of marks within the Markers discipline from zero to three. The cursor immediately modifications the shape. Extra choices could be configured from there, for instance if the marks are to be positioned above or under the cursor, or if the button ought to cease on the marks solely or not. To facilitate our demonstration, test the Solely cease graduations field.

Just under, you set the present minimal, most, and preliminary worth of the slider. Set 1 as minimal, three as most, and a couple of as present. On this faux demonstration app, these values ​​symbolize the extent of expertise of an expert: Junior, Mid, Senior. When the cursor modifications worth, the above label will likely be up to date to replicate the suitable stage of expertise.

To make this instance much more full, add one other horizontal slider to the view from the article library (Photos 250, 140, 180, 19). This can symbolize the years of expertise of an expert developer, designer or some other merchandise outlined within the drop-down checklist. This time, let's preserve it with out commencement marks. Set zero, 40, 5 because the values ​​for the minimal, most, and present fields, respectively. Lastly, choose the Steady test field within the Management part. By doing this, you’ll make the cursor in a position to report its worth to the appliance whereas the button is moved. When this test field is cleared, the cursor signifies its worth as soon as the button has stopped transferring. You will notice the distinction while you run the appliance as a result of we’ve two sliders with completely different settings.

By programming, you will get or set the present worth of the cursor utilizing the intValue property:

The minimal and most values ​​will also be set programmatically through the use of particularly minValue and maxValue. Each properties anticipate a Double worth.

To see how we will replace the labels above every cursor with its worth, choose the proprietor of the file within the doc preview and open the Connection Inspector. Join the handleExperienceLevelChange motion: to the primary slider with the ticks, and the handleExperienceYearsChange deal with: to the second slider representing the years of expertise. Then swap to the WorkInfoView.swift file and navigate to the handleExperienceLevelChange (_ 🙂 IBAction methodology. Add the next code:

@IBAction func handleExperienceLevelChange (_ sender: N any)

@IBAction func handleExperienceLevelChange(_ sender: All)

The above code updates the label textual content primarily based on the hypothetical experiment stage specified within the slider. Do one thing related for years of expertise, go to handleExperienceYearsChange (_ 🙂 methodology IBAction and add the next:

@IBAction func handleExperienceYearsChange (_ expéditeur: N'importe lequel)
    experienceYearsLabel.stringValue = "Années d'expérience: (experienceYearsSlider.intValue)"

@IBAction func handleExperienceYearsChange(_ sender: Tout)

expérienceAnnéesLabel.valeur de chaîne = "Des années d'expérience: (expérienceAnnéesSlider.intValeur)"

Étant donné que la propriété Steady a été activée pour le deuxième curseur, le code ci-dessus est exécuté chaque fois que le bouton est déplacé à gauche ou à droite pour mettre à jour l'étiquette en temps réel. Au contraire, la méthode IBAction précédente ne sera appelée que lorsque le bouton sera arrêté.

Indicateur de niveau

L'indicateur de niveau est un autre contrôle Cocoa qui se comporte de la même manière que le curseur, mais présente une apparence et des paramètres différents. Même si ce n'est pas un contrôle si commun que l'on peut trouver dans la majorité des functions macOS, je l'inclue ici automotive vous pourriez le trouver utile à un second donné.

L'indicateur de niveau prend en cost quatre apparences différentes, ce qui le rend parfait pour plusieurs varieties d'functions. La valeur par défaut est la capacité discrète:

Il y a aussi la capacité proceed:

La pertinence:

Et enfin Word:

Un indicateur de niveau peut être édité ou non. Lorsqu'il est modifiable, les utilisateurs peuvent définir le niveau d'une manière similaire à celle du curseur (faites glisser le niveau vers la gauche ou vers la droite). De même, à l'instar des curseurs, les valeurs minimale, maximale et initiale du courant doivent également être définies ici. Vous pouvez avoir des graduations, mais je ne les trouve pas aussi belles dans un indicateur de niveau. Ce qui est vraiment bien dans ce contrôle, c'est que vous pouvez appliquer différentes couleurs pour le niveau regular, avertissement et critique lorsque vous utilisez le model Capacité discrète ou Capacité proceed. Dans ce cas, vous devez également fournir les valeurs des niveaux d'avertissement et critique (des champs supplémentaires apparaissent dans l'inspecteur d'attributs).

Revenons donc au fichier WorkInfoView.xib, ajoutons un contrôle de niveau à notre vue (photographs 20, 20, 150, 12) et fixons son model à Score. Ce model affichera des étoiles qui représentent le niveau de satisfaction à l’égard du travail de la personne qui utilise ce formulaire dans notre scénario hypothétique. Définissez les valeurs minimale, maximale et actuelle de zero, 10, 5. Changez également la couleur en rouge en ouvrant la fenêtre contextuelle Couleur de l'picture (toute couleur rouge conviendrait). Notez qu'au lieu d'utiliser les étoiles par défaut, nous aurions pu fournir notre propre jeu d'photographs (deux photographs sont requises, une pour l'état sélectionné et l'autre pour l'état non sélectionné qui seraient placées dans les champs Notation et Espacement réservé en conséquence). Activez également les circumstances à cocher Continu et Modifiable.

Maintenant, ouvrez l’Inspecteur de connexions après avoir sélectionné l’objet Propriétaire du fichier dans la construction du doc et connecté l’motion handleSatisfactionLevelChange: au contrôle de niveau. Basculez vers le fichier WorkInfoView.swift et accédez à la fonction handleSatisfactionLevelChange (_ 🙂 de la méthode IBAction pour ajouter ceci:

@IBAction func handleSatisfactionLevelChange (_ expéditeur: N'importe lequel)
    satisfactionLabel.stringValue = "Niveau de satisfaction: (satisfactionLevelIndicator.intValue) / (Int (satisfactionLevelIndicator.maxValue))"

@IBAction func handleSatisfactionLevelChange(_ sender: Tout)

satisfactionLabel.valeur de chaîne = "Niveau de satisfaction: (satisfactionLevelIndicator.intValeur)/(Int(satisfactionLevelIndicator.Valeur max)) "

Comme vous pouvez le constater, l’obtention de la propriété stage worth (intValue) est similaire à l’obtention de la valeur d’un curseur. Ce qui précède obtient également la valeur maximale définie pour l'indicateur afin que satisfactionLabel puisse afficher quelque selected comme: «Niveau de satisfaction: eight/10».

Contrôle segmenté

Un contrôle segmenté est en fait un bouton séparé en plusieurs segments et permet de sélectionner une ou plusieurs valeurs parmi une assortment de valeurs regroupées. Vous pouvez avoir autant de segments que nécessaire, le nombre par défaut étant three. Un section peut être identifié à l'aide d'une étiquette, d'une picture ou d'une combinaison de ces deux éléments. D'autres propriétés concernant le model et le mode de sélection sont également disponibles dans l'inspecteur d'attributs.

Pour voir un contrôle segmenté en motion, retournez au fichier WorkInfoView.xib et ajoutez-en un de la bibliothèque d'objets à la vue, juste en dessous du libellé «Statut d'emploi actuel». Définissez son cadre sur 18, 74, 414, 24 et, tandis que vous êtes dans l’Inspecteur de taille, sélectionnez un par un les segments du haut et changez la largeur fixe en 136. Ensuite, définissez “Sans emploi”, “Employé” et “ Freelancer ”à chaque étiquette de section, respectivement.

L'utilisation du contrôle segmenté dans le code est facile. Pour montrer cela, sélectionnez le propriétaire du fichier et ouvrez l'inspecteur de connexions. Connectez l'motion handleEmploymentStatusChange: au contrôle segmenté. Ouvrez ensuite le fichier WorkInfoView.swift et dans la méthode handleEmploymentStatusChange (_ 🙂 IBAction, ajoutez les deux lignes suivantes:

@IBAction func handleEmploymentStatusChange (_ sender: Any)

@IBAction func handleEmploymentStatusChange(_ sender: Tout)

Ce qui précède imprimera sur la console l’étiquette du section sélectionné.

Actions de finition

La deuxième partie de l’exploration des contrôles de cacao est terminée, mais une dernière étape est nécessaire pour que cette vue s’affiche correctement lors du chargement. Dans le fichier WorkInfoView.xib, ouvrez l’Inspecteur de connexions après avoir sélectionné l’objet Propriétaire du fichier dans le plan de doc et connectez toutes les propriétés de prise aux contrôles appropriés. Nommer les factors de vente est auto-descriptif, vous ne rencontrerez donc aucun problème pour les associer correctement.

Préparation au chargement de vues personnalisées

Après avoir passé en revue la plupart des contrôles importants de Cocoa, il est temps de devenir un peu plus pratique et de voir remark nous pouvons charger les vues personnalisées que nous avons créées dans les events précédentes. Ce que nous allons faire ici ne se veut pas une resolution ponctuelle qui fonctionnera uniquement dans l’software de démonstration de ce didacticiel. Au lieu de cela, nous allons créer un code réutilisable pouvant être utilisé pour charger n'importe quelle vue personnalisée à l'avenir, dans n'importe quelle software.

Within the earlier components, we set the right customized view class to the File’s Proprietor object on every Xib. Within the PersonalInfoView.xib file we set the PersonalInfoView class because the File’s Proprietor, and the WorkInfoView to the WorkInfoView.xib file. Nonetheless, not one of the two customized view courses will load the Xib contents routinely and the IBOutlet properties will stay nil. Loading from a Xib file (or a Nib because it’s additionally known as) is a customized job that builders should do.

As our purpose is to write down reusable code and supply an answer as a lot basic as doable, we’ll create a protocol together with a protocol extension that may include default implementation of the strategies that we’ll outline. Open the LoadableView.swift file, and add the next:

protocol LoadableView: class

protocol LoadableView: class

Any NSView subclass that may undertake that protocol will likely be able to loading a customized view from a Xib file explicitly set, and a robust reference to that customized view will likely be saved by means of the mainView property. The load(fromNIBNamed:) methodology is the one which can do the precise work right here.

Let’s proceed now by implementing an extension for our protocol:

extension LoadableView the place Self: NSView

extension LoadableView Self: NSView

Discover that the default implementation that we’ll present right here will work if solely the category that adopts the protocol is a NSView class. Utilizing the the place Self: NSView clause is necessary, because the implementation you will note proper subsequent must know the kind of self (the article that conforms to the protocol) and it needs to be a NSView object.

Let’s begin implementing the primary methodology:

extension LoadableView the place Self: NSView

extension LoadableView Self: NSView

func cost(fromNIBNamed nibName: String) -> Bool

var nibObjects: NSArray?

let nibName = NSNib.Title(stringLiteral: nibName)

if Bundle.main.loadNibNamed(nibName, proprietor: self, topLevelObjects: AndnibObjects)

return false

Crucial line within the above code is the one the place the loadNibNamed(_:proprietor:topLevelObjects:) methodology of the Bundle class is named. That one opens the given Nib (Xib) file, and appends any top-level views (views within the IB canvas, not subviews inside a view) to the nibObjects array. In the event you marvel why nibObjects is a NSArray as an alternative of a Swift [Any] array, that’s as a result of that methodology expects for a NSArray occasion.

One other factor to note is the return worth of the strategy. If the Nib file can’t be opened (for instance, you mistype the Xib’s file identify), or the nibObjects array stays nil even after opening the Nib (eg, no views exist), we return false to point that no customized view was loaded.

Let’s get going with the implementation:

let viewObjects = nibObjects.filter

if viewObjects.depend > zero

let viewObjects = nibObjects.filtered $zero is NSView

if viewObjects.depend > zero

preserve let view = viewObjects[[[[zero] as? NSView different return false

mainView = view

self.addSubview(mainView!)

mainView?.translatesAutoresizingMaskIntoConstraints = false

mainView?.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true

mainView?.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true

mainView?.topAnchor.constraint(equalTo: self.topAnchor).isActive = true

mainView?.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true

return true

Our subsequent step as proven above is to filter the objects returned and preserve the NSView situations solely. Word that a Xib file may include different Cocoa controls within the canvas that aren’t NSView objects. As an example, we might have a replica of a button (NSButton) management someplace within the canvas, which might be contained within the nibObjects array too.

Word: What I simply talked about is an instance, and also you shouldn’t try this. It’s a very dangerous behavior having controls that don’t belong to any view thrown to the canvas in Interface Builder. You’d higher create separate Xib information to maintain management copies, so your precise working information are as clear as doable.

After filtering the nibObjects array as proven above, there isn’t a assure that the viewObjects array will even have contents. So, earlier than we proceed, ensuring that it comprises objects is a compulsory motion (if viewObjects.depend > zero).

The next are simple. If a number of top-level views are discovered, we contemplate that the primary one is the one which must be loaded and we assign it to the mainView property. Then we add it to self view (the view that may “host” it), and at last we set its structure constraints. We make the loaded view have the very same body to the container view’s. On the finish, we return true to point a profitable loading.

Right here’s the load(fromNIBNamed:) methodology as one piece:

func load(fromNIBNamed nibName: String) -> Bool

1

2

three

four

5

6

7

eight

9

ten

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

func cost(fromNIBNamed nibName: String) -> Bool

var nibObjects: NSArray?

let nibName = NSNib.Title(stringLiteral: nibName)

if Bundle.main.loadNibNamed(nibName, proprietor: self, topLevelObjects: AndnibObjects)

preserve let nibObjects = nibObjects different return false

let viewObjects = nibObjects.filtered $zero is NSView

if viewObjects.depend > zero

preserve let view = viewObjects[[[[zero] as? NSView different return false

mainView = view

self.addSubview(mainView!)

mainView?.translatesAutoresizingMaskIntoConstraints = false

mainView?.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true

mainView?.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true

mainView?.topAnchor.constraint(equalTo: self.topAnchor).isActive = true

mainView?.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true

return true

return false

The second methodology outlined within the protocol is generally an assistive methodology that has nothing to do with the customized view loading. It merely provides the view object that adopts the protocol to the given father or mother view. Right here is its implementation:

func add(toView parentView: NSView)
    parentView.addSubview(self)
    self.translatesAutoresizingMaskIntoConstraints = false
    self.leadingAnchor.constraint(equalTo: parentView.leadingAnchor).isActive = true
    self.trailingAnchor.constraint(equalTo: parentView.trailingAnchor).isActive = true
    self.topAnchor.constraint(equalTo: parentView.topAnchor).isActive = true
    self.bottomAnchor.constraint(equalTo: parentView.bottomAnchor).isActive = true

func add(toView parentView: NSView)

parentView.addSubview(self)

self.translatesAutoresizingMaskIntoConstraints = false

self.leadingAnchor.constraint(equalTo: parentView.leadingAnchor).isActive = true

self.trailingAnchor.constraint(equalTo: parentView.trailingAnchor).isActive = true

self.topAnchor.constraint(equalTo: parentView.topAnchor).isActive = true

self.bottomAnchor.constraint(equalTo: parentView.bottomAnchor).isActive = true

You’ll perceive the aim of this methodology shortly.

Loading Customized Views

Time to make use of the protocol we simply added to our undertaking and to load our customized views. Firstly, open the PersonalInfoView.swift file and go to the category opening line. There, undertake the LoadableView protocol:

class PersonalInfoView: NSView, LoadableView

class PersonalInfoView: NSView, LoadableView

Subsequent, it’s essential to declare the required property (mainView) by the protocol. Proper after the IBOutlet properties within the PersonalInfoView class add the next:

This property have to be declared to any class that conforms to the LoadableView protocol.

We are actually able to load the customized view we designed within the PersonalInfoView.xib file. Go to the init() methodology and replace it as proven subsequent:

init()

init()

Nice.init(Cadre: NSRect.zero)

if cost(fromNIBNamed: "PersonalInfoView")

See that we give as an argument the precise file identify of the Xib file. If loading is profitable, we’ll carry out these actions:

We’ll name the applyConstraints() methodology (already applied within the starter undertaking) to setup the structure constraints.
We’ll set preliminary values to a few controls for demonstrative functions.

init()
    tremendous.init(body: NSRect.zero)

    if load(fromNIBNamed: "PersonalInfoView")
        applyConstraints()

        birthdatePicker.dateValue = Date()
        colorWell.coloration = NSColor.lightGray

init()

Nice.init(Cadre: NSRect.zero)

if cost(fromNIBNamed: "PersonalInfoView")

Word that the actions taken contained in the if physique are particular to this demo app solely and they don’t include a basic roadmap by any means. Nonetheless, that if physique is the perfect place to carry out actions after the customized view has been loaded.

The PersonalInfoView class can now load its customized view from the Xib file, so let’s do the very same issues for the WorkInfoView class. Open the WorkInfoView.swift file and to begin with undertake the LoadableView protocol:

class WorkInfoView: NSView, LoadableView

class WorkInfoView: NSView, LoadableView

Then, declare the mainView required property:

Lastly, load the customized view within the init() methodology. On success, setup constraints and set the preliminary worth to the test field management of the customized view:

init()
    tremendous.init(body: NSRect.zero)

    if load(fromNIBNamed: "WorkInfoView")

init()

We are actually prepared to point out the customized views!

Presenting Customized Views

Since we’ve two customized views with completely different content material on every, we’ll use a tab view to current them. A tab view can show a number of views with solely considered one of them being seen at a given second. Tabs of a tab view are used to establish, separate and choose the view to show. Such a tab view exists already within the starter undertaking, and it may be discovered within the Essential.storyboard file.

It comprises two tabs, due to this fact two views that may include our customized views shortly.

Within the Attributes Inspector it’s doable to set a couple of properties, with the model being the commonest because it offers choices concerning the positioning of the tabs. Most often default properties are appropriate for many apps, so configuring a tab view management isn’t essential.

The tab view you see in the primary storyboard is related to an IBOutlet property known as tabView within the ViewController class. Let’s swap to the ViewController.swift file the place we’ll add only a few strains of code to current our customized views. At first, declare the next two properties (situations of the customized view courses) within the ViewController class:

var personalInfoView: PersonalInfoView?

var workInfoView: WorkInfoView?

var personalInfoView: PersonalInfoView?

var workInfoView: WorkInfoView?

Within the viewDidLoad() now, let’s entry the 2 views of the tab view management:

override func viewDidLoad()

override func viewDidLoad()

view1 is the left view and view2 the suitable view. On profitable unwrapping, we’ll initialize the personalInfoView and workInfoView properties (our customized views) and we’ll add them as subviews to the view1 and view2 respectively:

override func viewDidLoad()
    tremendous.viewDidLoad()

    guard let view1 = tabView.tabViewItem(at: zero).view, let view2 = tabView.tabViewItem(at: 1).view else return

    personalInfoView = PersonalInfoView()
    personalInfoView?.add(toView: view1)

    workInfoView = WorkInfoView()
    workInfoView?.add(toView: view2)

override func viewDidLoad()

Nice.viewDidLoad()

preserve let view1 = tabView.tabViewItem(at: zero).view, let view2 = tabView.tabViewItem(at: 1).view different

personalInfoView = PersonalInfoView()

personalInfoView?.add(toView: view1)

workInfoView = WorkInfoView()

workInfoView?.add(toView: view2)

Within the above code you see how the add(toView:) methodology of the LoadableView protocol is used.

C'est tout! Our demo app is prepared and now you can run the app. When you achieve this, see how every single management we added to each views works, and experiment with properties to alter their behaviour.

abstract

The best way customized views are loaded is without doubt one of the must-know issues for each macOS developer, and the answer offered on this submit can be utilized as-is in any software. Apart from that, I hope you loved our tour in a few of the most necessary Cocoa controls being obtainable to construct apps in macOS. Sure controls had been left apart deliberately (corresponding to desk view, define view, and some extra), as complete posts are going to be devoted to them. The subject of this tutorial can get quite a lot of experiment, so try this; experiment with the controls and their properties to learn how they behave, add extra controls from the Objects Library and make your individual small or massive apps to follow your information. I’m completely constructive that the extra you discover, the extra you’ll like macOS programming!

For reference, you’ll be able to obtain the whole Xcode undertaking on GitHub.