{"id":302318,"date":"2020-04-22T15:00:44","date_gmt":"2020-04-22T15:00:44","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=302318"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=302318","title":{"rendered":"\u0411\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0441\u043a\u0440\u043e\u043b\u043b \u0441 \u0431\u0430\u043d\u043d\u0435\u0440\u0430\u043c\u0438, \u0438\u043b\u0438 \u041a\u0430\u043a \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0442\u0440\u0435\u043c\u044f \u0432\u044c\u044e\u0445\u0430\u043c\u0438"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/company\/youla\/blog\/498462\/\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/322\/2d5\/f74\/3222d5f742f0548e472a4f5d0fb94a91.gif\"><\/div>\n<p>  \u041a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u043e\u0434 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441 \u0437\u0430\u0434\u0430\u0447\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0435 \u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c. \u0412\u0441\u0435\u0433\u0434\u0430 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0443\u0442\u0435\u0439, \u2014 \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u0431\u044b\u0441\u0442\u0440\u044b\u0435, \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u0435, \u2014 \u0438 \u0443 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0432\u043e\u0438 \u0434\u043e\u0441\u0442\u043e\u0438\u043d\u0441\u0442\u0432\u0430 \u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438.<\/p>\n<p>  \u0411\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439\/\u0446\u0438\u043a\u043b\u0438\u0447\u043d\u044b\u0439 \u0441\u043a\u0440\u043e\u043b\u043b \u0432 iOS \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c\u0438 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c\u0438 \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c, \u043d\u0443\u0436\u043d\u043e \u0438\u0434\u0442\u0438 \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0435 \u0443\u0445\u0438\u0449\u0440\u0435\u043d\u0438\u044f. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a\u0438\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 \u043b\u0435\u0436\u0430\u0442 \u043d\u0430 \u043f\u043e\u0432\u0435\u0440\u0445\u043d\u043e\u0441\u0442\u0438 \u0438 \u043a\u0430\u043a\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043c\u044b \u0432 \u0438\u0442\u043e\u0433\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438.<br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<h2>\u0417\u0430\u0434\u0430\u0447\u0430<\/h2>\n<p>  \u041d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u0443\u044e \u0446\u0438\u043a\u043b\u0438\u0447\u043d\u0443\u044e \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0443 \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0432 \u0432\u0438\u0434\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u0439 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438, \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0438 \u043f\u043e\u0434\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430. \u0412\u0432\u043e\u0434\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435: \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0438\u043c\u0435\u0435\u0442 \u043e\u0442\u0441\u0442\u0443\u043f\u044b \u043e\u0442 \u044d\u043a\u0440\u0430\u043d\u0430 \u043f\u043e 16.0 \u043f\u043e\u0438\u043d\u0442\u043e\u0432. \u041f\u043e \u0431\u043e\u043a\u0430\u043c \u043e\u0442 \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0442\u043e\u0440\u0447\u0430\u0442 \u00ab\u0443\u0448\u043a\u0438\u00bb. \u0410 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0431\u0430\u043d\u043d\u0435\u0440\u0430\u043c\u0438 8.0 \u043f\u043e\u0438\u043d\u0442\u043e\u0432.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/4ea\/316\/e3f\/4ea316e3fa358d45be7ca752daaf78dd.png\" width=\"500\"><\/div>\n<p>  <\/p>\n<h2>\u0418\u0437\u0443\u0447\u0430\u0435\u043c, \u0447\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0443 \u043a\u043e\u043b\u043b\u0435\u0433<\/h2>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/3af\/d5e\/302\/3afd5e302d0e93eb87666d668fb0796d.jpg\"><\/div>\n<p>  \u0414\u043e\u0434\u043e \u2014 \u0431\u0430\u043d\u043d\u0435\u0440\u044b \u043d\u0435 \u0446\u0438\u043a\u043b\u0438\u0447\u043d\u044b\u0435, \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u0439 \u0431\u0430\u043d\u043d\u0435\u0440 \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u0438\u043b\u0435\u0433\u0430\u0435\u0442 \u043a \u043b\u0435\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e \u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u043c \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0438.<\/p>\n<p>  Auto.ru \u2014 \u0431\u0430\u043d\u043d\u0435\u0440\u044b \u043d\u0435 \u0446\u0438\u043a\u043b\u0438\u0447\u043d\u044b\u0435, \u0435\u0441\u043b\u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u0430\u0439\u043f, \u0442\u043e \u0431\u0430\u043d\u043d\u0435\u0440\u044b \u043e\u0447\u0435\u043d\u044c \u0434\u043e\u043b\u0433\u043e \u0435\u0449\u0435 \u043b\u0438\u0441\u0442\u0430\u044e\u0442\u0441\u044f.<\/p>\n<p>  Ozon \u2014 \u0431\u0430\u043d\u043d\u0435\u0440\u044b \u0446\u0438\u043a\u043b\u0438\u0447\u043d\u044b\u0435, \u043d\u043e \u0438\u0445 \u043d\u0435\u043b\u044c\u0437\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u0441\u0430\u043d\u0438\u0435\u043c: \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0432\u0430\u0439\u043f\u0430, \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0443 \u0443\u0436\u0435 \u043d\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c.<\/p>\n<p>  Wildberries \u2014 \u0431\u0430\u043d\u043d\u0435\u0440\u044b \u043d\u0435 \u0446\u0438\u043a\u043b\u0438\u0447\u043d\u044b\u0435, \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0446\u0435\u043d\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0434\u043e\u043b\u0433\u043e\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438.<\/p>\n<p>  <strong>\u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0435 \u043f\u043e\u0436\u0435\u043b\u0430\u043d\u0438\u044f:<\/strong><\/p>\n<ul>\n<li>\u0411\u0430\u043d\u043d\u0435\u0440\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0446\u0435\u043d\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f.<\/li>\n<li>\u041f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u044c\u0441\u044f \u0431\u0435\u0437 \u0434\u043e\u043b\u0433\u043e\u0433\u043e \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438.<\/li>\n<li>\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0441\u0442\u044c \u0431\u0430\u043d\u043d\u0435\u0440\u043e\u0432: \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0430\u043b\u044c\u0446\u0435\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438.<\/li>\n<\/ul>\n<p>  <\/p>\n<h2>\u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/h2>\n<p>  \u041a\u043e\u0433\u0434\u0430 \u0432\u0441\u0442\u0430\u0435\u0442 \u043d\u043e\u0432\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0435\u0449\u0435 \u043d\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0440\u0435\u0448\u0430\u0442\u044c, \u0441\u0442\u043e\u0438\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0438 \u043f\u043e\u0434\u0445\u043e\u0434\u044b.<\/p>\n<h3>UICollectionView<\/h3>\n<p>  \u0414\u0435\u0439\u0441\u0442\u0432\u0443\u044f \u0432 \u043b\u043e\u0431, \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0439\u0442\u0438 \u043a \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0443 \u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435\u043c <code>UICollectionView<\/code>. \u0414\u0435\u043b\u0430\u0435\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 <code>Int.max<\/code> \u0438 \u043f\u0440\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0443, \u0430 \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 \u043c\u0435\u0442\u043e\u0434\u0430 \u0432 <code>dataSource<\/code> \u2014 <code>func collectionView(UICollectionView, cellForItemAt: IndexPath) -&gt; UICollectionViewCell<\/code>. \u0411\u0443\u0434\u0435\u043c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u044f, \u0447\u0442\u043e \u043d\u0443\u043b\u0435\u0432\u043e\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u2014 \u044d\u0442\u043e <code>Int.max \/ 2<\/code>. \u0422\u0430\u043a\u043e\u0433\u043e \u043c\u043e\u043d\u0441\u0442\u0440\u0430 \u0441 \u043a\u0443\u0447\u0435\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439, \u043a\u0430\u043a <code>UICollectionView<\/code>, \u043d\u0435\u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438.<\/p>\n<h3>UIScrollView \u0438 (n + 2) UIView<\/h3>\n<p>  \u0415\u0449\u0435 \u0435\u0441\u0442\u044c \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f UIScrollView, \u043d\u0430 \u043d\u0435\u043c \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u044e\u0442\u0441\u044f \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u0432\u0441\u0435 \u0431\u0430\u043d\u043d\u0435\u0440\u044b, \u0430 \u0432 \u043d\u0430\u0447\u0430\u043b\u043e \u0438 \u0432 \u043a\u043e\u043d\u0435\u0446 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0435\u0449\u0435 \u043f\u043e \u0431\u0430\u043d\u043d\u0435\u0440\u0443. \u041a\u043e\u0433\u0434\u0430 \u0434\u043e\u043a\u0440\u0443\u0447\u0438\u0432\u0430\u0435\u043c \u0434\u043e \u043a\u043e\u043d\u0446\u0430, \u043d\u0435\u0437\u0430\u043c\u0435\u0442\u043d\u043e \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043c\u0435\u043d\u044f\u0435\u043c \u043e\u0444\u0444\u0441\u0435\u0442 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u043f\u0435\u0440\u0432\u043e\u043c\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443. \u0410 \u043f\u0440\u0438 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0435 \u043d\u0430\u0437\u0430\u0434 \u0432\u0441\u0451 \u0434\u0435\u043b\u0430\u0435\u043c \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u0440\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u043a\u0443\u0447\u0430 view \u0431\u0435\u0437 \u0438\u0445 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/b45\/6ec\/9ea\/b456ec9eaee45c4ebd17f586e147fedb.png\"><\/div>\n<p>  <i><a href=\"https:\/\/medium.com\/swift2go\/custom-ui-master-class-infinite-paging-scroll-view-4be78d0de88f\">\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a<\/a><\/i><\/p>\n<h3>\u0421\u0432\u043e\u0439 \u043f\u0443\u0442\u044c<\/h3>\n<p>  \u041c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c UIScrollView + \u0442\u0440\u0438 UIView. \u042d\u0442\u0438 UIView \u0431\u0443\u0434\u0443\u0442 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f. \u0412 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c <code>contentOffset<\/code> \u043a \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u0431\u0430\u043d\u043d\u0435\u0440\u0443 \u0438 \u043f\u043e\u0434\u043c\u0435\u043d\u044f\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0443 \u0432\u0441\u0435\u0445 \u0442\u0440\u0435\u0445 UIView. \u0418 \u0442\u043e\u0433\u0434\u0430 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u043b\u0435\u0433\u043a\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043a\u0440\u043e\u0435\u0442 \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443.<\/p>\n<p>  \u041e\u0434\u043d\u0430\u043a\u043e \u0435\u0441\u0442\u044c \u043e\u043f\u0430\u0441\u0435\u043d\u0438\u0435, \u0447\u0442\u043e \u043f\u043e\u0434\u043c\u0435\u043d\u0430 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043c\u0435\u0442\u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e. \u0423\u0437\u043d\u0430\u0435\u043c \u043e\u0431 \u044d\u0442\u043e\u043c \u0432 \u0445\u043e\u0434\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h2>\n<p>  <\/p>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 UIScrollView \u0438 \u0442\u0440\u0451\u0445 UIImageView<\/h3>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u043d\u0430\u0441\u043b\u0435\u0434\u043d\u0438\u043a\u0430 <code>UIView<\/code>, \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u043c \u043d\u0430 \u043d\u0451\u043c <code>UIScrollView<\/code> \u0438 \u0442\u0440\u0438 <code>UIImageView<\/code>:<\/p>\n<pre><code class=\"swift\">final class BannersView: UIView {     private let scrollView = UIScrollView()      private let leftItemView = UIImageView()     private let centerItemView = UIImageView()     private let rightItemView = UIImageView()      init() {         super.init(frame: .zero)         self.setup()     }      required init?(coder aDecoder: NSCoder) {         fatalError(&quot;init(coder:) has not been implemented&quot;)     }      private func setup() {         self.addSubview(self.scrollView)         self.setupScrollView()          let imageViews = [self.leftItemView, self.centerItemView, self.rightItemView]         imageViews.forEach(self.scrollView.addSubview)     } } <\/code><\/pre>\n<p>  \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043c\u0435\u0442\u043e\u0434\u0430 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u043e\u0439 <code>scrollView<\/code>:<\/p>\n<ul>\n<li><code>decelerationRate<\/code> \u2014 \u044d\u0442\u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0441 \u043a\u0430\u043a\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c\u044e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043c\u0435\u0434\u043b\u044f\u0442\u044c\u0441\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 <code>.fast<\/code>.<\/li>\n<li><code>showsHorizontalScrollIndicator<\/code> \u2014 \u044d\u0442\u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u043b\u043e\u0441\u044b \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438:\n<pre><code class=\"swift\">private func setupScrollView() {     self.scrollView.decelerationRate = .fast     self.scrollView.showsHorizontalScrollIndicator = false } <\/code><\/pre>\n<\/li>\n<\/ul>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043d\u044f\u0442\u044c\u0441\u044f \u043c\u0430\u043a\u0435\u0442\u043e\u043c \u0438 \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u0435\u043c <code>ImageView<\/code>:<\/p>\n<pre><code class=\"swift\">override func layoutSubviews() {     super.layoutSubviews()     self.scrollView.frame = self.bounds      let horizontalItemOffsetFromSuperView: CGFloat = 16.0     let spaceBetweenItems: CGFloat = 8.0     let itemWidth = self.frame.width - horizontalItemOffsetFromSuperView * 2     let itemHeight: CGFloat = self.scrollView.frame.height      var startX: CGFloat = 0.0      let imageViews = [self.leftItemView, self.centerItemView, self.rightItemView]     imageViews.forEach { view in         view.frame.origin = CGPoint(x: startX, y: 0.0)         view.frame.size = CGSize(width: itemWidth, height: itemHeight)         startX += itemWidth + spaceBetweenItems     }      let viewsCount: CGFloat = 3.0     let contentWidth: CGFloat = itemWidth * viewsCount + spaceBetweenItems * (viewsCount - 1.0)     self.scrollView.contentSize = CGSize(width: contentWidth, height: self.frame.height) } <\/code><\/pre>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432 <code>UIImageView<\/code> \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0434\u0442\u044f\u043d\u0435\u043c \u0441 \u0441\u0430\u0439\u0442\u0430-\u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a <a href=\"https:\/\/placeholder.com\">https:\/\/placeholder.com<\/a>:<\/p>\n<pre><code class=\"swift\">    let imageURLs = ImageURLFactory.makeImageURLS()     imageViews.enumerated().forEach { key, view in         view.setImage(with: imageURLs[key])     } <\/code><\/pre>\n<p>  \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u0435\u0440\u0432\u044b\u0445 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0448\u0430\u0433\u043e\u0432:<\/p>\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><video controls style=\"top: 0; left: 0; width: 100%; height: 100%; position: absolute;\">Your browser does not support HTML5 video.<source src=\"https:\/\/v003.radikal.ru\/2004\/04\/6227953752-5-905175ff55957c18b4fdc9985b4ca505.mp4\" type=\"video\/mp4\"><\/source><\/video><\/div>\n<\/div>\n<\/div>\n<p>  <\/p>\n<h3>\u0426\u0435\u043d\u0442\u0440\u0438\u0440\u0443\u0435\u043c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0438 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0435<\/h3>\n<p>  \u0414\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>UIScrollViewDelegate<\/code>. \u0412 \u043c\u0435\u0442\u043e\u0434 <code>setup<\/code> \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0434\u0435\u043b\u0435\u0433\u0430\u0442 \u0434\u043b\u044f <code>UIScrollView<\/code>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c <code>contentInset<\/code>, \u0447\u0442\u043e\u0431\u044b \u0443 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0431\u044b\u043b\u0438 \u043e\u0442\u0441\u0442\u0443\u043f\u044b \u043f\u043e \u0431\u043e\u043a\u0430\u043c.<\/p>\n<pre><code class=\"swift\">self.scrollView.contentInset = UIEdgeInsets(top: 0.0, left: 16.0, bottom: 0.0, right: 16.0) self.scrollView.delegate = self <\/code><\/pre>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0435\u043c <code>extension<\/code> \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e <code>BannersView<\/code> \u0438 \u043e\u0434\u0438\u043d \u0438\u0437 \u043c\u0435\u0442\u043e\u0434\u043e\u0432. \u041c\u0435\u0442\u043e\u0434 \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u0430 <code>func scrollViewWillEndDragging<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0435\u0442 \u043f\u0440\u043e\u043a\u0440\u0443\u0447\u0438\u0432\u0430\u0442\u044c. \u0412 \u044d\u0442\u043e\u043c \u043c\u0435\u0442\u043e\u0434\u0435 \u043d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 <code>targetContentOffset<\/code> \u2014 \u044d\u0442\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 offset \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438 (\u0442\u043e\u0447\u043a\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0430).<\/p>\n<pre><code class=\"swift\"> extension BannersView: UIScrollViewDelegate {    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer&lt;CGPoint&gt;) {     let gap: CGFloat = self.centerItemView.frame.width \/ 3      let targetRightOffsetX = targetContentOffset.pointee.x + self.frame.width     if (self.rightItemView.frame.minX + gap) &lt; targetRightOffsetX {       targetContentOffset.pointee.x = self.rightItemView.frame.midX - self.frame.midX     }     else if (self.leftItemView.frame.maxX - gap) &gt; targetContentOffset.pointee.x {       targetContentOffset.pointee.x = self.leftItemView.frame.midX - self.frame.midX     }     else {       targetContentOffset.pointee.x = self.centerItemView.frame.midX - self.frame.midX     }   }  } <\/code><\/pre>\n<p>  <code>gap<\/code> \u2014 \u044d\u0442\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0441\u0447\u0438\u0442\u0430\u0442\u044c, \u0447\u0442\u043e view \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u043c. \u0415\u0441\u043b\u0438 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0442\u0440\u0435\u0442\u044c \u0448\u0438\u0440\u0438\u043d\u044b \u043e\u0440\u0430\u043d\u0436\u0435\u0432\u043e\u0433\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u0442\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 offset \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043e\u0440\u0430\u043d\u0436\u0435\u0432\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0432 \u0446\u0435\u043d\u0442\u0440\u0435.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/389\/bca\/39f\/389bca39fdaa2b4b29892f72f063a4ad.png\"><\/div>\n<p>  <code>targetRightOffsetX<\/code> \u2014 \u044d\u0442\u0430 \u0442\u043e\u0447\u043a\u0430 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438 \u043f\u0440\u0430\u0432\u044b\u0439 view \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u043c.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/829\/f7a\/401\/829f7a4012d80bc6689014d57ac27a99.png\"><\/div>\n<p>  \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430:<\/p>\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><video controls style=\"top: 0; left: 0; width: 100%; height: 100%; position: absolute;\">Your browser does not support HTML5 video.<source src=\"https:\/\/v003.radikal.ru\/2004\/9a\/6227953956-5-d6396eb7a87bdfd73e81c892f53321f5.mp4\" type=\"video\/mp4\"><\/source><\/video><\/div>\n<\/div>\n<\/div>\n<p>  <\/p>\n<h3>\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u0444\u0444\u0441\u0435\u0442\u043e\u043c \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438<\/h3>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u044f\u043c\u043e \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438 \u0431\u0443\u0434\u0435\u043c \u043c\u0435\u043d\u044f\u0442\u044c <code>contentOffset<\/code>, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044f \u0432 \u0446\u0435\u043d\u0442\u0440 \u044d\u043a\u0440\u0430\u043d\u0430 \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u0443\u044e view. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0435\u0437\u0430\u043c\u0435\u0442\u043d\u043e \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u043b\u043b\u044e\u0437\u0438\u044e \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0439 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438.<\/p>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u0435\u0442\u043e\u0434 \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u0430 <code>func scrollViewDidScroll(_ scrollView: UIScrollView)<\/code>, \u043e\u043d \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 <code>contentOffset<\/code> \u0443 <code>UIScrollView<\/code>.<\/p>\n<pre><code class=\"swift\"> func scrollViewDidScroll(_ scrollView: UIScrollView) {     guard             self.leftItemView.frame.width &gt; 0,             self.centerItemView.frame.width &gt; 0,             self.rightItemView.frame.width &gt; 0             else {         return     }      let gap: CGFloat = self.centerItemView.frame.width \/ 3     let spacing: CGFloat = 8.0      let currentRightOffset: CGFloat = scrollView.contentOffset.x + self.frame.width + scrollView.contentInset.left      if (self.rightItemView.frame.maxX - gap) &lt; currentRightOffset {         scrollView.contentOffset.x -= self.centerItemView.frame.width + spacing     } else if (self.leftItemView.frame.minX + gap) &gt; scrollView.contentOffset.x {         scrollView.contentOffset.x += self.centerItemView.frame.width + spacing     } } <\/code><\/pre>\n<p>  <code>gap<\/code> \u2014 \u044d\u0442\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u044f <code>contentOffset<\/code>. \u0420\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0442\u043e\u0447\u043a\u0443 \u0434\u043b\u044f <code>rightItemView<\/code>: <code>self.rightItemView.frame.maxX \u2014 gap<\/code>, \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u043c \u0441\u043c\u0435\u0449\u0430\u0442\u044c <code>contentOffset<\/code>. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u0434\u043e \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f <code>rightItemView<\/code> \u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u0438\u0442\u044c 100.0 \u043f\u043e\u0438\u043d\u0442\u043e\u0432, \u0442\u043e \u043c\u044b \u0441\u043c\u0435\u0449\u0430\u0435\u043c <code>contentOffset<\/code> \u043d\u0430\u0437\u0430\u0434, \u043d\u0430 \u0448\u0438\u0440\u0438\u043d\u0443 \u043e\u0434\u043d\u043e\u0433\u043e \u0431\u0430\u043d\u043d\u0435\u0440\u0430 \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0431\u0430\u043d\u043d\u0435\u0440\u0430\u043c\u0438 (spacing), \u0447\u0442\u043e\u0431\u044b <code>centerItemView<\/code> \u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u043d\u0430 \u043c\u0435\u0441\u0442\u0435 <code>rightItemView<\/code>. \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0434\u0435\u043b\u0430\u0435\u043c \u0434\u043b\u044f <code>leftItemView<\/code>: \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0442\u043e\u0447\u043a\u0443, \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u043c \u043c\u0435\u043d\u044f\u0442\u044c <code>contentOffset<\/code>.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/49f\/dc1\/65d\/49fdc165d8bc170644722913438a692b.jpg\"><\/div>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u0435\u0442\u043e\u0434 <code>func set(imageURLs: [URL])<\/code>, \u0447\u0442\u043e\u0431\u044b \u0441\u043d\u0430\u0440\u0443\u0436\u0438 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u0422\u0443\u0434\u0430 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043c \u0447\u0430\u0441\u0442\u044c \u043a\u043e\u0434\u0430 \u0438\u0437 <code>setup<\/code>.<\/p>\n<p>  \u0418 \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u0442\u0440\u043e\u043a\u0443, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 <code>centerItemView<\/code> \u0441\u0440\u0430\u0437\u0443 \u0431\u044b\u043b \u043f\u043e \u0446\u0435\u043d\u0442\u0440\u0443. <code>horizontalItemOffsetFromSuperView<\/code> \u043c\u044b \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0432 <code>layoutSubviews<\/code>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u044b\u043d\u0435\u0441\u0435\u043c \u0435\u0433\u043e \u0432 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432\u043d\u043e\u0432\u044c.<\/p>\n<pre><code class=\"swift\">func set(imageURLs: [URL]) {     \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u043d\u0430 ImageView     let imageViews = [self.leftItemView, self.centerItemView, self.rightItemView]     imageViews.enumerated().forEach { key, view in         view.setImage(with: imageURLs[key])     }     \/\/ \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u043e\u0444\u0444\u0441\u0435\u0442, \u0447\u0442\u043e\u0431\u044b centerItemView \u0431\u044b\u043b \u043f\u043e \u0446\u0435\u043d\u0442\u0440\u0443     self.scrollView.contentOffset.x = self.centerItemView.frame.minX - Constants.horizontalItemOffsetFromSuperView } <\/code><\/pre>\n<p>  \u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0441\u043d\u0430\u0440\u0443\u0436\u0438 \u0432\u043e <code>UIViewController.viewDidAppear<\/code>. \u0418\u043b\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u043f\u0435\u0440\u0432\u0443\u044e \u0446\u0435\u043d\u0442\u0440\u043e\u0432\u043a\u0443 \u0432 <code>layoutSubviews<\/code>, \u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c, \u0447\u0442\u043e \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 frame \u0432\u0441\u0435\u0439 view. \u0414\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043f\u0435\u0440\u0432\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c:<\/p>\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><video controls style=\"top: 0; left: 0; width: 100%; height: 100%; position: absolute;\">Your browser does not support HTML5 video.<source src=\"https:\/\/v003.radikal.ru\/2004\/d8\/6227953970-5-108ae86a2e98dcaca3330630b077f86e.mp4\" type=\"video\/mp4\"><\/source><\/video><\/div>\n<\/div>\n<\/div>\n<p>  \u0422\u0430\u043a\u2026 \u041f\u0440\u0438 \u0440\u0435\u0437\u043a\u043e\u0439 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0435 \u0441\u043b\u043e\u043c\u0430\u043b\u043e\u0441\u044c \u0446\u0435\u043d\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/317\/0ac\/a2c\/3170aca2c6da783148c8e1dc15842a38.png\"><\/div>\n<p>  \u0414\u0435\u043b\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u0440\u0438 \u0441\u0438\u043b\u044c\u043d\u043e\u0439 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0435 \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f <code>targetContentOffset<\/code>. \u0423\u0432\u0435\u043b\u0438\u0447\u0438\u043c <code>contentInset<\/code>, \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e. \u0426\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u0439 view \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e \u0446\u0435\u043d\u0442\u0440\u0443.<\/p>\n<pre><code class=\"swift\">self.scrollView.contentInset = UIEdgeInsets(top: 0.0, left: 300.0, bottom: 0.0, right: 300.0) <\/code><\/pre>\n<p>  <\/p>\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><video controls style=\"top: 0; left: 0; width: 100%; height: 100%; position: absolute;\">Your browser does not support HTML5 video.<source src=\"https:\/\/v003.radikal.ru\/2004\/cf\/6227953976-5-52ea19beec65da3b671ef9333b43a144.mp4\" type=\"video\/mp4\"><\/source><\/video><\/div>\n<\/div>\n<\/div>\n<p>  <\/p>\n<h3>\u041f\u043e\u0434\u043c\u0435\u043d\u044f\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u043d\u0442<\/h3>\n<p>  \u0417\u0430\u0434\u0430\u0447\u0430 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0438 <code>contentOffset<\/code> \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0437\u0430\u043c\u0435\u043d\u044f\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0443 view. \u041f\u0440\u0438 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0435 \u0432 \u043f\u0440\u0430\u0432\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u043f\u0440\u0430\u0432\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u043d\u0435\u0442 \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u043c, \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u0442\u0430\u043d\u0435\u0442 \u043b\u0435\u0432\u044b\u043c, \u0430 \u043b\u0435\u0432\u043e\u0435 \u2014 \u043f\u0440\u0430\u0432\u044b\u043c. 1 \u2014 2 \u2014 3 | 2 \u2014 3 \u2014 1.<\/p>\n<p>  \u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c ViewModel:<\/p>\n<pre><code class=\"swift\">struct BannersViewModel {     \/\/ \u0437\u0434\u0435\u0441\u044c \u0443 \u043d\u0430\u0441 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e 3 \u0441\u0441\u044b\u043b\u043a\u0438 \u0438\u043b\u0438 \u0431\u043e\u043b\u0435\u0435 \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f     let items: [URL] = ImageURLFactory.makeImageURLS() } <\/code><\/pre>\n<p>  \u0427\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u043a\u0430\u043a\u043e\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u0435\u0439\u0447\u0430\u0441 \u0432 \u0446\u0435\u043d\u0442\u0440\u0435, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0432 <code>BannersView<\/code> \u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u043e\u043c \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0438\u0437 view:<\/p>\n<pre><code class=\"swift\">    private var currentCenterItemIndex: Int = 0      private var viewModel: BannersViewModel?      private var leftItemViewModel: URL {         guard let items = self.viewModel?.items else { fatalError(&quot;not ready&quot;) }         let leftIndex = items.index(before: self.currentCenterItemIndex)         return leftIndex &lt; 0 ? items.last! : items[leftIndex]     }     private var centerItemViewModel: URL {         guard let items = self.viewModel?.items else { fatalError(&quot;not ready&quot;) }         return items[self.currentCenterItemIndex]     }     private var rightItemViewModel: URL {         guard let items = self.viewModel?.items else { fatalError(&quot;not ready&quot;) }         let rightIndex = items.index(after: self.currentCenterItemIndex)         return rightIndex &gt;= items.count ? items.first! : items[rightIndex]     } <\/code><\/pre>\n<p>  <code>leftItemViewModel<\/code>, <code>centerItemViewModel<\/code>, <code>rightItemViewModel<\/code> \u2014 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <code>currentCenterItemIndex<\/code> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043d\u0443\u0436\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 view. <code>force unwrap<\/code> \u0438 <code>fatal<\/code> \u0437\u0434\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u2265 3 (\u043f\u0440\u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u0438, \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0432 \u043c\u0435\u0442\u043e\u0434 <code>set<\/code>).<\/p>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u0435\u0442\u043e\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0443 views:<\/p>\n<pre><code class=\"swift\">    func nextItem() {         self.currentCenterItemIndex += 1         if self.viewModel?.items.count == self.currentCenterItemIndex {             self.currentCenterItemIndex = 0         }         self.updateViews()     }      func prevItem() {         self.currentCenterItemIndex -= 1         if self.currentCenterItemIndex == -1 {             self.currentCenterItemIndex = self.viewModel?.items.indices.last ?? 0         }         self.updateViews()     }      private func updateViews() {         self.leftItemView.setImage(with: self.leftItemViewModel)         self.centerItemView.setImage(with: self.centerItemViewModel)         self.rightItemView.setImage(with: self.rightItemViewModel)     } <\/code><\/pre>\n<p>  \u0418\u0437\u043c\u0435\u043d\u0438\u043c \u043c\u0435\u0442\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u043d\u0430\u0440\u0443\u0436\u0438 \u0434\u043b\u044f \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430:<\/p>\n<pre><code class=\"swift\">    func set(viewModel: BannersViewModel) {         self.viewModel = viewModel         self.updateViews()         self.scrollView.contentOffset.x = self.centerItemView.frame.minX - Constants.horizontalItemOffsetFromSuperView     } <\/code><\/pre>\n<p>  \u0418 \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c <code>nextItem<\/code> \u0438 <code>prevItem<\/code> \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u0430 \u043f\u0440\u0438 \u0441\u043c\u0435\u043d\u0435 <code>contentOffset<\/code>:<\/p>\n<pre><code class=\"swift\">    func scrollViewDidScroll(_ scrollView: UIScrollView) {         .......          if (self.rightItemView.frame.maxX - gap) &lt; currentRightOffset {             scrollView.contentOffset.x -= self.centerItemView.frame.width + spacing             self.nextItem()         } else if (self.leftItemView.frame.minX + gap) &gt; scrollView.contentOffset.x {             scrollView.contentOffset.x += self.centerItemView.frame.width + spacing             self.prevItem()         }     } <\/code><\/pre>\n<p>  \u0423\u0432\u0435\u043b\u0438\u0447\u0438\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u0441\u0441\u044b\u043b\u043e\u043a \u043d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u043e 5 (\u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0431\u044b\u043b\u043e \u0442\u0440\u0438):<\/p>\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><video controls style=\"top: 0; left: 0; width: 100%; height: 100%; position: absolute;\">Your browser does not support HTML5 video.<source src=\"https:\/\/v003.radikal.ru\/2004\/7d\/6227953979-5-d1a9025423cdb38a310afb6ef44d5c5d.mp4\" type=\"video\/mp4\"><\/source><\/video><\/div>\n<\/div>\n<\/div>\n<p>  <\/p>\n<h2>\u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0448\u0430\u0433\u0438<\/h2>\n<p>  \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u0443\u044e <code>UIView<\/code> \u0432\u043c\u0435\u0441\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438. \u042d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a, \u043f\u043e\u0434\u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0438 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435.<\/p>\n<p>  \u0420\u0430\u0441\u0448\u0438\u0440\u0438\u043c <code>ViewModel<\/code>:<\/p>\n<pre><code class=\"swift\">struct BannersViewModel {     let items: [Item]      struct Item {         let title: String         let subtitle: String         let imageUrl: URL     } } <\/code><\/pre>\n<p>  \u0418 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0431\u0430\u043d\u043d\u0435\u0440\u0430:<\/p>\n<pre><code class=\"swift\">extension BannersView {     final class ItemView: UIView {         private let titleLabel = UILabel()         private let subtitleLabel = UILabel()         private let imageView = UIImageView()          init() {             super.init(frame: .zero)             self.setup()         }          required init?(coder aDecoder: NSCoder) {             fatalError(&quot;init(coder:) has not been implemented&quot;)         }          private func setup() {             self.addSubview(self.imageView)             self.addSubview(self.titleLabel)             self.addSubview(self.subtitleLabel)              self.imageView.contentMode = .scaleAspectFill              self.layer.masksToBounds = true             self.layer.cornerRadius = 8.0         }          func set(viewModel: BannersViewModel.Item) {             self.titleLabel.text = viewModel.title             self.subtitleLabel.text = viewModel.subtitle             self.imageView.setImage(with: viewModel.imageUrl)         }          override func layoutSubviews() {             super.layoutSubviews()             self.imageView.frame = self.bounds              self.titleLabel.frame.origin = CGPoint(x: 16.0, y: 16.0)             self.titleLabel.frame.size = CGSize(width: self.bounds.width - 32.0, height: 20.0)              self.subtitleLabel.frame.origin = CGPoint(x: 16.0, y: self.titleLabel.frame.maxY + 4.0)             self.subtitleLabel.frame.size = self.titleLabel.frame.size         }     } } <\/code><\/pre>\n<p>  \u0417\u0430\u043c\u0435\u043d\u0438\u043c <code>UIImageView<\/code> \u0438 <code>ViewModel<\/code> \u0432 <code>BannersView<\/code>::<\/p>\n<pre><code class=\"swift\">     .......      private let leftItemView = ItemView()     private let centerItemView = ItemView()     private let rightItemView = ItemView()          private var leftItemViewModel: BannersViewModel.Item { ... }     private var centerItemViewModel: BannersViewModel.Item { ... }     private var rightItemViewModel: BannersViewModel.Item { ... }      .......      private func updateViews() {         self.leftItemView.set(viewModel: self.leftItemViewModel)         self.centerItemView.set(viewModel: self.centerItemViewModel)         self.rightItemView.set(viewModel: self.rightItemViewModel)     }      ....... <\/code><\/pre>\n<p>  \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:<\/p>\n<div class=\"oembed\">\n<div>\n<div style=\"left: 0; width: 100%; height: 0; position: relative; padding-bottom: 56.25%;\"><video controls style=\"top: 0; left: 0; width: 100%; height: 100%; position: absolute;\">Your browser does not support HTML5 video.<source src=\"https:\/\/v003.radikal.ru\/2004\/83\/6227953983-5-b73c14140d0d76eb90288e27c10efa44.mp4\" type=\"video\/mp4\"><\/source><\/video><\/div>\n<\/div>\n<\/div>\n<p>  <\/p>\n<h2>\u0412\u044b\u0432\u043e\u0434\u044b<\/h2>\n<p>  \u0421\u0434\u0435\u043b\u0430\u0442\u044c \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0446\u0438\u043a\u043b\u0438\u0447\u043d\u044b\u0439 \u0441\u043a\u0440\u043e\u043b\u043b \u0441 \u0431\u0430\u043d\u043d\u0435\u0440\u0430\u043c\u0438 \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435\u0439. \u0423\u0432\u0435\u0440\u0435\u043d, \u0447\u0442\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u043c\u043e\u0436\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u0432\u044b\u0432\u043e\u0434\u044b \u0438\u043b\u0438 \u043f\u043e\u0447\u0435\u0440\u043f\u043d\u0443\u0442\u044c \u043a\u0430\u043a\u0438\u0435-\u043b\u0438\u0431\u043e \u0438\u0434\u0435\u0438 \u0438\u0437 \u043d\u0430\u0448\u0435\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u0442\u0440\u0435\u043c\u044f \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u043c\u0438 <code>UIView<\/code>.<\/p>\n<p>  \u0415\u0449\u0435 \u0440\u0430\u0437 \u043c\u044b \u0443\u0431\u0435\u0434\u0438\u043b\u0438\u0441\u044c, \u0447\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0432 \u0433\u043e\u043b\u043e\u0432\u0443 \u043f\u0435\u0440\u0432\u044b\u043c\u0438, \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435, \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c\u0438. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u043e\u043f\u0430\u0441\u0430\u043b\u0438\u0441\u044c, \u0447\u0442\u043e \u043f\u043e\u0434\u043c\u0435\u043d\u044f\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0438 \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0435, \u043d\u043e \u0432\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0433\u043b\u0430\u0434\u043a\u043e. \u041d\u0435 \u0431\u043e\u0439\u0442\u0435\u0441\u044c \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043f\u043e\u0434\u0445\u043e\u0434\u044b, \u0435\u0441\u043b\u0438 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0435, \u0447\u0442\u043e \u044d\u0442\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e. \u0414\u0443\u043c\u0430\u0439\u0442\u0435 \u0441\u0432\u043e\u0435\u0439 \u0433\u043e\u043b\u043e\u0432\u043e\u0439 :).<\/p><\/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\/company\/youla\/blog\/498462\/\"> https:\/\/habr.com\/ru\/company\/youla\/blog\/498462\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/company\/youla\/blog\/498462\/\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/322\/2d5\/f74\/3222d5f742f0548e472a4f5d0fb94a91.gif\"><\/div>\n<p>  \u041a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u043e\u0434 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441 \u0437\u0430\u0434\u0430\u0447\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0435 \u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c. \u0412\u0441\u0435\u0433\u0434\u0430 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0443\u0442\u0435\u0439, \u2014 \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u0431\u044b\u0441\u0442\u0440\u044b\u0435, \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u0435, \u2014 \u0438 \u0443 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0432\u043e\u0438 \u0434\u043e\u0441\u0442\u043e\u0438\u043d\u0441\u0442\u0432\u0430 \u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438.<\/p>\n<p>  \u0411\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439\/\u0446\u0438\u043a\u043b\u0438\u0447\u043d\u044b\u0439 \u0441\u043a\u0440\u043e\u043b\u043b \u0432 iOS \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c\u0438 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c\u0438 \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c, \u043d\u0443\u0436\u043d\u043e \u0438\u0434\u0442\u0438 \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0435 \u0443\u0445\u0438\u0449\u0440\u0435\u043d\u0438\u044f. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a\u0438\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 \u043b\u0435\u0436\u0430\u0442 \u043d\u0430 \u043f\u043e\u0432\u0435\u0440\u0445\u043d\u043e\u0441\u0442\u0438 \u0438 \u043a\u0430\u043a\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043c\u044b \u0432 \u0438\u0442\u043e\u0433\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438.  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-302318","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/302318","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=302318"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/302318\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=302318"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=302318"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=302318"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}