Научете как да компютърирате отмествания в реално време в SwiftUI ScrollView

SwiftUI, новият декларативен начин за създаване на потребителски интерфейси, е наистина невероятна рамка. Много неща могат да се направят за нула време с пълни предварителни прегледи на живо, но понякога репликирането на нещо доста обичайно в UIKit може да се превърне в болка във врата. Отместванията на ScrollView са едно от тези неща!

В UIKit всеки UIScrollView има свойство, което ни позволява лесно да четем отместването на самия изглед:

var contentOffset: CGPoint { get set }

Той връща структура със стойностите x и y. Супер лесно, супер удобно!

SwiftUI, за съжаление, днес липсва това просто свойство. Така че трябва да измислим начин да получим тази стойност по някакъв начин.

В края на този урок ще можете да създадете нещо подобно на това:

Рамката SwiftUI често ни позволява (или принуждава) да мислим нестандартно, за да решаваме проблеми, и това е един чудесен повод да го направим.

Нека първо започнем с изграждането на много прост потребителски интерфейс с дълъг списък и етикет Text, който няма да може да покаже реалната стойност на отместването (разбира се, ще добавим тази функция по-късно), както можете да видите, че verticalOffset var никога не се променя:

За да постигнем резултата от видеото по-горе, ще кодираме View, който ще се държи точно като SwiftUI ScrollView, но излъчва по някакъв начин стойността в реално време на своето отместване.

Първо, трябва да създадем нова структура, която ще отговаря на протокола PreferenceKey.

Официалната документация на Apple ни дава дефиницията на този протокол, както следва:

Именувана стойност, произведена от изглед.
Изглед с множество деца автоматично комбинира своите стойности за дадено предпочитание в една стойност, видима за неговите предци.

Това е сложен начин да кажем, че позволяваме на изглед да говори с изгледите, които го съдържат и да предава стойности.

За да съответства на този протокол, трябва да бъдат внедрени свойство и функция, и двете статични:

static var defaultValue: Self.Value { get }
static func reduce(value: inout Self.Value, nextValue: () -> Self.Value)

Стойността по подразбиране ще бъде нашето отместване, CGPoint, с начална стойност 0,0.

Нека създадем структурата OffsetPreferenceKey точно така:

Браво, сега е време да създадем нашата версия на scrollView.
Нека създадем структура със същите свойства на SwiftUI ScrollView, но с допълнително нещо, onOffsetChanged затваряне, което да се активира, когато scrollview промени позицията си:

Както можете да видите, използвах общо променливо съдържание, за да предам цялото съдържание на ScrollView. Както е посочено в дефиницията на структурата T ще бъде от тип View.

Нека сега да разгледаме имплементацията на свойството body:

  • На ред 2 създадох ScrollView
  • На ред 3 GeometryReader, който съдържа празен изглед, Color.Clear без размери. Трябва да проследим позицията на изглед и е умна идея да използваме безразмерен. Вътре в него съм задал ключа OffsetPreferenceKey, предаващ като стойност произхода на самия кадър. Използвах coordinateSpace(name:), за да позволя на друга функция да намира и оперира с нашия изглед Color и да работи с измерения спрямо този изглед.
  • Предавам началната позиция на външния свят, стартирайки затварянето, когато тази стойност се промени, на ред 15.
  • На ред 12 използвам предадения инициализатор content.

Това е цялата структура:

Това е готово! Имаме нашия чисто нов OffsettableScrollView, който ще може да предава стойността на своето отместване по всяко време, когато се промени!

Сега е време да променим нашия оригинален изглед на съдържание с най-накрая свързан Text:

Свърши! Както можете да видите, сега е супер лесно и супер чисто!

Надявам се тази статия да ви е харесала. Ако се интересувате от видео версията, това ръководство е и в моя YouTube канал:

Приятно кодиране!