{"id":484301,"date":"2026-06-19T12:56:24","date_gmt":"2026-06-19T12:56:24","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=484301"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=484301","title":{"rendered":"\u0421\u0432\u043e\u0439 NavigationBar \u043d\u0430 iOS: large title, \u043f\u043e\u0438\u0441\u043a \u0438 \u0441\u043f\u0438\u0441\u043a\u0438 \u043d\u0430 Texture"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0451\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e <code>UINavigationBar<\/code> \u0438 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0431\u0430\u0440 \u043d\u0430 \u043e\u0431\u044b\u0447\u043d\u043e\u043c <code>UIView<\/code>: \u0441 \u043a\u043e\u043b\u043b\u0430\u043f\u0441\u0438\u0440\u0443\u044e\u0449\u0438\u043c large title \u043a\u0430\u043a \u0443 Apple, \u0441\u043e \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u043f\u043e\u0438\u0441\u043a\u0430, \u0441 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u0430\u043d\u0435\u043b\u044f\u043c\u0438 \u043f\u043e\u0434 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c \u2014 \u0438 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0441 <code>UITableView<\/code>, \u043d\u043e \u0438 \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u0430\u043c\u0438 \u043d\u0430 Texture (AsyncDisplayKit).<\/p>\n<p>\u042f \u0434\u0435\u043b\u0430\u043b \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u043a\u0440\u0443\u043f\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438 \u043e\u043d \u0434\u0430\u0432\u043d\u043e \u0436\u0438\u0432\u0451\u0442 \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435. \u041d\u0438\u0436\u0435 \u2014 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0438, \u0447\u0442\u043e \u0432\u0430\u0436\u043d\u0435\u0435, \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441\u044b: \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0447\u0435\u0441\u0442\u043d\u044b\u0439 \u0440\u0430\u0437\u0431\u043e\u0440 \u043e\u0431\u0445\u043e\u0434\u043d\u044b\u0445 \u043f\u0443\u0442\u0435\u0439 \u043f\u043e\u043b\u0435\u0437\u043d\u0435\u0435 \u043f\u0440\u0438\u0447\u0451\u0441\u0430\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438, \u0433\u0434\u0435 \u0432\u0441\u0451 \u0441\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0441 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0440\u0430\u0437\u0430.<\/p>\n<h3>\u0417\u0430\u0447\u0435\u043c \u043d\u0443\u0436\u0435\u043d \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 navbar<\/h3>\n<p>\u041d\u0430\u0431\u043e\u0440 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u0431\u044b\u043b \u0442\u0430\u043a\u043e\u0439:<\/p>\n<ul>\n<li>\n<p>large title, \u043f\u043b\u0430\u0432\u043d\u043e \u0441\u0436\u0438\u043c\u0430\u044e\u0449\u0438\u0439\u0441\u044f \u043f\u0440\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0435 \u2014 \u043a\u0430\u043a \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u0434 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c \u2014 \u0441\u0442\u0440\u043e\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0442\u043e\u0436\u0435 \u043a\u043e\u043b\u043b\u0430\u043f\u0441\u0438\u0442 \u043f\u0440\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0435, \u0430 \u0432 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0432\u0441\u044e \u0448\u0438\u0440\u0438\u043d\u0443;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u0434 \u043f\u043e\u0438\u0441\u043a\u043e\u043c \u2014 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u043d\u0435\u043b\u0438, \u0447\u0430\u0441\u0442\u044c \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0434\u043e\u043b\u0436\u043d\u0430 \u0443\u0435\u0437\u0436\u0430\u0442\u044c \u043f\u0440\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0435, \u0447\u0430\u0441\u0442\u044c \u2014 \u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c\u0441\u044f;<\/p>\n<\/li>\n<li>\n<p>\u0440\u0430\u0437\u043c\u044b\u0442\u044b\u0439 \u0444\u043e\u043d (<code>UIVisualEffectView<\/code>), \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0449\u0438\u0439\u0441\u044f \u0438 \u0438\u0441\u0447\u0435\u0437\u0430\u044e\u0449\u0438\u0439 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0430;<\/p>\n<\/li>\n<li>\n<p>\u0438, \u0447\u0442\u043e \u0432\u0430\u0436\u043d\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u044c \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0442\u0438\u043f\u0430\u043c\u0438 \u0441\u043a\u0440\u043e\u043b\u043b-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432: \u0447\u0430\u0441\u0442\u044c \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u043d\u0430 UIKit, \u0447\u0430\u0441\u0442\u044c \u2014 \u043d\u0430 Texture (<code>ASTableNode<\/code> \/ <code>ASCollectionNode<\/code>).<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 <code>UINavigationBar<\/code> \u0441 <code>prefersLargeTitles<\/code> \u0438 <code>UISearchController<\/code> \u0432 \u0442\u0435\u043e\u0440\u0438\u0438 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u043c\u043d\u043e\u0433\u043e\u0435. \u041d\u043e \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u043f\u0430\u043d\u0435\u043b\u0438, \u043d\u0443\u0436\u043d\u043e \u0442\u043e\u0447\u043d\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043c\u043e\u043c\u0435\u043d\u0442\u043e\u043c \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0431\u043b\u044e\u0440\u0430, \u0442\u043e\u043d\u043a\u043e \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u0441\u043d\u0430\u043f\u043f\u0438\u043d\u0433 \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043f\u043e\u0434\u0440\u0443\u0436\u0438\u0442\u044c \u0432\u0441\u0451 \u0441 Texture \u2014 \u0442\u043e\u0447\u0435\u043a \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u043f\u043e\u0447\u0442\u0438 \u043d\u0435 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f. \u0412 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043c\u043e\u043c\u0435\u043d\u0442 \u0434\u0435\u0448\u0435\u0432\u043b\u0435 \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 <code>UIView<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u043f\u0440\u0438\u0442\u0432\u043e\u0440\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u0432\u0431\u0430\u0440\u043e\u043c, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u0436\u0438\u0432\u0451\u0442 \u0441\u0432\u0435\u0440\u0445\u0443 \u044d\u043a\u0440\u0430\u043d\u0430 \u0438 \u0441\u0430\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0441\u0435\u0442\u0430\u043c\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0430.<\/p>\n<p>\u041d\u0430\u0437\u043e\u0432\u0451\u043c \u0435\u0433\u043e <code>CollapsingNavBar<\/code>. \u0414\u0430\u043b\u044c\u0448\u0435 \u2014 \u043f\u043e \u0447\u0430\u0441\u0442\u044f\u043c.<\/p>\n<h3>\u0410\u043d\u0430\u0442\u043e\u043c\u0438\u044f: \u0431\u0430\u0440 \u043a\u0430\u043a \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0442\u0435\u043a \u043f\u0430\u043d\u0435\u043b\u0435\u0439<\/h3>\n<p>\u0420\u0430\u0441\u043a\u043b\u0430\u0434\u043a\u0430 \u043f\u0440\u044f\u043c\u043e\u043b\u0438\u043d\u0435\u0439\u043d\u0430 \u2014 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 <code>UIStackView<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443 \u043b\u0435\u0436\u0430\u0442 \u043f\u0430\u043d\u0435\u043b\u0438:<\/p>\n<pre><code class=\"swift\">stack.addArrangedSubviews(    topPanel,          \/\/ \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 44pt: left-\u043a\u043d\u043e\u043f\u043a\u0430, title, right-\u043a\u043d\u043e\u043f\u043a\u0438    spacePanel,        \/\/ \u0440\u0430\u0441\u0442\u044f\u0433\u0438\u0432\u0430\u044e\u0449\u0438\u0439\u0441\u044f \u0437\u0430\u0437\u043e\u0440 (\u043a\u0430\u043a \u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e large title)    largeTitlePanel,   \/\/ \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a    searchPanel,       \/\/ \u0441\u0442\u0440\u043e\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430    closablePanel,     \/\/ \u043f\u0430\u043d\u0435\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0443\u0435\u0437\u0436\u0430\u0435\u0442 \u043f\u0440\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0435    pinnedPanel,       \/\/ \u043f\u0430\u043d\u0435\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f    separatorLine      \/\/ \u043d\u0438\u0436\u043d\u044f\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043b\u0438\u043d\u0438\u044f)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0434 \u0444\u043e\u043d\u043e\u043c \u043b\u0435\u0436\u0430\u0442 <code>backgroundView<\/code> (\u0441\u043f\u043b\u043e\u0448\u043d\u043e\u0439 \u0446\u0432\u0435\u0442) \u0438 <code>blurView<\/code> (<code>UIVisualEffectView<\/code>); \u043e\u043d\u0438 \u043f\u043e\u0434\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e, \u0440\u0430\u0441\u043a\u0440\u044b\u0442 large title \u0438\u043b\u0438 \u043d\u0435\u0442.<\/p>\n<p>\u041a\u0430\u0436\u0434\u0430\u044f \u043f\u0430\u043d\u0435\u043b\u044c \u2014 \u044d\u0442\u043e <code>UIView<\/code> \u0441 \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442\u0430\u043c\u0438, \u043f\u0440\u0438\u0447\u0451\u043c \u043d\u0430 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 <code>NSLayoutConstraint<\/code> \u043c\u044b \u0434\u0435\u0440\u0436\u0438\u043c \u0441\u043b\u0430\u0431\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438, \u0447\u0442\u043e\u0431\u044b \u043c\u0435\u043d\u044f\u0442\u044c \u0438\u0445 <code>constant<\/code> \u043f\u0440\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0435:<\/p>\n<pre><code class=\"swift\">private weak var spacePanelHeight: NSLayoutConstraint?private weak var largeTitleTop: NSLayoutConstraint?private weak var searchTop: NSLayoutConstraint?private weak var searchHeight: NSLayoutConstraint?private weak var closablePanelTop: NSLayoutConstraint?<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u043a\u043e\u043b\u043b\u0430\u043f\u0441\u0430 \u2014 \u044d\u0442\u043e \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 <code>CALayer<\/code>, \u0430 \u043f\u0435\u0440\u0435\u0441\u0447\u0451\u0442 <code>constant<\/code> \u0443 \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442\u043e\u0432 \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0442\u0438\u043a \u0441\u043a\u0440\u043e\u043b\u043b\u0430. \u0414\u0430\u043b\u044c\u0448\u0435 \u0441\u0442\u0430\u043d\u0435\u0442 \u0432\u0438\u0434\u043d\u043e, \u043a\u0430\u043a\u0438\u0435 \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u0442\u0435\u043a\u0430\u044e\u0442 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f.<\/p>\n<h3>\u041a\u0430\u043a \u0431\u0430\u0440 \u0446\u0435\u043f\u043b\u044f\u0435\u0442\u0441\u044f \u043a \u0441\u043a\u0440\u043e\u043b\u043b\u0443<\/h3>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0438\u0434\u0435\u044f: \u0431\u0430\u0440 \u0441\u0430\u043c \u0432\u043b\u0430\u0434\u0435\u0435\u0442 <code>contentInset.top<\/code> \u0441\u043a\u0440\u043e\u043b\u043b\u0430. \u041f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043e\u043d \u043f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043e\u0442\u0431\u0438\u0440\u0430\u0435\u0442 \u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043d\u0441\u0435\u0442\u0430\u043c\u0438:<\/p>\n<pre><code class=\"swift\">private func sync(with scrollView: UIScrollView) {    guard stack.bounds.height != 0 else { return }    \/\/ \u0434\u0430\u043b\u044c\u0448\u0435 \u0437\u0430 \u0438\u043d\u0441\u0435\u0442\u044b, scroll-to-top \u0438 \u0432\u0441\u0451 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0435 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0441\u0430\u043c \u0431\u0430\u0440    scrollView.scrollsToTop = false    scrollView.contentInsetAdjustmentBehavior = .never    let maxHeight = expandedHeight()    scrollView.contentInset.top = maxHeight    scrollView.contentOffset.y = -maxHeight}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>scrollsToTop = false<\/code> \u0438 <code>contentInsetAdjustmentBehavior = .never<\/code> \u043e\u0437\u043d\u0430\u0447\u0430\u044e\u0442, \u0447\u0442\u043e \u0432\u0441\u044f \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0437\u0430 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u044c \u0438\u043d\u0441\u0435\u0442\u043e\u0432 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043a\u0440\u043e\u043b\u043b\u0430, \u0431\u0430\u0440 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043d\u0430\u0431\u043e\u0440 KVO-\u043e\u0431\u0437\u0451\u0440\u0432\u0435\u0440\u043e\u0432:<\/p>\n<pre><code class=\"swift\">insetObserver       = scrollView.observe(\\.contentInset)  { ... }contentSizeObserver = scrollView.observe(\\.contentSize)   { ... }offsetObserver      = scrollView.observe(\\.contentOffset) { ... }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u043c\u0435\u0447\u0443: \u0441\u0430\u043c \u043a\u043e\u043b\u043b\u0430\u043f\u0441 \u0431\u0430\u0440\u0430 \u0437\u0430\u0432\u044f\u0437\u0430\u043d \u043d\u0430 KVO <code>contentOffset<\/code>, \u0430 \u043d\u0435 \u043d\u0430 <code>scrollViewDidScroll<\/code>. \u0422\u0430\u043a \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u043f\u043e \u0434\u0432\u0443\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, KVO \u043b\u043e\u0432\u0438\u0442 \u043b\u044e\u0431\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0444\u0444\u0441\u0435\u0442\u0430, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0435. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u043e\u043d\u043e \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0442\u043e\u0433\u043e, \u043a\u0442\u043e \u0432 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u043e\u043c \u0441\u043a\u0440\u043e\u043b\u043b\u0430, \u2014 \u0430 \u0434\u0435\u043b\u0435\u0433\u0430\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 (\u0441\u043d\u0430\u043f\u043f\u0438\u043d\u0433\u0430), \u0438 \u0441\u043e\u0432\u043c\u0435\u0449\u0430\u0442\u044c \u043e\u0431\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0435 \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u043e.<\/p>\n<h4>expandedHeight() \u2014 \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u043e\u0433\u043e \u0431\u0430\u0440\u0430<\/h4>\n<p>\u0427\u0442\u043e\u0431\u044b \u0432\u044b\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0439 <code>contentInset.top<\/code>, \u043d\u0443\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c \u0432\u044b\u0441\u043e\u0442\u0443 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u043e\u0433\u043e \u0431\u0430\u0440\u0430. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u0430\u0440 \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0439 (\u043f\u0430\u043d\u0435\u043b\u0438 \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0438 \u0438\u0441\u0447\u0435\u0437\u0430\u044e\u0442), \u0432\u044b\u0441\u043e\u0442\u0443 \u043f\u0440\u043e\u0449\u0435 \u0438\u0437\u043c\u0435\u0440\u0438\u0442\u044c \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e: \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0432\u044b\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u0441\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442\u044b \u0432 \u00ab\u0440\u0430\u0441\u043a\u0440\u044b\u0442\u043e\u0435\u00bb \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043f\u0440\u043e\u0433\u043d\u0430\u0442\u044c layout, \u0441\u043d\u044f\u0442\u044c <code>maxY<\/code> \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u043f\u0430\u043d\u0435\u043b\u0438 \u0438 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442\u044b \u043e\u0431\u0440\u0430\u0442\u043d\u043e.<\/p>\n<pre><code class=\"swift\">private func expandedHeight() -&gt; CGFloat {    \/\/ \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f \u0433\u043b\u0443\u0448\u0438\u043c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043e\u0431\u0437\u0451\u0440\u0432\u0435\u0440 bounds \u0441\u0442\u0435\u043a\u0430,    \/\/ \u0438\u043d\u0430\u0447\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442\u043e\u0432 \u0441\u043f\u0440\u043e\u0432\u043e\u0446\u0438\u0440\u0443\u0435\u0442 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0441\u0447\u0451\u0442    ignoreStackBoundsChanges = true    defer { ignoreStackBoundsChanges = false }    let saved = snapshotConstraints()      \/\/ \u0437\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0438\u0435 constant'\u044b    applyExpandedConstraints()             \/\/ \u0432\u044b\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u00ab\u0440\u0430\u0441\u043a\u0440\u044b\u0442\u043e\u0435\u00bb \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435    stack.layoutIfNeeded()    var height = (stack.arrangedSubviews.last?.frame.maxY ?? 0) + safeAreaInsets.top    restoreConstraints(saved)              \/\/ \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u0430\u043a \u0431\u044b\u043b\u043e    stack.layoutIfNeeded()    if let refreshControl = scrollView?.refreshControl, refreshControl.isRefreshing {        height += refreshControl.bounds.height    }    return height}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0424\u043b\u0430\u0433 <code>ignoreStackBoundsChanges<\/code> \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u0435\u043d: \u0431\u0430\u0440 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 <code>bounds<\/code> \u0441\u0442\u0435\u043a\u0430, \u0430 \u0432 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u0430\u043c \u043c\u0435\u043d\u044f\u0435\u0442 \u0435\u0433\u043e \u0442\u0443\u0434\u0430 \u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e. \u042d\u0442\u043e \u0441\u043a\u0432\u043e\u0437\u043d\u0430\u044f \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0432\u0441\u0435\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u2014 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u043c\u0435\u043d\u044f\u0435\u0442 \u0442\u043e, \u043d\u0430 \u0447\u0442\u043e \u0441\u0430\u043c \u0436\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d, \u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u043e \u0433\u043b\u0443\u0448\u0438\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043e\u0431\u0437\u0451\u0440\u0432\u0435\u0440\u044b, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0443\u0439\u0442\u0438 \u0432 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0446\u0438\u043a\u043b.<\/p>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u043d\u0435\u043f\u0440\u0438\u044f\u0442\u043d\u043e\u0441\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0441\u0442\u043e\u0438\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044c: \u043f\u0440\u0438 \u0442\u0430\u043a\u043e\u043c \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u0438 \u0432\u044b\u0441\u043e\u0442\u0430 \u0438\u043d\u043e\u0433\u0434\u0430 \u00ab\u0434\u0440\u043e\u0436\u0438\u0442\u00bb \u043d\u0430 \u043e\u0434\u0438\u043d \u043f\u0438\u043a\u0441\u0435\u043b\u044c (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0435\u0440\u0435\u0434\u0443\u0435\u0442\u0441\u044f 233 \u0438 234). \u0414\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u043d\u043e\u0439 \u043f\u0435\u0440\u0432\u043e\u043f\u0440\u0438\u0447\u0438\u043d\u044b \u044f \u043d\u0435 \u043d\u0430\u0448\u0451\u043b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u2014 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u0432\u044b\u0441\u043e\u0442 \u0441 \u043f\u043e\u0440\u043e\u0433\u043e\u043c \u0432 1pt \u0438 \u043d\u0435 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u043c\u0435\u043d\u044c\u0448\u0435. \u0414\u043b\u044f \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0430 \u044d\u0442\u043e\u0433\u043e \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e, \u0445\u043e\u0442\u044f \u043e\u0441\u0430\u0434\u043e\u043a \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f.<\/p>\n<h3>\u041a\u043e\u043b\u043b\u0430\u043f\u0441: \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u0436\u0430\u0442\u0438\u0435 \u043f\u0430\u043d\u0435\u043b\u0435\u0439<\/h3>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u2014 \u0432 \u043e\u0431\u0437\u0451\u0440\u0432\u0435\u0440\u0435 <code>contentOffset<\/code>. \u0421\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0432\u0435\u043b\u0438\u0447\u0438\u043d\u0430 \u00ab\u0443\u0442\u043e\u043f\u043b\u0435\u043d\u043d\u043e\u0441\u0442\u0438\u00bb \u0441\u043a\u0440\u043e\u043b\u043b\u0430, \u0438 \u043f\u043e \u043d\u0435\u0439 \u043f\u0430\u043d\u0435\u043b\u0438 \u0441\u0436\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0441\u0432\u0435\u0440\u0445\u0443 \u0432\u043d\u0438\u0437 \u0432 \u0441\u0442\u0440\u043e\u0433\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0437\u0430\u0437\u043e\u0440, \u0437\u0430\u0442\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430, \u0437\u0430\u0442\u0435\u043c \u043d\u0438\u0436\u043d\u0438\u0435 \u043f\u0430\u043d\u0435\u043b\u0438 \u0438 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u2014 large title.<\/p>\n<pre><code class=\"swift\">offsetObserver = scrollView.observe(\\.contentOffset, options: [.old, .new]) { [weak self] scrollView, change in    guard let self,          self.searchBar?.isActive != true,          let old = change.oldValue?.y, let new = change.newValue?.y, old != new    else { return }    var offset = scrollView.contentOffset.y + scrollView.contentInset.top               - self.startOffset + self.startCollapse    \/\/ 1. \u0437\u0430\u0437\u043e\u0440 \u043c\u0435\u0436\u0434\u0443 \u0442\u043e\u043f-\u043f\u0430\u043d\u0435\u043b\u044c\u044e \u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c \u2014 \u043a\u0430\u043a \u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e navbar    if let c = self.spacePanelHeight {        c.constant = max(-offset, 0)        self.spacePanel.isHidden = c.constant == 0    }    \/\/ 2. \u0441\u0442\u0440\u043e\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0443\u0436\u0438\u043c\u0430\u0435\u043c \u043f\u043e \u0432\u044b\u0441\u043e\u0442\u0435, \u0437\u0430\u0442\u0435\u043c \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u043c \u043d\u0430\u0432\u0435\u0440\u0445    if let searchBar, let searchHeight, let searchTop {        let target = min(searchBar.intrinsicContentSize.height - offset,                         searchBar.intrinsicContentSize.height)        searchHeight.constant = max(0, target)        \/\/ \u043f\u043e\u043f\u0443\u0442\u043d\u043e \u043f\u043b\u0430\u0432\u043d\u043e \u0433\u0430\u0441\u0438\u043c \u0438\u043a\u043e\u043d\u043a\u0443 \u043b\u0443\u043f\u044b \u0438 \u043f\u043b\u0435\u0439\u0441\u0445\u043e\u043b\u0434\u0435\u0440        \/\/ ...        offset -= (defaultSearchHeight - self.searchPanel.bounds.height)    }    \/\/ 3. closable-\u043f\u0430\u043d\u0435\u043b\u044c    \/\/ 4. large title \u2014 \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u043c \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0441 \u043a\u0440\u043e\u0441\u0441-\u0444\u0435\u0439\u0434\u043e\u043c \u043d\u0430 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a    if let largeTitleTop {        \/\/ ...        let collapsed = self.largeTitlePanel.bounds.height &lt; threshold        self.crossfade(show: collapsed ? self.compactTitle : self.largeTitle,                       hide: collapsed ? self.largeTitle : self.compactTitle)    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0441\u0442\u043e\u0438\u0442 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0434\u0432\u0443\u0445 \u0434\u0435\u0442\u0430\u043b\u044f\u0445.<\/p>\n<p><strong>\u041a\u0440\u043e\u0441\u0441-\u0444\u0435\u0439\u0434 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430.<\/strong> \u041a\u043e\u0433\u0434\u0430 large title \u0441\u0436\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u043d\u0438\u0436\u0435 \u043f\u043e\u0440\u043e\u0433\u0430, \u043d\u0443\u0436\u043d\u043e \u043f\u043b\u0430\u0432\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u043f\u043e \u0446\u0435\u043d\u0442\u0440\u0443 \u0442\u043e\u043f-\u043f\u0430\u043d\u0435\u043b\u0438 (\u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442 \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u043c \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0438). \u0412\u0430\u0436\u043d\u044b\u0439 \u043d\u044e\u0430\u043d\u0441 \u2014 \u043d\u0435\u043b\u044c\u0437\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u043f\u043e\u0432\u0435\u0440\u0445 \u0443\u0436\u0435 \u0438\u0434\u0443\u0449\u0435\u0439, \u0438\u043d\u0430\u0447\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u043c\u0435\u0440\u0446\u0430\u0442\u044c. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0443 \u0432\u044c\u044e\u0445 \u0437\u0430\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0444\u043b\u0430\u0433 \u00ab\u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0443\u0436\u0435 \u0438\u0434\u0451\u0442\u00bb, \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f:<\/p>\n<pre><code class=\"swift\">private func crossfade(show: UIView, hide: UIView, duration: TimeInterval = 0.1) {    guard show.isHidden || show.alpha != 1 else { return }    show.isAnimating = true; hide.isAnimating = true    show.alpha = 0; show.isHidden = false    UIView.animate(withDuration: duration, delay: 0, options: .beginFromCurrentState) {        show.alpha = 1        hide.alpha = 0    } completion: { finished in        guard finished else { return }        show.isAnimating = false; hide.isAnimating = false        hide.isHidden = true    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code><strong>startOffset<\/strong><\/code><strong> \u0438 <\/strong><code><strong>startCollapse<\/strong><\/code><strong>.<\/strong> \u042d\u0442\u043e \u0434\u0432\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0435 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441 \u00ab\u043e\u0442\u043a\u0443\u0434\u0430 \u043e\u0442\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u0436\u0430\u0442\u0438\u0435\u00bb. \u0415\u0441\u043b\u0438 \u044d\u043a\u0440\u0430\u043d \u043e\u0442\u043a\u0440\u044b\u0442 \u0432 \u0441\u0430\u043c\u043e\u043c \u0432\u0435\u0440\u0445\u0443 \u0441\u043f\u0438\u0441\u043a\u0430, \u0432\u0441\u0451 \u043f\u0440\u043e\u0441\u0442\u043e: \u0431\u0430\u0440 \u0441\u0436\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0435 \u0432\u043d\u0438\u0437. \u041d\u043e \u0435\u0441\u043b\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0441\u043a\u0440\u043e\u043b\u043b, \u0443\u0436\u0435 \u043a\u0443\u0434\u0430-\u0442\u043e \u043f\u0440\u043e\u0441\u043a\u0440\u043e\u043b\u043b\u0435\u043d\u043d\u044b\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0442\u0430\u0431\u043e\u0432), \u043d\u0443\u0436\u043d\u043e \u0443\u0447\u0435\u0441\u0442\u044c, \u0447\u0442\u043e \u0431\u0430\u0440 \u0443\u0436\u0435 \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e \u0441\u0436\u0430\u0442, \u0438 \u043d\u0435 \u0434\u0451\u0440\u0433\u0430\u0442\u044c \u0435\u0433\u043e \u043b\u0438\u0448\u043d\u0438\u0439 \u0440\u0430\u0437. \u042d\u0442\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0445\u0440\u0443\u043f\u043a\u0438\u0445 \u0443\u0447\u0430\u0441\u0442\u043a\u043e\u0432 \u043b\u043e\u0433\u0438\u043a\u0438, \u0438 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u043e\u043d \u0443 \u043c\u0435\u043d\u044f \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0451\u043d \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u043c \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c \u2014 \u0441\u0443\u0442\u044c \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u043e\u0447\u043a\u0430 \u043e\u0442\u0441\u0447\u0451\u0442\u0430 \u0441\u0436\u0430\u0442\u0438\u044f \u043f\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u043a\u0440\u043e\u043b\u043b\u0438\u0442 \u0432\u0432\u0435\u0440\u0445, \u0438 \u043e\u0431\u043d\u0443\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u0438 \u0432\u0435\u0440\u0445\u0430 \u0441\u043f\u0438\u0441\u043a\u0430.<\/p>\n<h3>\u0421\u043d\u0430\u043f\u043f\u0438\u043d\u0433: \u0434\u043e\u0432\u043e\u0434\u043a\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 \u0434\u043e \u0446\u0435\u043b\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/h3>\n<p>\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0436\u0438\u043c\u0430\u0442\u044c \u043f\u0430\u043d\u0435\u043b\u0438 \u043f\u043e \u043e\u0444\u0444\u0441\u0435\u0442\u0443, \u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u043e\u0442\u043f\u0443\u0441\u043a\u0430\u043d\u0438\u044f \u043f\u0430\u043b\u044c\u0446\u0430 large title \u043c\u043e\u0436\u0435\u0442 \u043e\u0441\u0442\u0430\u0442\u044c\u0441\u044f \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u044b\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 40% \u2014 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043d\u0435\u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d\u043d\u043e. \u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043d\u0430\u0432\u0431\u0430\u0440 \u0443\u043c\u0435\u0435\u0442 \u0434\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0434\u043e \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f (\u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0442\u043a\u0440\u044b\u0442 \u0438\u043b\u0438 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u043a\u0440\u044b\u0442), \u0438 \u043e\u0442 \u0441\u0432\u043e\u0435\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0442\u043e\u0433\u043e \u0436\u0435.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0443\u0436\u0435 \u043d\u0443\u0436\u0435\u043d \u0434\u0435\u043b\u0435\u0433\u0430\u0442 \u0441\u043a\u0440\u043e\u043b\u043b\u0430: \u043c\u043e\u043c\u0435\u043d\u0442 \u0434\u043e\u0432\u043e\u0434\u043a\u0438 \u043b\u043e\u0432\u0438\u0442\u0441\u044f \u0432 <code>scrollViewWillEndDragging<\/code>, \u0433\u0434\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c <code>targetContentOffset<\/code> \u2014 \u0442\u043e\u0447\u043a\u0443, \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0441\u043a\u0440\u043e\u043b\u043b \u043f\u0440\u0438\u043b\u0435\u0442\u0438\u0442 \u043f\u043e\u0441\u043b\u0435 \u0438\u043d\u0435\u0440\u0446\u0438\u0438.<\/p>\n<pre><code class=\"swift\">scrollProxy.onWillEndDragging = { [weak self] scrollView, velocity, targetContentOffset in    guard let self, abs(velocity.y) &gt; 0 else { return }    \/\/ \u0441\u0447\u0438\u0442\u0430\u0435\u043c, \u043a\u0430\u043a\u0438\u043c\u0438 \u0431\u044b\u043b\u0438 \u0431\u044b \u0432\u044b\u0441\u043e\u0442\u044b \u043f\u0430\u043d\u0435\u043b\u0435\u0439 \u0432 \u0442\u043e\u0447\u043a\u0435 targetContentOffset,    \/\/ \u0438 \u0441\u0434\u0432\u0438\u0433\u0430\u0435\u043c \u044d\u0442\u0443 \u0442\u043e\u0447\u043a\u0443 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043f\u0430\u043d\u0435\u043b\u044c \u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u043b\u0438\u0431\u043e \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u0439,    \/\/ \u043b\u0438\u0431\u043e \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u043a\u0440\u044b\u0442\u043e\u0439 \u2014 \u043d\u043e \u043d\u0435 \u043f\u043e\u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435    let diff = self.searchPanelBaseHeight - projectedSearchHeight    if diff &lt; self.searchPanelBaseHeight \/ 2 {        targetContentOffset.pointee.y -= diff             \/\/ \u0434\u043e\u0440\u0430\u0441\u043a\u0440\u044b\u0442\u044c    } else if projectedSearchHeight != 0 {        targetContentOffset.pointee.y += projectedSearchHeight   \/\/ \u0434\u043e\u0437\u0430\u043a\u0440\u044b\u0442\u044c    }    \/\/ \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0434\u043b\u044f large title}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439, \u043a\u043e\u0433\u0434\u0430 \u0438\u043d\u0435\u0440\u0446\u0438\u0438 \u043d\u0435\u0442 \u0432\u043e\u043e\u0431\u0449\u0435 (\u043f\u0430\u043b\u0435\u0446 \u043e\u0442\u043f\u0443\u0441\u0442\u0438\u043b\u0438 \u043f\u043e\u0447\u0442\u0438 \u0431\u0435\u0437 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438), \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d \u0437\u0430\u043f\u0430\u0441\u043d\u043e\u0439 \u043f\u0443\u0442\u044c \u0447\u0435\u0440\u0435\u0437 <code>scrollViewDidEndDragging<\/code> \/ <code>scrollViewDidEndDecelerating<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u0432\u043e\u0434\u0438\u0442 \u043f\u0430\u043d\u0435\u043b\u044c \u0443\u0436\u0435 \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c <code>setContentOffset(_:animated:)<\/code>. \u041b\u043e\u0433\u0438\u043a\u0430 \u0442\u0430\u043a\u0430\u044f: \u0435\u0441\u043b\u0438 \u0431\u0443\u0434\u0435\u0442 deceleration \u2014 \u0432\u0441\u0451 \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u043d\u043e \u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u0448\u0430\u0433\u0435; \u0435\u0441\u043b\u0438 \u0436\u0435 \u0433\u0434\u0435-\u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u043d\u0435\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c \u2014 \u0435\u0451 \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442 \u0432\u044b\u0437\u043e\u0432 \u0442\u043e\u0439 \u0436\u0435 \u0434\u043e\u0432\u043e\u0434\u043a\u0438 \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u043d\u043e\u0439 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0430. \u0422\u043e \u0435\u0441\u0442\u044c \u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u0443\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0430\u043a \u0441\u0442\u0440\u0430\u0445\u043e\u0432\u043a\u0430 \u043e\u0442 \u043f\u043e\u0433\u0440\u0435\u0448\u043d\u043e\u0441\u0442\u0435\u0439 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0440\u0430\u0441\u0447\u0451\u0442\u0430.<\/p>\n<h3>\u0414\u0435\u043b\u0435\u0433\u0430\u0442-\u043f\u0440\u043e\u043a\u0441\u0438: \u0440\u0430\u0431\u043e\u0442\u0430 \u0441\u043e \u0441\u043a\u0440\u043e\u043b\u043b\u043e\u043c \u0431\u0435\u0437 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430 \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u0430 \u0443 \u044d\u043a\u0440\u0430\u043d\u0430<\/h3>\n<p>\u042d\u0442\u043e \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c.<\/p>\n<p>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430: \u0434\u043b\u044f \u0441\u043d\u0430\u043f\u043f\u0438\u043d\u0433\u0430 \u043d\u0443\u0436\u0435\u043d \u0434\u0435\u043b\u0435\u0433\u0430\u0442 \u0441\u043a\u0440\u043e\u043b\u043b\u0430. \u041d\u043e \u0434\u0435\u043b\u0435\u0433\u0430\u0442 \u0443\u0436\u0435 \u0437\u0430\u043d\u044f\u0442 \u2014 \u0443 <code>UITableView<\/code> \u044d\u0442\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u044d\u043a\u0440\u0430\u043d\u0430, \u0443 Texture \u044d\u0442\u043e <code>ASTableNode.delegate<\/code>. \u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u0431\u0440\u0430\u0442\u044c \u0434\u0435\u043b\u0435\u0433\u0430\u0442 \u0441\u0435\u0431\u0435, \u044d\u043a\u0440\u0430\u043d \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c <code>didSelectRow<\/code>, <code>willDisplay<\/code>, batch-fetch \u0438 \u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432. \u0415\u0441\u043b\u0438 \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0434\u0435\u043b\u0435\u0433\u0430\u0442 \u044d\u043a\u0440\u0430\u043d\u0443 \u2014 \u0441\u043d\u0430\u043f\u043f\u0438\u043d\u0433 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u0433\u0434\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c.<\/p>\n<p>\u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u2014 \u043f\u0440\u043e\u043a\u0441\u0438-\u0434\u0435\u043b\u0435\u0433\u0430\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0444\u043e\u0440\u0432\u0430\u0440\u0434\u0438\u0442 \u0432\u0441\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u0443 \u0438 \u043f\u043e\u043f\u0443\u0442\u043d\u043e \u0434\u0451\u0440\u0433\u0430\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u044b. \u0417\u0434\u0435\u0441\u044c \u0434\u0432\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438:<\/p>\n<ol>\n<li>\n<p>\u042d\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0438\u043f\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c\u0438 Swift, \u0430 \u043d\u0435 \u0447\u0435\u0440\u0435\u0437 <code>NSProxy<\/code> \/ message-forwarding: \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u044b Texture \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u0443\u044e\u0442\u0441\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0438\u043f\u043e\u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u2014 <code>UIScrollView<\/code>, <code>UITableView<\/code>, <code>UICollectionView<\/code>, <code>ASTableNode<\/code>, <code>ASCollectionNode<\/code>, \u0438 \u0443 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0432\u043e\u0439 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u0430.<\/p>\n<\/li>\n<\/ol>\n<p>\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u043a\u0441\u0438 \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a\u043e\u043c \u043f\u043e \u0442\u0438\u043f\u0443 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u0430:<\/p>\n<pre><code class=\"swift\">class ScrollProxy&lt;Delegate: UIScrollViewDelegate&gt;: NSObject, UIScrollViewDelegate {    weak var target: Delegate?    var onWillEndDragging: ((UIScrollView, CGPoint, UnsafeMutablePointer&lt;CGPoint&gt;) -&gt; Void)?    var onDidEndDragging:  ((UIScrollView, Bool) -&gt; Void)?    var onDidEndDecelerating: ((UIScrollView) -&gt; Void)?    init(target: Delegate?) { self.target = target }    func scrollViewWillEndDragging(_ scrollView: UIScrollView,                                   withVelocity velocity: CGPoint,                                   targetContentOffset: UnsafeMutablePointer&lt;CGPoint&gt;) {        target?.scrollViewWillEndDragging?(scrollView, withVelocity: velocity,                                           targetContentOffset: targetContentOffset)        onWillEndDragging?(scrollView, velocity, targetContentOffset)   \/\/ \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0445\u0443\u043a    }    \/\/ ... \u0438 \u0442\u0430\u043a \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0444\u043e\u0440\u0432\u0430\u0440\u0434\u044f\u0442\u0441\u044f \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b UIScrollViewDelegate}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>target<\/code> \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d <code>weak<\/code>, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u044d\u043a\u0440\u0430\u043d. \u0418\u0437-\u0437\u0430 \u044d\u0442\u043e\u0433\u043e \u0441\u0430\u043c\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e, \u0445\u0440\u0430\u043d\u044f\u0449\u0435\u0435 \u043f\u0440\u043e\u043a\u0441\u0438 \u0432 \u0431\u0430\u0440\u0435, \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0441\u0438\u043b\u044c\u043d\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u043e\u0439 \u2014 \u0438\u043d\u0430\u0447\u0435 \u043f\u0440\u043e\u043a\u0441\u0438 \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0451\u043d \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438.<\/p>\n<p>\u041f\u043e\u0434 \u043a\u0430\u0436\u0434\u044b\u0439 \u0442\u0438\u043f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u2014 \u043f\u043e\u0434\u043a\u043b\u0430\u0441\u0441, \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u043a\u0441\u0438 \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0438\u0439 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430:<\/p>\n<pre><code class=\"swift\">final class TableNodeProxy: ScrollProxy&lt;ASTableDelegate&gt;, ASTableDelegate {    func tableNode(_ node: ASTableNode, didSelectRowAt indexPath: IndexPath) {        target?.tableNode?(node, didSelectRowAt: indexPath)    }    func shouldBatchFetch(for node: ASTableNode) -&gt; Bool {        target?.shouldBatchFetch?(for: node) ?? false    }    \/\/ ... \u0435\u0449\u0451 ~30 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 ASTableDelegate, \u043a\u0430\u0436\u0434\u044b\u0439 \u0444\u043e\u0440\u0432\u0430\u0440\u0434\u0438\u0442\u0441\u044f \u0432\u0440\u0443\u0447\u043d\u0443\u044e}final class CollectionNodeProxy: ScrollProxy&lt;ASCollectionDelegate&gt;, ASCollectionDelegateFlowLayout { ... }final class TableViewProxy: ScrollProxy&lt;UITableViewDelegate&gt;, UITableViewDelegate { ... }final class CollectionViewProxy: ScrollProxy&lt;UICollectionViewDelegate&gt;, UICollectionViewDelegate { ... }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u0430, \u0434\u0435\u0441\u044f\u0442\u043a\u0438 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u0430 \u0444\u043e\u0440\u0432\u0430\u0440\u0434\u044f\u0442\u0441\u044f \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u0435 \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439. \u042d\u0442\u043e \u043c\u043d\u043e\u0433\u043e\u0441\u043b\u043e\u0432\u043d\u043e, \u043d\u043e \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u043e\u043c \u2014 \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0440\u0430\u043d\u0442\u0430\u0439\u043c-\u043c\u0430\u0433\u0438\u0438.<\/p>\n<p>\u041f\u043e\u0434\u043c\u0435\u043d\u0430 \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043a\u0440\u043e\u043b\u043b\u0430: \u043f\u043e \u0435\u0433\u043e \u0442\u0438\u043f\u0443 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043d\u0443\u0436\u043d\u044b\u0439 \u043f\u043e\u0434\u043a\u043b\u0430\u0441\u0441 \u043f\u0440\u043e\u043a\u0441\u0438, \u0430 \u0441\u0442\u0430\u0440\u043e\u043c\u0443 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0443 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0435\u0433\u043e \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0434\u0435\u043b\u0435\u0433\u0430\u0442:<\/p>\n<pre><code class=\"swift\">private func attach(_ scrollView: UIScrollView) {    \/\/ \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0443 \u0435\u0433\u043e \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0434\u0435\u043b\u0435\u0433\u0430\u0442    detachCurrentProxy()    \/\/ \u043d\u0430\u0432\u0435\u0441\u0438\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u043f\u0440\u043e\u043a\u0441\u0438 \u043d\u0430 \u043d\u043e\u0432\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440    if let node = (scrollView as? ASTableView)?.tableNode {        let proxy = TableNodeProxy(target: node.delegate)        self.scrollProxy = proxy        \/\/ \u0441\u0438\u043b\u044c\u043d\u0430\u044f \u0441\u0441\u044b\u043b\u043a\u0430        node.delegate = proxy    } else if let node = (scrollView as? ASCollectionView)?.collectionNode {        \/\/ ...    } else if let table = scrollView as? UITableView {        \/\/ ...    } \/\/ ... UICollectionView \/ \u043f\u0440\u043e\u0441\u0442\u043e UIScrollView}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u043e \u0432\u0441\u0442\u0440\u043e\u0438\u0442\u044c\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u044d\u043a\u0440\u0430\u043d\u043e\u043c \u0438 \u0435\u0433\u043e \u0441\u043a\u0440\u043e\u043b\u043b\u043e\u043c \u0441\u0440\u0430\u0437\u0443 \u0434\u043b\u044f \u0434\u0432\u0443\u0445 \u0441\u0442\u0435\u043a\u043e\u0432 \u2014 UIKit \u0438 Texture \u2014 \u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u0430\u0447\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0432\u043e \u0432\u0441\u0435\u0439 \u044d\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435.<\/p>\n<h3>\u041a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441\u044b \u0438 \u043e\u0431\u0445\u043e\u0434\u043d\u044b\u0435 \u043f\u0443\u0442\u0438<\/h3>\n<p>\u041d\u0438\u0436\u0435 \u2014 \u0432\u0435\u0449\u0438, \u0431\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e, \u043d\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0435\u0434\u043a\u043e \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0432 \u0443\u0447\u0435\u0431\u043d\u0438\u043a\u0438.<\/p>\n<h4>1. \u0421\u0432\u0438\u0437\u0437\u043b UIRefreshControl.endRefreshing<\/h4>\n<p>\u041f\u0440\u0438 pull-to-refresh iOS \u043d\u0430 <code>endRefreshing<\/code> \u0441\u0430\u043c \u043f\u043e\u0434\u043a\u0440\u0443\u0447\u0438\u0432\u0430\u0435\u0442 <code>contentInset.top<\/code>. \u041d\u043e \u0432 \u044d\u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 <code>isRefreshing<\/code> \u0435\u0449\u0451 \u0440\u0430\u0432\u0435\u043d <code>true<\/code>, \u0438\u0437-\u0437\u0430 \u0447\u0435\u0433\u043e \u0440\u0430\u0441\u0447\u0451\u0442 \u0438\u043d\u0441\u0435\u0442\u0430 (\u043e\u043d \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0432\u044b\u0441\u043e\u0442\u044b refresh control) \u0432\u044b\u0434\u0430\u0451\u0442 \u043d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. \u041e\u0434\u0438\u043d \u0438\u0437 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u043b\u0435\u0447\u0435\u043d\u0438\u044f \u2014 \u043f\u043e\u0434\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e <code>endRefreshing<\/code> \u0438 \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u0451 \u00ab\u043f\u043d\u0443\u0442\u044c\u00bb \u0438\u043d\u0441\u0435\u0442 \u043d\u0430 +1\/\u22121, \u0447\u0442\u043e\u0431\u044b \u0431\u0430\u0440 \u043f\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u0430\u043b\u0441\u044f \u043f\u043e KVO:<\/p>\n<pre><code class=\"swift\">extension UIRefreshControl {    @objc dynamic func swizzled_endRefreshing() {        swizzled_endRefreshing()                  \/\/ \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b (\u043f\u043e\u0441\u043b\u0435 swizzle \u044d\u0442\u043e \u043e\u043d \u0438 \u0435\u0441\u0442\u044c)        guard let scrollView = superview as? UIScrollView else { return }        scrollView.contentInset.top += 1        scrollView.contentInset.top -= 1          \/\/ \u0441\u043f\u0440\u043e\u0432\u043e\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c KVO contentInset    }}private func swizzleRefreshControlOnce() {    guard !Self.didSwizzle else { return }    Self.didSwizzle = true    let original = class_getInstanceMethod(UIRefreshControl.self, #selector(UIRefreshControl.endRefreshing))!    let swizzled = class_getInstanceMethod(UIRefreshControl.self, #selector(UIRefreshControl.swizzled_endRefreshing))!    method_exchangeImplementations(original, swizzled)}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0424\u043b\u0430\u0433 <code>didSwizzle<\/code> \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442, \u0447\u0442\u043e \u043f\u043e\u0434\u043c\u0435\u043d\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0451\u0442 \u0440\u043e\u0432\u043d\u043e \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u043d\u0430 \u0432\u0441\u0451 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0421\u0432\u0438\u0437\u0437\u043b \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435 \u2014 \u043d\u0435 \u043b\u0443\u0447\u0448\u0430\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430, \u0438 \u044f \u0434\u0435\u0440\u0436\u0443 \u044d\u0442\u043e \u043c\u0435\u0441\u0442\u043e \u043d\u0430 \u043e\u0441\u043e\u0431\u043e\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435; \u043d\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u043f\u043e\u0439\u043c\u0430\u0442\u044c \u043d\u0443\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0431\u0435\u0437 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u0445\u0430\u043a\u043e\u0432 \u044f \u043d\u0435 \u043d\u0430\u0448\u0451\u043b. \u042d\u0442\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441, \u0430 \u043d\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u044f.<\/p>\n<h4>2. scroll-to-top \u0447\u0435\u0440\u0435\u0437 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u043a\u0440\u043e\u043b\u043b<\/h4>\n<p>\u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 scroll-to-top (\u0442\u0430\u043f \u043f\u043e \u0441\u0442\u0430\u0442\u0443\u0441-\u0431\u0430\u0440\u0443) \u043f\u0440\u043e\u0441\u0442\u043e \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e \u043f\u0440\u044b\u0433\u0430\u0435\u0442 \u043a \u0432\u0435\u0440\u0445\u0443 \u0441\u043f\u0438\u0441\u043a\u0430. \u041c\u043d\u0435 \u0436\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0434\u043e\u0432\u043e\u0434\u043a\u0438 \u2014 \u0441 \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u043c \u043f\u0440\u0443\u0436\u0438\u043d\u044b (\u043b\u0451\u0433\u043a\u0438\u043c overshoot \u0443 \u0432\u0435\u0440\u0445\u043d\u0435\u0439 \u0433\u0440\u0430\u043d\u0438\u0446\u044b), \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043d\u0435 \u0434\u0430\u0451\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0448\u0442\u0430\u0442\u043d\u044b\u0439 scroll-to-top \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f (<code>scrollsToTop = false<\/code>), \u0430 \u0432\u043c\u0435\u0441\u0442\u043e \u043d\u0435\u0433\u043e \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044f \u0441\u0432\u043e\u0439: \u043f\u043e\u0432\u0435\u0440\u0445 \u0431\u0430\u0440\u0430 \u043a\u043b\u0430\u0434\u0451\u0442\u0441\u044f \u043d\u0435\u0432\u0438\u0434\u0438\u043c\u044b\u0439 <code>UIScrollView<\/code> \u0441 <code>scrollsToTop = true<\/code>, \u0438 \u0442\u0430\u043f \u043b\u043e\u0432\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0435\u0433\u043e \u0434\u0435\u043b\u0435\u0433\u0430\u0442:<\/p>\n<pre><code class=\"swift\">private lazy var statusBarTapCatcher: UIScrollView = {    let view = UIScrollView()    view.delegate = scrollToTopCatcher    view.contentSize = CGSize(width: 0, height: 1000)    view.contentOffset.y = 1     \/\/ \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u043e \u043a\u0443\u0434\u0430 \u00ab\u0441\u043a\u0440\u043e\u043b\u043b\u0438\u0442\u044c\u0441\u044f \u043a \u0432\u0435\u0440\u0445\u0443\u00bb    return view}()private final class ScrollToTopCatcher: NSObject, UIScrollViewDelegate {    let action: () -&gt; Void    init(action: @escaping () -&gt; Void) { self.action = action }    func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -&gt; Bool {        defer { action() }        return false             \/\/ \u0441\u0430\u043c \u043d\u0435 \u0441\u043a\u0440\u043e\u043b\u043b\u044e\u0441\u044c, \u043d\u043e \u0442\u0430\u043f \u043f\u043e\u0439\u043c\u0430\u043d \u2014 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e \u0441\u0432\u043e\u044e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0420\u0430\u0434\u0438 \u044d\u0442\u043e\u0433\u043e \u0432\u0441\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f scroll-to-top \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u043c: <code>contentOffset<\/code> \u0433\u043e\u043d\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 display-link-\u0430\u043d\u0438\u043c\u0430\u0442\u043e\u0440 \u0441 \u043f\u043e\u0434\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u043c\u0438 \u043a\u0440\u0438\u0432\u044b\u043c\u0438 \u0411\u0435\u0437\u044c\u0435 (\u0441 <code>y<\/code> &gt; 1 \u043d\u0430 \u043a\u043e\u043d\u0446\u0435 \u2014 \u044d\u0442\u043e \u0438 \u0434\u0430\u0451\u0442 \u043f\u0440\u0443\u0436\u0438\u043d\u0438\u0441\u0442\u044b\u0439 overshoot), \u0430 \u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u043d\u043e\u0439 \u0434\u0438\u0441\u0442\u0430\u043d\u0446\u0438\u0438, \u043f\u0440\u0438\u0447\u0451\u043c \u043f\u043e\u0434 \u0440\u0430\u0437\u043d\u044b\u0435 \u0434\u0438\u0441\u0442\u0430\u043d\u0446\u0438\u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0440\u0430\u0437\u043d\u044b\u0435 timing-\u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u042d\u0442\u043e \u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0433\u043e, \u043d\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u0442 \u0441\u0430\u043c\u044b\u0439 \u044d\u0444\u0444\u0435\u043a\u0442 \u043f\u0440\u0443\u0436\u0438\u043d\u044b, \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c.<\/p>\n<h4>3. \u0417\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 \u0440\u0435\u0430\u043a\u0446\u0438\u0438 \u043d\u0430 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f<\/h4>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u0430\u0440 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d \u043f\u043e KVO \u043d\u0430 <code>contentInset<\/code>, <code>contentOffset<\/code>, <code>contentSize<\/code>, <code>bounds<\/code> \u0438 \u0441\u0430\u043c \u0436\u0435 \u0432\u0441\u0451 \u044d\u0442\u043e \u043c\u0435\u043d\u044f\u0435\u0442, \u0437\u0430\u043c\u0435\u0442\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043a\u043e\u0434\u0430 \u2014 \u044d\u0442\u043e \u0444\u043b\u0430\u0433\u0438 \u0438 guard-\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u00ab\u043d\u0435 \u044f \u043b\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u044d\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u00bb: <code>ignoreStackBoundsChanges<\/code>, \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u00ab\u044d\u0442\u043e \u0442\u043e\u0442 \u0441\u0430\u043c\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0439 \u0441\u043a\u0440\u043e\u043b\u043b\u00bb, \u043f\u043e\u0440\u043e\u0433\u0438 \u0432 1pt. \u0411\u0435\u0437 \u043d\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0443\u0445\u043e\u0434\u0438\u0442 \u0432 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0439 layout \u0438 \u0444\u0440\u0438\u0437. \u042d\u0442\u043e \u043f\u0440\u044f\u043c\u043e\u0435 \u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0435 \u0440\u0443\u0447\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u043d\u0441\u0435\u0442\u0430\u043c\u0438.<\/p>\n<h3>\u0427\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u043d\u0430\u0447\u0435<\/h3>\n<p>\u0417\u0430\u043c\u0435\u0442\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 (1pt-\u044d\u0444\u0444\u0435\u043a\u0442\u044b, \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0435 KVO, \u0441\u0432\u0438\u0437\u0437\u043b refresh control) \u0440\u0430\u0441\u0442\u0451\u0442 \u0438\u0437 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f <code>contentInset<\/code>: \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0432\u044b\u0441\u043e\u0442\u0443 \u0441 \u0438\u043d\u0441\u0435\u0442\u043e\u043c \u0441\u043a\u0440\u043e\u043b\u043b\u0430. \u0421\u043e\u0431\u043b\u0430\u0437\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0435\u0448\u0438\u0442\u044c, \u0447\u0442\u043e \u00ab\u043d\u0430\u0434\u043e \u0431\u044b\u043b\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u043d\u0430\u0447\u0435\u00bb \u2014 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0431\u0430\u0440 \u043e\u0432\u0435\u0440\u043b\u0435\u0435\u043c \u043d\u0430\u0434 \u0441\u043a\u0440\u043e\u043b\u043b\u043e\u043c \u0438 \u043d\u0435 \u0442\u0440\u043e\u0433\u0430\u0442\u044c \u0438\u043d\u0441\u0435\u0442\u044b. \u041d\u043e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u044d\u0442\u043e, \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u043d\u0435 \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u0435, \u0430 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442: \u043e\u0432\u0435\u0440\u043b\u0435\u044e \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0441\u0434\u0432\u0438\u0433\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043d\u0442, \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0441 \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438, refresh control, scroll-to-top \u0438 safe area \u2014 \u0442\u043e \u0435\u0441\u0442\u044c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u0440\u043e\u0432\u043d\u043e \u0442\u0443 \u0440\u0430\u0431\u043e\u0442\u0443, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0441\u0435\u0439\u0447\u0430\u0441 \u0437\u0430 \u043d\u0430\u0441 \u0434\u0435\u043b\u0430\u0435\u0442 <code>contentInset<\/code>, \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u0435\u0437 \u043f\u043e\u043c\u043e\u0449\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b. \u0422\u0430\u043a \u0447\u0442\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043d\u0441\u0435\u0442\u043e\u043c \u0437\u0434\u0435\u0441\u044c \u2014 \u043d\u0435 \u043b\u0438\u0448\u043d\u0435\u0435 \u0443\u0441\u043b\u043e\u0436\u043d\u0435\u043d\u0438\u0435, \u0430, \u043f\u043e\u0445\u043e\u0436\u0435, \u043d\u0430\u0438\u043c\u0435\u043d\u0435\u0435 \u0431\u043e\u043b\u0435\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0438\u0437 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432. \u0421\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0442\u0443\u0442 \u043d\u0435 \u0432 \u0432\u044b\u0431\u043e\u0440\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0430, \u0430 \u0432 \u0441\u0430\u043c\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435: \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435, \u043d\u0435 \u0438\u043c\u0435\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430.<\/p>\n<p>\u0427\u0442\u043e \u0442\u043e\u0447\u043d\u043e \u043e\u043f\u0440\u0430\u0432\u0434\u0430\u043b\u043e \u0441\u0435\u0431\u044f:<\/p>\n<ul>\n<li>\n<p><strong>\u043f\u0440\u043e\u043a\u0441\u0438-\u0434\u0435\u043b\u0435\u0433\u0430\u0442 \u043a\u0430\u043a \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a<\/strong> \u2014 \u0435\u0434\u0438\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0434\u043b\u044f UIKit \u0438 Texture, \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u043c \u043f\u043e\u0434\u043a\u043b\u0430\u0441\u0441\u043e\u043c \u0437\u0430 \u0441\u0447\u0438\u0442\u0430\u043d\u043d\u044b\u0435 \u043c\u0438\u043d\u0443\u0442\u044b;<\/p>\n<\/li>\n<li>\n<p><strong>\u043a\u043e\u043b\u043b\u0430\u043f\u0441 \u0447\u0435\u0440\u0435\u0437 KVO <\/strong><code><strong>contentOffset<\/strong><\/code> \u0432\u043c\u0435\u0441\u0442\u043e \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u0430 \u2014 \u044d\u0442\u043e \u043e\u0442\u0432\u044f\u0437\u0430\u043b\u043e \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043e\u0442 \u0442\u043e\u0433\u043e, \u043a\u0442\u043e \u0432\u043b\u0430\u0434\u0435\u0435\u0442 \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u043e\u043c \u0441\u043a\u0440\u043e\u043b\u043b\u0430;<\/p>\n<\/li>\n<li>\n<p><strong>\u0441\u043d\u0430\u043f\u043f\u0438\u043d\u0433 \u0447\u0435\u0440\u0435\u0437 <\/strong><code><strong>targetContentOffset<\/strong><\/code><strong> \u0441 \u0437\u0430\u043f\u0430\u0441\u043d\u044b\u043c \u043f\u0443\u0442\u0451\u043c<\/strong> \u2014 \u0434\u0430\u0451\u0442 \u043f\u043b\u0430\u0432\u043d\u0443\u044e \u0434\u043e\u0432\u043e\u0434\u043a\u0443 \u0431\u0435\u0437 \u0440\u044b\u0432\u043a\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1049644\/\">https:\/\/habr.com\/ru\/articles\/1049644\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0451\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e UINavigationBar \u0438 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0431\u0430\u0440 \u043d\u0430 \u043e\u0431\u044b\u0447\u043d\u043e\u043c UIView: \u0441 \u043a\u043e\u043b\u043b\u0430\u043f\u0441\u0438\u0440\u0443\u044e\u0449\u0438\u043c large title \u043a\u0430\u043a \u0443 Apple, \u0441\u043e \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u043f\u043e\u0438\u0441\u043a\u0430, \u0441 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u0430\u043d\u0435\u043b\u044f\u043c\u0438 \u043f\u043e\u0434 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c \u2014 \u0438 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0441 UITableView, \u043d\u043e \u0438 \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u0430\u043c\u0438 \u043d\u0430 Texture (AsyncDisplayKit).\u042f \u0434\u0435\u043b\u0430\u043b \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u043a\u0440\u0443\u043f\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438 \u043e\u043d \u0434\u0430\u0432\u043d\u043e \u0436\u0438\u0432\u0451\u0442 \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435. \u041d\u0438\u0436\u0435 \u2014 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0438, \u0447\u0442\u043e \u0432\u0430\u0436\u043d\u0435\u0435, \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441\u044b: \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0447\u0435\u0441\u0442\u043d\u044b\u0439 \u0440\u0430\u0437\u0431\u043e\u0440 \u043e\u0431\u0445\u043e\u0434\u043d\u044b\u0445 \u043f\u0443\u0442\u0435\u0439 \u043f\u043e\u043b\u0435\u0437\u043d\u0435\u0435 \u043f\u0440\u0438\u0447\u0451\u0441\u0430\u043d\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438, \u0433\u0434\u0435 \u0432\u0441\u0451 \u0441\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0441 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0440\u0430\u0437\u0430.\u0417\u0430\u0447\u0435\u043c \u043d\u0443\u0436\u0435\u043d \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 navbar\u041d\u0430\u0431\u043e\u0440 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u0431\u044b\u043b \u0442\u0430\u043a\u043e\u0439:large title, \u043f\u043b\u0430\u0432\u043d\u043e \u0441\u0436\u0438\u043c\u0430\u044e\u0449\u0438\u0439\u0441\u044f \u043f\u0440\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0435 \u2014 \u043a\u0430\u043a \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439;\u043f\u043e\u0434 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c \u2014 \u0441\u0442\u0440\u043e\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0442\u043e\u0436\u0435 \u043a\u043e\u043b\u043b\u0430\u043f\u0441\u0438\u0442 \u043f\u0440\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0435, \u0430 \u0432 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0432\u0441\u044e \u0448\u0438\u0440\u0438\u043d\u0443;\u043f\u043e\u0434 \u043f\u043e\u0438\u0441\u043a\u043e\u043c \u2014 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u043d\u0435\u043b\u0438, \u0447\u0430\u0441\u0442\u044c \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0434\u043e\u043b\u0436\u043d\u0430 \u0443\u0435\u0437\u0436\u0430\u0442\u044c \u043f\u0440\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0435, \u0447\u0430\u0441\u0442\u044c \u2014 \u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c\u0441\u044f;\u0440\u0430\u0437\u043c\u044b\u0442\u044b\u0439 \u0444\u043e\u043d (UIVisualEffectView), \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0449\u0438\u0439\u0441\u044f \u0438 \u0438\u0441\u0447\u0435\u0437\u0430\u044e\u0449\u0438\u0439 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0430;\u0438, \u0447\u0442\u043e \u0432\u0430\u0436\u043d\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u044c \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0442\u0438\u043f\u0430\u043c\u0438 \u0441\u043a\u0440\u043e\u043b\u043b-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432: \u0447\u0430\u0441\u0442\u044c \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u043d\u0430 UIKit, \u0447\u0430\u0441\u0442\u044c \u2014 \u043d\u0430 Texture (ASTableNode \/ ASCollectionNode).\u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 UINavigationBar \u0441 prefersLargeTitles \u0438 UISearchController \u0432 \u0442\u0435\u043e\u0440\u0438\u0438 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u043c\u043d\u043e\u0433\u043e\u0435. \u041d\u043e \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u043f\u0430\u043d\u0435\u043b\u0438, \u043d\u0443\u0436\u043d\u043e \u0442\u043e\u0447\u043d\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043c\u043e\u043c\u0435\u043d\u0442\u043e\u043c \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0431\u043b\u044e\u0440\u0430, \u0442\u043e\u043d\u043a\u043e \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u0441\u043d\u0430\u043f\u043f\u0438\u043d\u0433 \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043f\u043e\u0434\u0440\u0443\u0436\u0438\u0442\u044c \u0432\u0441\u0451 \u0441 Texture \u2014 \u0442\u043e\u0447\u0435\u043a \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u043f\u043e\u0447\u0442\u0438 \u043d\u0435 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f. \u0412 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043c\u043e\u043c\u0435\u043d\u0442 \u0434\u0435\u0448\u0435\u0432\u043b\u0435 \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 UIView, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u043f\u0440\u0438\u0442\u0432\u043e\u0440\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u0432\u0431\u0430\u0440\u043e\u043c, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u0436\u0438\u0432\u0451\u0442 \u0441\u0432\u0435\u0440\u0445\u0443 \u044d\u043a\u0440\u0430\u043d\u0430 \u0438 \u0441\u0430\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0441\u0435\u0442\u0430\u043c\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0430.\u041d\u0430\u0437\u043e\u0432\u0451\u043c \u0435\u0433\u043e CollapsingNavBar. \u0414\u0430\u043b\u044c\u0448\u0435 \u2014 \u043f\u043e \u0447\u0430\u0441\u0442\u044f\u043c.\u0410\u043d\u0430\u0442\u043e\u043c\u0438\u044f: \u0431\u0430\u0440 \u043a\u0430\u043a \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0442\u0435\u043a \u043f\u0430\u043d\u0435\u043b\u0435\u0439\u0420\u0430\u0441\u043a\u043b\u0430\u0434\u043a\u0430 \u043f\u0440\u044f\u043c\u043e\u043b\u0438\u043d\u0435\u0439\u043d\u0430 \u2014 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 UIStackView, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443 \u043b\u0435\u0436\u0430\u0442 \u043f\u0430\u043d\u0435\u043b\u0438:stack.addArrangedSubviews(    topPanel,          \/\/ \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 44pt: left-\u043a\u043d\u043e\u043f\u043a\u0430, title, right-\u043a\u043d\u043e\u043f\u043a\u0438    spacePanel,        \/\/ \u0440\u0430\u0441\u0442\u044f\u0433\u0438\u0432\u0430\u044e\u0449\u0438\u0439\u0441\u044f \u0437\u0430\u0437\u043e\u0440 (\u043a\u0430\u043a \u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e large title)    largeTitlePanel,   \/\/ \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a    searchPanel,       \/\/ \u0441\u0442\u0440\u043e\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430    closablePanel,     \/\/ \u043f\u0430\u043d\u0435\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0443\u0435\u0437\u0436\u0430\u0435\u0442 \u043f\u0440\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0435    pinnedPanel,       \/\/ \u043f\u0430\u043d\u0435\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f    separatorLine      \/\/ \u043d\u0438\u0436\u043d\u044f\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043b\u0438\u043d\u0438\u044f)\u041f\u043e\u0434 \u0444\u043e\u043d\u043e\u043c \u043b\u0435\u0436\u0430\u0442 backgroundView (\u0441\u043f\u043b\u043e\u0448\u043d\u043e\u0439 \u0446\u0432\u0435\u0442) \u0438 blurView (UIVisualEffectView); \u043e\u043d\u0438 \u043f\u043e\u0434\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e, \u0440\u0430\u0441\u043a\u0440\u044b\u0442 large title \u0438\u043b\u0438 \u043d\u0435\u0442.\u041a\u0430\u0436\u0434\u0430\u044f \u043f\u0430\u043d\u0435\u043b\u044c \u2014 \u044d\u0442\u043e UIView \u0441 \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442\u0430\u043c\u0438, \u043f\u0440\u0438\u0447\u0451\u043c \u043d\u0430 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 NSLayoutConstraint \u043c\u044b \u0434\u0435\u0440\u0436\u0438\u043c \u0441\u043b\u0430\u0431\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438, \u0447\u0442\u043e\u0431\u044b \u043c\u0435\u043d\u044f\u0442\u044c \u0438\u0445 constant \u043f\u0440\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0435:private weak var spacePanelHeight: NSLayoutConstraint?private weak var largeTitleTop: NSLayoutConstraint?private weak var searchTop: NSLayoutConstraint?private weak var searchHeight: NSLayoutConstraint?private weak var closablePanelTop: NSLayoutConstraint?\u0422\u043e \u0435\u0441\u0442\u044c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u043a\u043e\u043b\u043b\u0430\u043f\u0441\u0430 \u2014 \u044d\u0442\u043e \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 CALayer, \u0430 \u043f\u0435\u0440\u0435\u0441\u0447\u0451\u0442 constant \u0443 \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442\u043e\u0432 \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0442\u0438\u043a \u0441\u043a\u0440\u043e\u043b\u043b\u0430. \u0414\u0430\u043b\u044c\u0448\u0435 \u0441\u0442\u0430\u043d\u0435\u0442 \u0432\u0438\u0434\u043d\u043e, \u043a\u0430\u043a\u0438\u0435 \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u0442\u0435\u043a\u0430\u044e\u0442 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f.\u041a\u0430\u043a \u0431\u0430\u0440 \u0446\u0435\u043f\u043b\u044f\u0435\u0442\u0441\u044f \u043a \u0441\u043a\u0440\u043e\u043b\u043b\u0443\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0438\u0434\u0435\u044f: \u0431\u0430\u0440 \u0441\u0430\u043c \u0432\u043b\u0430\u0434\u0435\u0435\u0442 contentInset.top \u0441\u043a\u0440\u043e\u043b\u043b\u0430. \u041f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043e\u043d \u043f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043e\u0442\u0431\u0438\u0440\u0430\u0435\u0442 \u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043d\u0441\u0435\u0442\u0430\u043c\u0438:private func sync(with scrollView: UIScrollView) {    guard stack.bounds.height != 0 else { return }    \/\/ \u0434\u0430\u043b\u044c\u0448\u0435 \u0437\u0430 \u0438\u043d\u0441\u0435\u0442\u044b, scroll-to-top \u0438 \u0432\u0441\u0451 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0435 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0441\u0430\u043c \u0431\u0430\u0440    scrollView.scrollsToTop = false    scrollView.contentInsetAdjustmentBehavior = .never    let maxHeight = expandedHeight()    scrollView.contentInset.top = maxHeight    scrollView.contentOffset.y = -maxHeight}scrollsToTop = false \u0438 contentInsetAdjustmentBehavior = .never \u043e\u0437\u043d\u0430\u0447\u0430\u044e\u0442, \u0447\u0442\u043e \u0432\u0441\u044f \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0437\u0430 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u044c \u0438\u043d\u0441\u0435\u0442\u043e\u0432 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435.\u0427\u0442\u043e\u0431\u044b \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043a\u0440\u043e\u043b\u043b\u0430, \u0431\u0430\u0440 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043d\u0430\u0431\u043e\u0440 KVO-\u043e\u0431\u0437\u0451\u0440\u0432\u0435\u0440\u043e\u0432:insetObserver       = scrollView.observe(\\.contentInset)  { &#8230; }contentSizeObserver = scrollView.observe(\\.contentSize)   { &#8230; }offsetObserver      = scrollView.observe(\\.contentOffset) { &#8230; }\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u043c\u0435\u0447\u0443: \u0441\u0430\u043c \u043a\u043e\u043b\u043b\u0430\u043f\u0441 \u0431\u0430\u0440\u0430 \u0437\u0430\u0432\u044f\u0437\u0430\u043d \u043d\u0430 KVO contentOffset, \u0430 \u043d\u0435 \u043d\u0430 scrollViewDidScroll. \u0422\u0430\u043a \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u043f\u043e \u0434\u0432\u0443\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, KVO \u043b\u043e\u0432\u0438\u0442 \u043b\u044e\u0431\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0444\u0444\u0441\u0435\u0442\u0430, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0435. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u043e\u043d\u043e \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0442\u043e\u0433\u043e, \u043a\u0442\u043e \u0432 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u043e\u043c \u0441\u043a\u0440\u043e\u043b\u043b\u0430, \u2014 \u0430 \u0434\u0435\u043b\u0435\u0433\u0430\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 (\u0441\u043d\u0430\u043f\u043f\u0438\u043d\u0433\u0430), \u0438 \u0441\u043e\u0432\u043c\u0435\u0449\u0430\u0442\u044c \u043e\u0431\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0435 \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u043e.expandedHeight() \u2014 \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u043e\u0433\u043e \u0431\u0430\u0440\u0430\u0427\u0442\u043e\u0431\u044b \u0432\u044b\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0439 contentInset.top, \u043d\u0443\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c \u0432\u044b\u0441\u043e\u0442\u0443 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u043e\u0433\u043e \u0431\u0430\u0440\u0430. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u0430\u0440 \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0439 (\u043f\u0430\u043d\u0435\u043b\u0438 \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0438 \u0438\u0441\u0447\u0435\u0437\u0430\u044e\u0442), \u0432\u044b\u0441\u043e\u0442\u0443 \u043f\u0440\u043e\u0449\u0435 \u0438\u0437\u043c\u0435\u0440\u0438\u0442\u044c \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e: \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0432\u044b\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u0441\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442\u044b \u0432 \u00ab\u0440\u0430\u0441\u043a\u0440\u044b\u0442\u043e\u0435\u00bb \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043f\u0440\u043e\u0433\u043d\u0430\u0442\u044c layout, \u0441\u043d\u044f\u0442\u044c maxY \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u043f\u0430\u043d\u0435\u043b\u0438 \u0438 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442\u044b \u043e\u0431\u0440\u0430\u0442\u043d\u043e.private func expandedHeight() -&gt; CGFloat {    \/\/ \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f \u0433\u043b\u0443\u0448\u0438\u043c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043e\u0431\u0437\u0451\u0440\u0432\u0435\u0440 bounds \u0441\u0442\u0435\u043a\u0430,    \/\/ \u0438\u043d\u0430\u0447\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442\u043e\u0432 \u0441\u043f\u0440\u043e\u0432\u043e\u0446\u0438\u0440\u0443\u0435\u0442 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0441\u0447\u0451\u0442    ignoreStackBoundsChanges = true    defer { ignoreStackBoundsChanges = false }    let saved = snapshotConstraints()      \/\/ \u0437\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0438\u0435 constant&#8217;\u044b    applyExpandedConstraints()             \/\/ \u0432\u044b\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u00ab\u0440\u0430\u0441\u043a\u0440\u044b\u0442\u043e\u0435\u00bb \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435    stack.layoutIfNeeded()    var height = (stack.arrangedSubviews.last?.frame.maxY ?? 0) + safeAreaInsets.top    restoreConstraints(saved)              \/\/ \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u0430\u043a \u0431\u044b\u043b\u043e    stack.layoutIfNeeded()    if let refreshControl = scrollView?.refreshControl, refreshControl.isRefreshing {        height += refreshControl.bounds.height    }    return height}\u0424\u043b\u0430\u0433 ignoreStackBoundsChanges \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u0435\u043d: \u0431\u0430\u0440 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 bounds \u0441\u0442\u0435\u043a\u0430, \u0430 \u0432 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u0430\u043c \u043c\u0435\u043d\u044f\u0435\u0442 \u0435\u0433\u043e \u0442\u0443\u0434\u0430 \u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e. \u042d\u0442\u043e \u0441\u043a\u0432\u043e\u0437\u043d\u0430\u044f \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0432\u0441\u0435\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u2014 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u043c\u0435\u043d\u044f\u0435\u0442 \u0442\u043e, \u043d\u0430 \u0447\u0442\u043e \u0441\u0430\u043c \u0436\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d, \u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u043e \u0433\u043b\u0443\u0448\u0438\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043e\u0431\u0437\u0451\u0440\u0432\u0435\u0440\u044b, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0443\u0439\u0442\u0438 \u0432 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0446\u0438\u043a\u043b.\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u043d\u0435\u043f\u0440\u0438\u044f\u0442\u043d\u043e\u0441\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0441\u0442\u043e\u0438\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044c: \u043f\u0440\u0438 \u0442\u0430\u043a\u043e\u043c \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u0438 \u0432\u044b\u0441\u043e\u0442\u0430 \u0438\u043d\u043e\u0433\u0434\u0430 \u00ab\u0434\u0440\u043e\u0436\u0438\u0442\u00bb \u043d\u0430 \u043e\u0434\u0438\u043d \u043f\u0438\u043a\u0441\u0435\u043b\u044c (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0435\u0440\u0435\u0434\u0443\u0435\u0442\u0441\u044f 233 \u0438 234). \u0414\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u043d\u043e\u0439 \u043f\u0435\u0440\u0432\u043e\u043f\u0440\u0438\u0447\u0438\u043d\u044b \u044f \u043d\u0435 \u043d\u0430\u0448\u0451\u043b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u2014 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u0432\u044b\u0441\u043e\u0442 \u0441 \u043f\u043e\u0440\u043e\u0433\u043e\u043c \u0432 1pt \u0438 \u043d\u0435 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u043c\u0435\u043d\u044c\u0448\u0435. \u0414\u043b\u044f \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0430 \u044d\u0442\u043e\u0433\u043e \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e, \u0445\u043e\u0442\u044f \u043e\u0441\u0430\u0434\u043e\u043a \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f.\u041a\u043e\u043b\u043b\u0430\u043f\u0441: \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u0436\u0430\u0442\u0438\u0435 \u043f\u0430\u043d\u0435\u043b\u0435\u0439\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u2014 \u0432 \u043e\u0431\u0437\u0451\u0440\u0432\u0435\u0440\u0435 contentOffset. \u0421\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0432\u0435\u043b\u0438\u0447\u0438\u043d\u0430 \u00ab\u0443\u0442\u043e\u043f\u043b\u0435\u043d\u043d\u043e\u0441\u0442\u0438\u00bb \u0441\u043a\u0440\u043e\u043b\u043b\u0430, \u0438 \u043f\u043e \u043d\u0435\u0439 \u043f\u0430\u043d\u0435\u043b\u0438 \u0441\u0436\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0441\u0432\u0435\u0440\u0445\u0443 \u0432\u043d\u0438\u0437 \u0432 \u0441\u0442\u0440\u043e\u0433\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0437\u0430\u0437\u043e\u0440, \u0437\u0430\u0442\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430, \u0437\u0430\u0442\u0435\u043c \u043d\u0438\u0436\u043d\u0438\u0435 \u043f\u0430\u043d\u0435\u043b\u0438 \u0438 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u2014 large title.offsetObserver = scrollView.observe(\\.contentOffset, options: [.old, .new]) { [weak self] scrollView, change in    guard let self,          self.searchBar?.isActive != true,          let old = change.oldValue?.y, let new = change.newValue?.y, old != new    else { return }    var offset = scrollView.contentOffset.y + scrollView.contentInset.top               &#8212; self.startOffset + self.startCollapse    \/\/ 1. \u0437\u0430\u0437\u043e\u0440 \u043c\u0435\u0436\u0434\u0443 \u0442\u043e\u043f-\u043f\u0430\u043d\u0435\u043b\u044c\u044e \u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c \u2014 \u043a\u0430\u043a \u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e navbar    if let c = self.spacePanelHeight {        c.constant = max(-offset, 0)        self.spacePanel.isHidden = c.constant == 0    }    \/\/ 2. \u0441\u0442\u0440\u043e\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0443\u0436\u0438\u043c\u0430\u0435\u043c \u043f\u043e \u0432\u044b\u0441\u043e\u0442\u0435, \u0437\u0430\u0442\u0435\u043c \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u043c \u043d\u0430\u0432\u0435\u0440\u0445    if let searchBar, let searchHeight, let searchTop {        let target = min(searchBar.intrinsicContentSize.height &#8212; offset,                         searchBar.intrinsicContentSize.height)        searchHeight.constant = max(0, target)        \/\/ \u043f\u043e\u043f\u0443\u0442\u043d\u043e \u043f\u043b\u0430\u0432\u043d\u043e \u0433\u0430\u0441\u0438\u043c \u0438\u043a\u043e\u043d\u043a\u0443 \u043b\u0443\u043f\u044b \u0438 \u043f\u043b\u0435\u0439\u0441\u0445\u043e\u043b\u0434\u0435\u0440        \/\/ &#8230;        offset -= (defaultSearchHeight &#8212; self.searchPanel.bounds.height)    }    \/\/ 3. closable-\u043f\u0430\u043d\u0435\u043b\u044c    \/\/ 4. large title \u2014 \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u043c \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0441 \u043a\u0440\u043e\u0441\u0441-\u0444\u0435\u0439\u0434\u043e\u043c \u043d\u0430 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a    if let largeTitleTop {        \/\/ &#8230;        let collapsed = self.largeTitlePanel.bounds.height &lt; threshold        self.crossfade(show: collapsed ? self.compactTitle : self.largeTitle,                       hide: collapsed ? self.largeTitle : self.compactTitle)    }}\u0417\u0434\u0435\u0441\u044c \u0441\u0442\u043e\u0438\u0442 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0434\u0432\u0443\u0445 \u0434\u0435\u0442\u0430\u043b\u044f\u0445.\u041a\u0440\u043e\u0441\u0441-\u0444\u0435\u0439\u0434 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430. \u041a\u043e\u0433\u0434\u0430 large title \u0441\u0436\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u043d\u0438\u0436\u0435 \u043f\u043e\u0440\u043e\u0433\u0430, \u043d\u0443\u0436\u043d\u043e \u043f\u043b\u0430\u0432\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u043f\u043e \u0446\u0435\u043d\u0442\u0440\u0443 \u0442\u043e\u043f-\u043f\u0430\u043d\u0435\u043b\u0438 (\u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442 \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u043c \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0438). \u0412\u0430\u0436\u043d\u044b\u0439 \u043d\u044e\u0430\u043d\u0441 \u2014 \u043d\u0435\u043b\u044c\u0437\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u043f\u043e\u0432\u0435\u0440\u0445 \u0443\u0436\u0435 \u0438\u0434\u0443\u0449\u0435\u0439, \u0438\u043d\u0430\u0447\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u043c\u0435\u0440\u0446\u0430\u0442\u044c. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0443 \u0432\u044c\u044e\u0445 \u0437\u0430\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0444\u043b\u0430\u0433 \u00ab\u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0443\u0436\u0435 \u0438\u0434\u0451\u0442\u00bb, \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f:private func crossfade(show: UIView, hide: UIView, duration: TimeInterval = 0.1) {    guard show.isHidden || show.alpha != 1 else { return }    show.isAnimating = true; hide.isAnimating = true    show.alpha = 0; show.isHidden = false    UIView.animate(withDuration: duration, delay: 0, options: .beginFromCurrentState) {        show.alpha = 1        hide.alpha = 0    } completion: { finished in        guard finished else { return }        show.isAnimating = false; hide.isAnimating = false        hide.isHidden = true    }}startOffset \u0438 startCollapse. \u042d\u0442\u043e \u0434\u0432\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0435 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441 \u00ab\u043e\u0442\u043a\u0443\u0434\u0430 \u043e\u0442\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u0436\u0430\u0442\u0438\u0435\u00bb. \u0415\u0441\u043b\u0438 \u044d\u043a\u0440\u0430\u043d \u043e\u0442\u043a\u0440\u044b\u0442 \u0432 \u0441\u0430\u043c\u043e\u043c \u0432\u0435\u0440\u0445\u0443 \u0441\u043f\u0438\u0441\u043a\u0430, \u0432\u0441\u0451 \u043f\u0440\u043e\u0441\u0442\u043e: \u0431\u0430\u0440 \u0441\u0436\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0435 \u0432\u043d\u0438\u0437. \u041d\u043e \u0435\u0441\u043b\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0441\u043a\u0440\u043e\u043b\u043b, \u0443\u0436\u0435 \u043a\u0443\u0434\u0430-\u0442\u043e \u043f\u0440\u043e\u0441\u043a\u0440\u043e\u043b\u043b\u0435\u043d\u043d\u044b\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0442\u0430\u0431\u043e\u0432), \u043d\u0443\u0436\u043d\u043e \u0443\u0447\u0435\u0441\u0442\u044c, \u0447\u0442\u043e \u0431\u0430\u0440 \u0443\u0436\u0435 \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e \u0441\u0436\u0430\u0442, \u0438 \u043d\u0435 \u0434\u0451\u0440\u0433\u0430\u0442\u044c \u0435\u0433\u043e \u043b\u0438\u0448\u043d\u0438\u0439 \u0440\u0430\u0437. \u042d\u0442\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0445\u0440\u0443\u043f\u043a\u0438\u0445 \u0443\u0447\u0430\u0441\u0442\u043a\u043e\u0432 \u043b\u043e\u0433\u0438\u043a\u0438, \u0438 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u043e\u043d \u0443 \u043c\u0435\u043d\u044f \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0451\u043d \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u043c \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c \u2014 \u0441\u0443\u0442\u044c \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u043e\u0447\u043a\u0430 \u043e\u0442\u0441\u0447\u0451\u0442\u0430 \u0441\u0436\u0430\u0442\u0438\u044f \u043f\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u043a\u0440\u043e\u043b\u043b\u0438\u0442 \u0432\u0432\u0435\u0440\u0445, \u0438 \u043e\u0431\u043d\u0443\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0434\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u0438 \u0432\u0435\u0440\u0445\u0430 \u0441\u043f\u0438\u0441\u043a\u0430.\u0421\u043d\u0430\u043f\u043f\u0438\u043d\u0433: \u0434\u043e\u0432\u043e\u0434\u043a\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 \u0434\u043e \u0446\u0435\u043b\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0436\u0438\u043c\u0430\u0442\u044c \u043f\u0430\u043d\u0435\u043b\u0438 \u043f\u043e \u043e\u0444\u0444\u0441\u0435\u0442\u0443, \u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u043e\u0442\u043f\u0443\u0441\u043a\u0430\u043d\u0438\u044f \u043f\u0430\u043b\u044c\u0446\u0430 large title \u043c\u043e\u0436\u0435\u0442 \u043e\u0441\u0442\u0430\u0442\u044c\u0441\u044f \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u044b\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 40% \u2014 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043d\u0435\u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d\u043d\u043e. \u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u043d\u0430\u0432\u0431\u0430\u0440 \u0443\u043c\u0435\u0435\u0442 \u0434\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0434\u043e \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f (\u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0442\u043a\u0440\u044b\u0442 \u0438\u043b\u0438 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u043a\u0440\u044b\u0442), \u0438 \u043e\u0442 \u0441\u0432\u043e\u0435\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0442\u043e\u0433\u043e \u0436\u0435.\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0443\u0436\u0435 \u043d\u0443\u0436\u0435\u043d \u0434\u0435\u043b\u0435\u0433\u0430\u0442 \u0441\u043a\u0440\u043e\u043b\u043b\u0430: \u043c\u043e\u043c\u0435\u043d\u0442 \u0434\u043e\u0432\u043e\u0434\u043a\u0438 \u043b\u043e\u0432\u0438\u0442\u0441\u044f \u0432 scrollViewWillEndDragging, \u0433\u0434\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c targetContentOffset \u2014 \u0442\u043e\u0447\u043a\u0443, \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0441\u043a\u0440\u043e\u043b\u043b \u043f\u0440\u0438\u043b\u0435\u0442\u0438\u0442 \u043f\u043e\u0441\u043b\u0435 \u0438\u043d\u0435\u0440\u0446\u0438\u0438.scrollProxy.onWillEndDragging = { [weak self] scrollView, velocity, targetContentOffset in    guard let self, abs(velocity.y) &gt; 0 else { return }    \/\/ \u0441\u0447\u0438\u0442\u0430\u0435\u043c, \u043a\u0430\u043a\u0438\u043c\u0438 \u0431\u044b\u043b\u0438 \u0431\u044b&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-484301","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/484301","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=484301"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/484301\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=484301"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=484301"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=484301"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}