Гид по проекту: Light

До сих пор на этом уроке вы изучали основы Xcode и Interface Builder. Теперь вы сможете применить свои знания об этих инструментах, создав проект.

К концу этого проекта вы создадите приложение под названием Light, которое меняет цвет экрана с черного на белый и обратно всякий раз, когда пользователь нажимает на кнопку. Чтобы успешно создать light, вам нужно будет использовать документацию Xcode, установить точки останова и создать выходы и действия.

Этот проект будет включать в себя изменение некоторого кода — даже если вы относительно новичок в языке Swift. Не расстраивайтесь, если у вас возникли проблемы с конкретными частями кода проекта. Просто продолжай в том же духе!

Часть первая

Создайте кнопку и действие

Создайте новый проект Xcode, используя шаблон приложения для iOS, который вы использовали в предыдущих уроках. При создании проекта убедитесь, что для параметра интерфейс установлено значение Раскадровка. Назовите проект "Light". Когда вы создадите и запустите проект, вы заметите, что пользователю не с чем взаимодействовать. Вы скоро это измените.

Выберите раскадровку Main в навигаторе проекта, чтобы открыть раскадровку в конструкторе интерфейсов. 

Первоначальный интерфейс, созданный Xcode, включает в себя экземпляр ViewController. ViewController - это подкласс UIViewController, который поставляется предопределенным как часть шаблона приложения iOS и указан в навигаторе проекта. Вы можете нажать кнопку Show Document Outline (Показать схему документа)  1  , чтобы отобразить все контроллеры представления, определенные в Main раскадровке.

 

Выберите View Controller в структуре документа,  2   затем нажмите кнопку Identity inspector в верхней части области Инспектора, чтобы подтвердить, что данный конкретный view controller имеет тип ViewController.

Если вы используете симулятор, используйте кнопку Устройства в нижней части холста (текущий выбор показан рядом с кнопкой), чтобы настроить размер холста. Установите размер холста в соответствии с конфигурацией iPhone 13 Pro и выберите iPhone 12 Pro или iPhone 13 Pro simulator из меню в левом конце панели инструментов Xcode toolbar.

Если вы используете свое собственное устройство для этого проекта, размер контроллера просмотра может не совпадать с размером вашего экрана. Используйте кнопку “View as” в нижней части холста, чтобы настроить размер холста в соответствии с вашим устройством, но оставьте его в портретной ориентации.


Выберите обзор View Controller, затем выберите инспектор атрибутов Attributes inspector, который позволит вам настроить атрибуты любого элемента интерфейса. Цвет фона для этого представления уже установлен на белый. Это желаемое состояние вашего приложения при запуске, поэтому вам не нужно ничего менять прямо сейчас.

Затем добавьте кнопку, которая будет использоваться для изменения цвета фона вида, имитируя включение и выключение света. Нажмите кнопку + в правом верхнем углу панели инструментов, чтобы открыть библиотеку. Как вы узнали из предыдущего урока, эта библиотека включает в себя список общих объектов, которые можно добавить в раскадровку. Прокрутите список или воспользуйтесь фильтром поиска в верхней части области библиотеки.

 

Найдите объект “Button” (“Кнопка”) в библиотеке и перетащите его поверх обзора. Когда вы отпустите курсор, в контуре документа должно быть указано, что кнопка была добавлена в качестве подвида.  3  

 

 

Переместите кнопку в верхний левый угол обзора. Направляющие для выравнивания полей помогут зафиксировать объект в правильном положении.  4  

 

 

Присвойте вашей кнопке действие, которое она будет выполнять при нажатии (клик или тап). Добавьте помощника редактора с помощью кнопки Adjust Editor Options (Настроить параметры редактора)  5   и выберите Assistant Editor (Помощник редактора)  6  , чтобы разделить рабочую область Xcode на две части: Interface Builder и соответствующий ему код.

 

 

Теперь перетащите с зажатым Control  (или щелкните правой кнопкой мыши) кнопку в доступную область в определении класса ViewController. При перетаскивании от кнопки протягивается синяя линия, а под курсором отображается синяя горизонтальная полоса, указывающая допустимое место для создания соединения.  7  

 

 

Когда вы отпустите курсор мыши, вам будет предложено создать outlet или определить действие (action). Измените подключение на действие, затем установите имя на ”buttonPressed".  8   Когда вы нажмете кнопку Подключения, Xcode создаст новый метод, который будет вызываться при каждом нажатии кнопки. Вы можете заметить ключевое слово @IBAction прямо перед методом buttonPressed(_:). @IBAction сигнализирует Xcode о том, что между визуальным элементом в раскадровке и функцией может быть создана связь.

 

 

Создайте и запустите приложение. Когда вы нажимаете кнопку, ничего не происходит, потому что в методе buttonPressed(_:) нет кода для выполнения. Чтобы убедиться, что метод вызывается, вы можете поместить точку останова в определение метода. Теперь нажмите кнопку, и сработает точка останова.  9  

 

 

Теперь, когда вы убедились, что действие работает правильно, вы можете добавить некоторый код для изменения цвета фона. Удалите точку останова, прежде чем продолжить.

 

Часть вторая

Измените фон

Если индикатор включен (то есть, если цвет фона белый), то свет должен быть выключен. В противном случае, если свет выключен (фон черный), то свет должен быть включен. Утверждение "свет включен" является либо истинным, либо ложным утверждением, поэтому имело бы смысл использовать логическое значение, чтобы определить, как изменить цвет фона.

В верхней части определения класса ViewController создайте переменную с именем lightOn и установите начальное значение true, поскольку экран начинается с белого фона.

 

var lightOn = true

 

Каждый раз, когда нажимается кнопка, значение должно меняться с true на false или с false на true. У логических значений Swift есть метод toggle(), который делает именно это. Поскольку метод buttonPressed(_:) вызывается всякий раз, когда выполняется нажатие, внесите в него изменения.

 

@IBAction func buttonPressed(_ sender: Any) {
    lightOn.toggle()
}

 

После того, как значение было изменено, вы можете использовать новое значение, чтобы определить, как изменить цвет фона. Если предполагается, что индикатор должен быть выключен, измените его на черный. Или, если он должен быть включен, измените его на белый. Вы можете написать эту логику, используя простой оператор if.

 

@IBAction func buttonPressed(_ sender: Any) {
    lightOn.toggle()
    if lightOn {
      view.backgroundColor = .white
    } else {
      view.backgroundColor = .black
    }
}

 

Создайте и запустите свое приложение, и фон должен успешно меняться при каждом нажатии. Отличная работа!

Поскольку размер вашего приложения продолжает расти, убедитесь, что ваш код остается организованным. Вместо того, чтобы помещать оператор if непосредственно в метод button Pressed(_:), вы можете переместить его в новый метод, который обрабатывает обновление всего пользовательского интерфейса.

 

 

 

Выделите весь оператор if, а затем выберите  10   Editor > Refactor >​
 Extract to Method.  11  

 

 

Xcode перемещает код с места в новый метод и переходит в специальный режим редактирования, который позволяет вам одновременно задавать имя нового метода и обновлять место его вызова. Введите updateUI и нажмите клавишу возврата, чтобы задать имя.  12  

Xcode переместил выбранный код в новый метод с именем updateUI(), а затем добавил вызов updateUI(), где когда-то находился код.

Результат должен выглядеть следующим образом:

 

fileprivate func updateUI() {
  if lightOn {
    view.backgroundColor = .white
  } else {
    view.backgroundColor = .black
  }
}
 
@IBAction func buttonPressed(_ sender: Any) {
    lightOn.toggle()
    updateUI()
}

 

Обратите внимание на ключевое слово fileprivate, которое Xcode использовал перед именем метода. Swift использует этот специальный модификатор доступа, чтобы указать, откуда может быть вызван метод. Если вы используете функцию рефакторинга Xcode и вам нужно вызвать свой метод вне файла, в котором он определен, удалите ключевое слово fileprivate перед ним.

Это небольшое изменение для небольшого приложения. Вы увидите, что этот шаблон сохраняется на протяжении всей этой книги, и вам будет намного проще отлаживать проблемы с интерфейсом, если весь код, который обновляет представление, содержится в одном методе.

 

Часть третья

Обновите текст кнопки

Теперь вы успешно настроили кнопку на изменение цвета фона вида, но заголовок текста кнопки остается неизменным независимо от состояния освещения. На данный момент нет никакого способа ссылаться на вашу недавно созданную кнопку в коде. Сначала вы должны создать аутлет для кнопки. Перетащите с зажатым Control кнопку в конструкторе интерфейсов на пустое место в верхней части определения контроллера представления в области редактора. Во всплывающем окне убедитесь, что аутлет выбран в разделе Подключение, и введите “lightButton” в поле Название.

Всплывающее меню должно выглядеть следующим образом:  13  

 

 

Нажмите кнопку Connect (Подключиться).

Как вы узнали из предыдущего урока, вы можете видеть эти детали outlet слева направо:

  • Круг — Заполненный круг указывает на то, что outlet подключена. Круг будет пустым, если свойство ни к чему не подключено.
  • @IBOutlet — Это ключевое слово сигнализирует Xcode о том, что свойство в этой строке является аутлетом.
  • var lightButton — объявляет свойство с именем “lightButton”.
  • UIButton! — Тип свойства - UIButton!. Восклицательный знак предупреждает вас о том, что программа завершит работу, если вы попытаетесь получить доступ к этому свойству, а outlet не подключена. Вы узнаете больше о восклицательном знаке, когда узнаете об опциях в более позднем разделе.

Создав outlet, теперь вы можете вносить изменения в кнопку программно. Начните с поиска правильного места для обновления заголовка кнопки и правильного действия для ее выполнения.

 

 

Добавьте точку останова в первую строку метода buttonPressed(_:), затем создайте и запустите свое приложение. Как и следовало ожидать, при нажатии кнопки для изменения цвета будет выполнено соответствующее действие buttonPressed(_:). Но поскольку вы добавили точку останова, код будет приостановлен перед выполнением строки с точкой останова.  14  

Нажмите кнопку “Step over” (“Перейти”)  15  , чтобы запустить первую строку. Теперь ваше приложение приостановлено непосредственно перед запуском метода updateUI(). Нажмите кнопку “Step into” (“Войти”). Теперь приложение приостановлено непосредственно перед выполнением первой строки updateUI.  16  

 

 

Найдите минутку, чтобы попытаться прочитать тело метода updateUI()  17  . Поскольку Swift - очень читаемый язык программирования, вы, вероятно, можете интерпретировать строки следующим образом: “Если горит индикатор, цвет фона представления должен быть белым, или же цвет фона представления должен быть черным”.

Теперь рассмотрим, как следует определить название кнопки. Если индикатор горит, заголовок кнопки должен гласить “Off”, или же заголовок кнопки должен гласить “On”. Имеет смысл, что заголовок кнопки должен быть обновлен аналогично цвету фона представления.

Теперь вы нашли разумное место для обновления текста — в методе updateUI(). Но какова фактическая функция для этого? Как вы узнали ранее, документация по Xcode всегда доступна для вашей поддержки. Поэтому всякий раз, когда вы в чем-то не уверены, хорошей привычкой будет искать ответы в документации.

 

 

Чтобы узнать, как задать заголовок lightButton, начните с чтения документации по его типу, UIButton. Вы можете получить доступ к документации напрямую, используя Window > Developer Documentation из меню Xcode. При этом откроется отдельное окно со средством просмотра документации.

Начните вводить UIButton в поле поиска документации. Автозаполнение быстро предлагает варианты. Как только вы увидите UIButton в меню, продолжайте и выберите его.  18  

 

 

Прокрутите вниз до раздела Topics (Темы), чтобы найти список под названием "Managing the Title" ("Управление заголовком").​ Там вы найдете функцию для установки заголовка: func setTitle(String?, for: UIControl.State).

Щелкните по имени функции, чтобы увидеть ее объявление и список ее параметров.  19   Первый параметр - это желаемый текст, а второй параметр - UIControl.State. Параметр UIControl.State представляет различные потенциальные состояния кнопки, например: если она бездействует, если пользователь начал нажимать на нее или если кнопка отключена. Нажмите кнопку UIControl.State в разделе Declaration (Декларации).

 

 

В этом новом списке символов раздел Констант содержит константу normal  20  , которая соответствует состоянию кнопки, когда она включена и бездействует на экране. Это правильное состояние для настройки заголовка кнопки.

 

 

Благодаря вашим новым знаниям о методе updateUI() вы можете удалить точки останова, добавленные ранее, и настроить метод так, чтобы он выглядел следующим образом:

 

func updateUI() {
  if lightOn {
    view.backgroundColor = .white
    lightButton.setTitle(”Off”, for: .normal)
  } else {
    view.backgroundColor = .black
    lightButton.setTitle(”On”, for: .normal)
  }
}

 

Создайте и запустите свое приложение. Нажатие или нажатие на кнопку теперь должно изменить как цвет фона, так и текст кнопки. Но есть ошибка: перед нажатием кнопки текст по-прежнему читается как “Button”, а не “On” или “Off”. Как вы можете обновить код, чтобы устранить эту проблему?

В вашем проекте уже есть код, который будет следить за тем, чтобы текст кнопки соответствовал включенному или выключенному состоянию подсветки: updateUI(). Вам просто нужно вызвать его при первой загрузке представления — чтобы кнопка обновлялась при появлении представления, а не при первом нажатии пользователем кнопки. Вы можете запустить установочный код в функции viewDidLoad(), которая уже определена в вашем подклассе view controller и вызывается, когда контроллер представления готов появиться на экране.

Вызовите updateUI() в рамках этого метода, как показано в следующем примере:

 

override func viewDidLoad() {
    super.viewDidLoad()
    updateUI()
}

 

Создайте и снова запустите свое приложение. При запуске текст кнопки теперь должен гласить "On".

 

Часть четвертая

Улучшите пользовательский опыт

У вас есть приложение, которое работает. Это отличное начало. Теперь уделите минутку размышлениям о его дизайне и о том, как пользователь воспринимает приложение. Что можно было бы улучшить?

Глядя на кнопку, вы можете понять, что текст кажется посторонним. Довольно ясно, включен ли индикатор в данный момент или выключен — на это указывает цвет фона. Нужно ли пользователю вообще видеть текст?

Имеет ли значение, где на экране находится кнопка? И разве это не немного странно, что большая часть экрана недоступна для нажатия?

Возможно, было бы лучше удалить текст с кнопки и сделать так, чтобы кнопка заполняла весь экран. Таким образом, пользователь может нажать в любом месте экрана, чтобы включить и выключить свет. Важной частью создания любого приложения является рассмотрение мелких деталей и попытка создать интуитивно понятный, простой и мощный пользовательский интерфейс. В этом случае имеет смысл, чтобы пользователь мог нажать в любом месте экрана, чтобы переключить цвет фона.

Для начала вам нужно изменить размер кнопки, чтобы она заполнила весь экран. Выберите кнопку в конструкторе интерфейсов, затем перетащите ее верхний левый и нижний правый углы, расширяя кнопку, чтобы покрыть весь белый вид.  21  

 

 

Удалите текст заголовка для кнопки. Область нажатия кнопки по-прежнему будет работать так, как ожидалось, но теперь она будет выглядеть так, как будто на холсте существует только белый вид.  22  

 

 

Когда текст исчезнет, вы можете удалить строки кода в updateUI(), которые вносят изменения в заголовок кнопки.

 

func updateUI() {
    if lightOn {
        view.backgroundColor = .white
    } else {
        view.backgroundColor = .black
    }
}

 

В этом обновленном дизайне свойства кнопки не нужно изменять, пока кто-то использует приложение. Это означает, что  outlet, который вы создали в начале проекта, больше не нужен. Как разработчик, вы хотите сохранить свой код как можно более чистым, поэтому рекомендуется очистить @IBOutlet.

Сначала разорвите соединение между кнопкой и ее outlet. Для этого нажмите кнопку в Конструкторе интерфейсов, затем откройте Connections inspector (инспектор подключений).  23   Здесь вы можете увидеть все события и выводы соединений, связанные с конкретным объектом. В этом случае вы можете видеть, что кнопка привязана к buttonPressed: action и к outlet lightButton. ​ Нажмите крестик рядом с outlet, чтобы удалить ее.  24  

 

 

Поскольку больше нет никаких объектов, связанных с lightButton, маленький кружок рядом с @IBOutlet больше не заполняется.  25  

 

 

Теперь можно безопасно удалить объявление lightButton. Создайте и запустите свое приложение в последний раз, чтобы протестировать новые улучшения дизайна. Теперь вы должны иметь возможность нажимать или щелкать в любом месте экрана, чтобы изменить цвет его фона.

Поскольку обе строки в операторе if-else выполняют одно и то же (устанавливают backgroundColor), метод updateUI() может выглядеть более чистым, если вы используете троичный оператор вместо оператора if-else.

 

func updateUI() {
  view.backgroundColor = lightOn ? .white : .black
}

 

Создайте и запустите свое приложение еще раз, чтобы убедиться, что троичный оператор работает должным образом.

Подведение итогов

Вы успешно создали приложение, которое одним нажатием кнопки меняет цвет экрана с черного на белый и обратно — что-то вроде фонарика. Вы также упростили дизайн приложения, приняв сознательные решения для улучшения пользовательского опыта, удалив заголовок кнопки и заполнив экран областью, к которой можно прикоснуться. Даже если у вас ограниченные знания о Swift, вы смогли пройти через строки кода и обратиться к документации, чтобы завершить этот проект.

Вам было трудно ориентироваться в Xcode или использовать Interface Builder? Если это так, вернитесь к предыдущим урокам, в которых они обсуждались более подробно. Вы обнаружите, что чем больше вы строите, тем более привычным это становится.

Когда вы переходите к следующему блоку, держите документацию разработчика под рукой. Разработчики хороши настолько, насколько хороши инструменты и ресурсы, которые они используют.

 


Отрывок из книги
Develop in Swift Fundamentals
Apple Education
https://books.apple.com/ru/book/develop-in-swift-fundamentals/id1581182804

Information

Apple, the Apple logo, Apple Books, Apple TV, Apple Watch, Cocoa, Cocoa Touch, Finder, Handoff, HealthKit, iPad, iPad Pro, iPhone, iPod touch, Keynote, Mac, macOS, Numbers, Objective-C, Pages, Photo Booth, Safari, Siri, Spotlight, Swift, tvOS, watchOS, and Xcode are trademarks of Apple Inc., registered in the U.S. and other countries. App Store and iBooks Store are service marks of Apple Inc., registered in the U.S. and other countries. ​
The Bluetooth® word mark and logos are registered trademarks owned by Bluetooth SIG, Inc. and any use of such marks by Apple is under license. ​
IOS is a trademark or registered trademark of Cisco in the U.S. and other countries and is used under license. ​
Other product and company names mentioned herein may be trademarks of their respective companies.