рдореЛрдмрд╛рдЗрд▓ рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдХреЗ рд▓рд┐рдП рдкреНрд░рддреНрдпреЗрдХ рдбреЗрд╡рд▓рдкрд░ рдХреЛ рдПрдХ рдХрд╛рд░реНрдп рдХреЗ рд╕рд╛рде рд▓рдЧрд╛рддрд╛рд░ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рдПрдХ рд╣реА рддрд░реАрдХреЗ рд╕реЗ рд╣рд▓ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд╣рдореЗрд╢рд╛ рдХрдИ рддрд░реАрдХреЗ рд╣реЛрддреЗ рд╣реИрдВ, рдХреБрдЫ рддреНрд╡рд░рд┐рдд, рдХреБрдЫ рдЬрдЯрд┐рд▓, рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рдХреЗ рдЕрдкрдиреЗ рдлрд╛рдпрджреЗ рдФрд░ рдиреБрдХрд╕рд╛рди рд╣реЛрддреЗ рд╣реИрдВредрдЖрдИрдУрдПрд╕ рдореЗрдВ рдЕрдВрддрд╣реАрди / рдЪрдХреНрд░реАрдп рд╕реНрдХреНрд░реЙрд▓ рдорд╛рдирдХ рдЙрдкрдХрд░рдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЖрдкрдХреЛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдЪрд╛рд▓ рдореЗрдВ рдЬрд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдЖрдкрдХреЛ рдмрддрд╛рдКрдВрдЧрд╛ рдХрд┐ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреМрди рд╕реЗ рд╡рд┐рдХрд▓реНрдк рд╕рддрд╣ рдкрд░ рд╣реИрдВ рдФрд░ рдХреМрди рд╕рд╛ рд╡рд┐рдХрд▓реНрдк рд╣рдордиреЗ рдЕрдВрддрддрдГ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛редрдХрд╛рд░реНрдп
рддреИрдпрд╛рд░ рдЪрд┐рддреНрд░, рд╢реАрд░реНрд╖рдХ рдФрд░ рдЙрдкрд╢реАрд░реНрд╖рдХ рдХреЗ рд░реВрдк рдореЗрдВ рддрддреНрд╡реЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдЕрдВрддрд╣реАрди рдЪрдХреНрд░реАрдп рд╕реНрдХреНрд░реЙрд▓ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рдерд╛ред рдЗрдирдкреБрдЯ: рдХреЗрдВрджреНрд░реАрдп рдЫрд╡рд┐ 16.0 рдЕрдВрдХреЛрдВ рд╕реЗ рд╕реНрдХреНрд░реАрди рд╕реЗ рдЗрдВрдбреЗрдВрдЯ рд╣реЛрддреА рд╣реИред рдХреЗрдВрджреНрд░реАрдп рдЫрд╡рд┐ рдХреЗ рдХрд┐рдирд╛рд░реЛрдВ рдкрд░ "рдХрд╛рди" рдЪрд┐рдкрдХреЗ рд░рд╣рддреЗ рд╣реИрдВред рдФрд░ рдмреИрдирд░ рдХреЗ рдмреАрдЪ рдХреА рджреВрд░реА 8.0 рдЕрдВрдХ рд╣реИредрд╣рдо рдЕрдзреНрдпрдпрди рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рд╕рд╣рдпреЛрдЧрд┐рдпреЛрдВ рджреНрд╡рд╛рд░рд╛ рдХреНрдпрд╛ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ
рдбреЛрдбреЛ - рдмреИрдирд░ рдЪрдХреНрд░реАрдп рдирд╣реАрдВ рд╣реИрдВ, рдХреЗрдВрджреНрд░реАрдп рдмреИрдирд░ рд╣рдореЗрд╢рд╛ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рджреВрд░реА рдкрд░ рдмрд╛рдПрдВ рдХрд┐рдирд╛рд░реЗ рд╕реЗ рд╕рдЯреЗ рд╣реЛрддреЗ рд╣реИрдВредAuto.ru - рдмреИрдирд░ рдЪрдХреНрд░реАрдп рдирд╣реАрдВ рд╣реИрдВ, рдпрджрд┐ рдЖрдк рд╕реНрд╡рд╛рдЗрдк рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдмреИрдирд░ рдмрд╣реБрдд рд▓рдВрдмреЗ рд╕рдордп рддрдХ рдлрд╝реНрд▓рд┐рдк рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВредрдУрдЬреЛрди - рдмреИрдирд░ рдЪрдХреНрд░реАрдп рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЙрдиреНрд╣реЗрдВ рд╕реНрдкрд░реНрд╢ рджреНрд╡рд╛рд░рд╛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ: рдПрдХ рдмрд╛рд░ рд╕реНрд╡рд╛рдЗрдк рдХреА рджрд┐рд╢рд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рддрд╕реНрд╡реАрд░ рдХреЛ рд░реЛрдХрд╛ рдирд╣реАрдВ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИредрд╡рд╛рдЗрд▓реНрдбрдмреЗрд░реАрдЬрд╝ - рдмреИрдирд░ рдЪрдХреНрд░реАрдп рдирд╣реАрдВ рд╣реИрдВ, рдХреЗрдВрджреНрд░рд┐рдд рд╣реЛрддрд╛ рд╣реИ, рд╕реНрдХреНрд░реЙрд▓ рдПрдиреАрдореЗрд╢рди рдХреЗ рд▓рдВрдмреЗ рд╕рдордп рддрдХ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдкрд░редрдЕрдВрддрд┐рдо рдЗрдЪреНрдЫрд╛:- рдмреИрдирд░ рдХреЗрдВрджреНрд░рд┐рдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред
- рд╕реНрдХреНрд░реЙрд▓рд┐рдВрдЧ рдХреЛ рдПрдиреАрдореЗрд╢рди рдХреЗ рд▓рдВрдмреЗ рдЗрдВрддрдЬрд╛рд░ рдХреЗ рдмрд┐рдирд╛ рд╕рдорд╛рдкреНрдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред
- рдмреИрдирд░ рдХреА рдкреНрд░рдмрдВрдзрди рдХреНрд╖рдорддрд╛: рдЕрдкрдиреА рдЙрдВрдЧрд▓реА рд╕реЗ рд╕реНрдХреНрд░реЙрд▓ рдПрдиреАрдореЗрд╢рди рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд╡рд┐рдХрд▓реНрдк
рдЬрдм рдПрдХ рдирдпрд╛ рдХрд╛рд░реНрдп рдЙрддреНрдкрдиреНрди рд╣реЛрддрд╛ рд╣реИ рдЬреЛ рдЕрднреА рддрдХ рд╣рд▓ рдирд╣реАрдВ рд╣реБрдЖ рд╣реИ, рддреЛ рдпрд╣ рдореМрдЬреВрджрд╛ рд╕рдорд╛рдзрд╛рдиреЛрдВ рдФрд░ рджреГрд╖реНрдЯрд┐рдХреЛрдгреЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд╛рдпрдХ рд╣реИредUICollectionView
рдорд╛рдереЗ рдореЗрдВ рдЕрднрд┐рдирдп рдХрд░рддреЗ рд╣реБрдП, рдЖрдк рдмрдирд╛рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк рдкрд░ рдЖ рд╕рдХрддреЗ рд╣реИрдВ UICollectionView
ред рд╣рдо рддрддреНрд╡реЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдмрдирд╛рддреЗ рд╣реИрдВ Int.max
рдФрд░ рдЖрд░рдВрднреАрдХрд░рдг рдХреЗ рджреМрд░рд╛рди рд╣рдо рдордзреНрдп рджрд┐рдЦрд╛рддреЗ рд╣реИрдВ, рдФрд░ рдЬрдм dataSource
- рдореЗрдВ рд╡рд┐рдзрд┐ рдХреЛ рдмреБрд▓рд╛рддреЗ рд╣реИрдВ func collectionView(UICollectionView, cellForItemAt: IndexPath) -> UICollectionViewCell
ред рд╣рдо рдЗрд╕реА рддрддреНрд╡ рдХреЛ рд╡рд╛рдкрд╕ рдХрд░реЗрдВрдЧреЗ, рдпрд╣ рдорд╛рдирддреЗ рд╣реБрдП рдХрд┐ рд╢реВрдиреНрдп рддрддреНрд╡ рдпрд╣ рд╣реИ Int.max / 2
ред рд╕реБрд╡рд┐рдзрд╛рдУрдВ рдХрд╛ рдПрдХ рдЧреБрдЪреНрдЫрд╛ рдХреЗ рд╕рд╛рде рдЗрд╕ рддрд░рд╣ рдХреЗ рдПрдХ рд░рд╛рдХреНрд╖рд╕, рдЬреИрд╕реЗ UICollectionView
, рд╣рдорд╛рд░реЗ рд╕рд░рд▓ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЕрдиреБрдЪрд┐рдд рд╣реИредUIScrollView рдФрд░ (n + 2) UIView
рдЕрднреА рднреА рдПрдХ рд╡рд┐рдХрд▓реНрдк рд╣реИ рдЬрд┐рд╕рдореЗрдВ UIScrollView рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдмрд┐рд▓реНрдХреБрд▓ рд╕рднреА рдмреИрдирд░ рдЙрд╕ рдкрд░ рд░рдЦреЗ рдЧрдП рд╣реИрдВ, рдФрд░ рдпрд╣ рдмреИрдирд░ рджреНрд╡рд╛рд░рд╛ рд╢реБрд░реБрдЖрдд рдФрд░ рдЕрдВрдд рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рд╣реИред рдЬрдм рд╣рдо рдЗрд╕реЗ рд╕рдорд╛рдкреНрдд рдХрд░ рд▓реЗрддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рдЕрдкрд░рд┐рд╣рд╛рд░реНрдп рд░реВрдк рд╕реЗ рдСрдлрд╕реЗрдЯ рдмрджрд▓рддреЗ рд╣реИрдВ рдФрд░ рдкрд╣рд▓реЗ рддрддреНрд╡ рдкрд░ рд▓реМрдЯ рдЖрддреЗ рд╣реИрдВред рдФрд░ рдЬрдм рд╡рд╛рдкрд╕ рд╕реНрдХреНрд░реЙрд▓ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рд╡рд┐рдкрд░реАрдд рдХрд░рддреЗ рд╣реИрдВред рдирддреАрдЬрддрди, рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рддрддреНрд╡реЛрдВ рдХреЗ рд╕рд╛рде, рдЙрдиреНрд╣реЗрдВ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдмрд┐рдирд╛ рд╡рд┐рдЪрд╛рд░реЛрдВ рдХрд╛ рдПрдХ рдЧреБрдЪреНрдЫрд╛ рдмрдирд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рд╕реНрд░реЛрддрдЕрдкрдиреЗ рддрд░реАрдХреЗ рд╕реЗ
рд╣рдордиреЗ UIScrollView + рддреАрди UIView рдмрдирд╛рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ред рдЗрди UIView рдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рд╕реНрдХреНрд░реЙрд▓рд┐рдВрдЧ рдХреЗ рд╕рдордп, рд╣рдо contentOffset
рдХреЗрдВрджреНрд░реАрдп рдмреИрдирд░ рдкрд░ рд▓реМрдЯ рдЖрдПрдВрдЧреЗ рдФрд░ рддреАрдиреЛрдВ UIView рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЛ рдмрджрд▓ рджреЗрдВрдЧреЗ ред рдФрд░ рдлрд┐рд░ рдЖрдкрдХреЛ рдПрдХ рд╣рд▓реНрдХрд╛ рдШрдЯрдХ рдорд┐рд▓рдирд╛ рдЪрд╛рд╣рд┐рдП рдЬреЛ рдЗрд╕ рдХрд╛рд░реНрдп рдХреЛ рдмрдВрдж рдХрд░ рджреЗрддрд╛ рд╣реИредрд╣рд╛рд▓рд╛рдВрдХрд┐, рдПрдХ рдЪрд┐рдВрддрд╛ рдпрд╣ рд╣реИ рдХрд┐ рд╕реНрдХреНрд░реЙрд▓рд┐рдВрдЧ рдХреЗ рджреМрд░рд╛рди рдЦрд░рд╛рдм рд╣реЛрдиреЗ рд╡рд╛рд▓реА рд╕рд╛рдордЧреНрд░реА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реЛрдЧреАред рд╣рдо рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рджреМрд░рд╛рди рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реАрдЦрддреЗ рд╣реИрдВредрдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
UIScrollView рдФрд░ рддреАрди UIImageView рддреИрдпрд╛рд░ рдХрд░рдирд╛
рдПрдХ рд╡рд╛рд░рд┐рд╕ рдмрдирд╛рдПрдВ UIView
, рдЙрд╕ рдкрд░ UIScrollView
рддреАрди рдЬрдЧрд╣ рджреЗрдВ UIImageView
: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("init(coder:) has not been implemented")
}
private func setup() {
self.addSubview(self.scrollView)
self.setupScrollView()
let imageViews = [self.leftItemView, self.centerItemView, self.rightItemView]
imageViews.forEach(self.scrollView.addSubview)
}
}
рд╕реЗрдЯрд┐рдВрдЧ рдХреЗ рд╕рд╛рде рд╡рд┐рдзрд┐ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЬреЛрдбрд╝реЗрдВ scrollView
:рдореВрд▓ рд╕реЗрдЯрдЕрдк рдХреЗ рдмрд╛рдж, рд╣рдо рд▓реЗрдЖрдЙрдЯ рдФрд░ рдкреНрд▓реЗрд╕рдореЗрдВрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ ImageView
: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)
}
рдЙрди UIImageView
рдЫрд╡рд┐рдпреЛрдВ рдХреЛ рдЬреЛрдбрд╝реЗрдВ рдЬрд┐рдиреНрд╣реЗрдВ рд╣рдо рдЫрд╡рд┐ рдЬрдирд░реЗрдЯрд░ рд╕рд╛рдЗрдЯ https://placeholder.com рд╕реЗ рдЦреАрдВрдЪреЗрдВрдЧреЗ : let imageURLs = ImageURLFactory.makeImageURLS()
imageViews.enumerated().forEach { key, view in
view.setImage(with: imageURLs[key])
}
рдкрд╣рд▓реЗ рддреИрдпрд╛рд░реА рдЪрд░рдгреЛрдВ рдХрд╛ рдкрд░рд┐рдгрд╛рдо:рд╕реНрдХреНрд░реЙрд▓ рдХрд░рддреЗ рд╕рдордп рдХреЗрдВрджреНрд░ рдЫрд╡рд┐рдпрд╛рдВ
рд╕реНрдХреНрд░реЙрд▓ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдо рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ UIScrollViewDelegate
ред рд╣рдо setup
рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреЛ рд╡рд┐рдзрд┐ рдХреЗ рд▓рд┐рдП рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВ UIScrollView
, рдФрд░ contentInset
рдкрдХреНрд╖реЛрдВ рдкрд░ рдЗрдВрдбреЗрдВрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╣рд▓реА рдФрд░ рдЕрдВрддрд┐рдо рдЫрд╡рд┐рдпрд╛рдВ рднреА рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВредself.scrollView.contentInset = UIEdgeInsets(top: 0.0, left: 16.0, bottom: 0.0, right: 16.0)
self.scrollView.delegate = self
рд╣рдо рдЕрдкрдиреЗ рддрд░реАрдХреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдХреЗ extension
рд▓рд┐рдП рдмрдирд╛рддреЗ рд╣реИрдВ BannersView
ред func scrollViewWillEndDragging
рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рджреНрд╡рд╛рд░рд╛ рд╕реНрдХреНрд░реЙрд▓ рдХрд░рдирд╛ рдмрдВрдж рдХрд░рдиреЗ рдкрд░ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рд╡рд┐рдзрд┐ рдХреЛ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕ рдкрджреНрдзрддрд┐ рдореЗрдВ, рд╣рдо рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ targetContentOffset
- рдпрд╣ рд╡рд╣ рдЪрд░ рд╣реИ рдЬреЛ рдЕрдВрддрд┐рдо рд╕реНрдХреНрд░реЙрд▓ рдСрдлрд╝рд╕реЗрдЯ рдХреЗ рд▓рд┐рдП рдЬрд╝рд┐рдореНрдореЗрджрд╛рд░ рд╣реИ (рд╡рд╣ рдмрд┐рдВрджреБ рдЬрд┐рд╕ рдкрд░ рд╕реНрдХреНрд░реЙрд▓ рдмрдВрдж рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ)ред
extension BannersView: UIScrollViewDelegate {
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let gap: CGFloat = self.centerItemView.frame.width / 3
let targetRightOffsetX = targetContentOffset.pointee.x + self.frame.width
if (self.rightItemView.frame.minX + gap) < targetRightOffsetX {
targetContentOffset.pointee.x = self.rightItemView.frame.midX - self.frame.midX
}
else if (self.leftItemView.frame.maxX - gap) > targetContentOffset.pointee.x {
targetContentOffset.pointee.x = self.leftItemView.frame.midX - self.frame.midX
}
else {
targetContentOffset.pointee.x = self.centerItemView.frame.midX - self.frame.midX
}
}
}
gap
- рдпрд╣ рд╡рд╣ рджреВрд░реА рд╣реИ рдЬрд┐рд╕ рдкрд░ рд╣рдо рдпрд╣ рдорд╛рди рд▓реЗрдВрдЧреЗ рдХрд┐ рджреГрд╢реНрдп рдХреЗрдВрджреНрд░реАрдп рд╣реИред рдпрджрд┐ рд╕реНрдХреНрд░реАрди рдкрд░ рдирд╛рд░рдВрдЧреА рдЫрд╡рд┐ рдХреА рдЪреМрдбрд╝рд╛рдИ рдХрд╛ рдПрдХ рддрд┐рд╣рд╛рдИ рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрддрд╛ рд╣реИ, рддреЛ рд╣рдо рдЕрдВрддрд┐рдо рдСрдлрд╕реЗрдЯ рд╕реЗрдЯ рдХрд░реЗрдВрдЧреЗ рддрд╛рдХрд┐ рдирд╛рд░рдВрдЧреА рдЫрд╡рд┐ рдХреЗрдВрджреНрд░ рдореЗрдВ рд╣реЛредtargetRightOffsetX
- рдпрд╣ рдмрд┐рдВрджреБ рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛ рдХрд┐ рд╕рд╣реА рджреГрд╢реНрдп рдХреЗрдВрджреНрд░реАрдп рд╣реИ рдпрд╛ рдирд╣реАрдВредрдЗрд╕ рд╡рд┐рдзрд┐ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рдкрд░рд┐рдгрд╛рдо:рд╕реНрдХреНрд░реЙрд▓ рдХрд░рддреЗ рд╣реБрдП рдСрдлрд╝рд╕реЗрдЯ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд░реЗрдВ
рдЕрдм, рд╕реНрдХреНрд░реЙрд▓рд┐рдВрдЧ рдХреЗ рджреМрд░рд╛рди, рд╣рдо рдмрджрд▓ рдЬрд╛рдПрдВрдЧреЗ contentOffset
, рд╕реНрдХреНрд░реАрди рдХреЗ рдХреЗрдВрджреНрд░ рдореЗрдВ рдХреЗрдВрджреНрд░реАрдп рджреГрд╢реНрдп рдкрд░ рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдЧрд╛ред рдпрд╣ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдмрд┐рдирд╛ рдХрд┐рд╕реА рд╕реВрдЪрдирд╛ рдХреЗ рдЕрдирдВрдд рд╕реНрдХреНрд░реЙрд▓рд┐рдВрдЧ рдХрд╛ рднреНрд░рдо рдкреИрджрд╛ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛редрдПрдХ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рд╡рд┐рдзрд┐ рдЬреЛрдбрд╝реЗрдВ func scrollViewDidScroll(_ scrollView: UIScrollView)
, рдЗрд╕реЗ contentOffset
y рдкрд░рд┐рд╡рд░реНрддрди рд╣реЛрдиреЗ рдкрд░ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ UIScrollView
ред
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard
self.leftItemView.frame.width > 0,
self.centerItemView.frame.width > 0,
self.rightItemView.frame.width > 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) < currentRightOffset {
scrollView.contentOffset.x -= self.centerItemView.frame.width + spacing
} else if (self.leftItemView.frame.minX + gap) > scrollView.contentOffset.x {
scrollView.contentOffset.x += self.centerItemView.frame.width + spacing
}
}
gap
- рдпрд╣ рд╡рд╣ рджреВрд░реА рд╣реИ рдЬрд╣рд╛рдВ рд╕реЗ рд╣рдо рд╡рд┐рд╕реНрдерд╛рдкрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХрд╛ рдирд┐рд░реНрдзрд╛рд░рдг рдХрд░реЗрдВрдЧреЗ contentOffset
ред рд╣рдо рдЙрд╕ рдмрд┐рдВрджреБ рдХреА рдЧрдгрдирд╛ рдХрд░рддреЗ рд╣реИрдВ rightItemView
: self.rightItemView.frame.maxX тАФ gap
рдЬрд┐рд╕ рдЪреМрд░рд╛рд╣реЗ рдХреЗ рдмрд╛рдж рд╣рдо рд╢рд┐рдлреНрдЯ рд╣реЛрдВрдЧреЗ contentOffset
ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ rightItemView
100.0 рдЕрдВрдХ рдкреВрд░реНрдг рдкреНрд░рджрд░реНрд╢рди рддрдХ рд╕реНрдХреНрд░реЙрд▓ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ , рддреЛ рд╣рдо contentOffset
рдПрдХ рдмреИрдирд░ рдХреА рдЪреМрдбрд╝рд╛рдИ рд╕реЗ, рдкреАрдЫреЗ рдХреА рдУрд░ рд╢рд┐рдлреНрдЯ рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВ, рдмреИрдирд░ (рд░рд┐рдХреНрддрд┐) рдХреЗ рдмреАрдЪ рдХреА рджреВрд░реА рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрддреЗ рд╣реБрдП, рддрд╛рдХрд┐ рдпрд╣ centerItemView
рдЬрдЧрд╣ рдореЗрдВ рд╣реЛ rightItemView
ред рдЗрд╕реА рддрд░рд╣, рд╣рдо рдЗрд╕рдХреЗ рд▓рд┐рдП рдХрд░рддреЗ рд╣реИрдВ leftItemView
: рд╣рдо рдЙрд╕ рдмрд┐рдВрджреБ рдХреА рдЧрдгрдирд╛ рдХрд░рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХреЗ рдЪреМрд░рд╛рд╣реЗ рдХреЗ рдмрд╛рдж рд╣рдо рдмрджрд▓ рдЬрд╛рдПрдВрдЧреЗ contentOffset
редfunc set(imageURLs: [URL])
рдмрд╛рд╣рд░ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рдХреЛ рдЙрдЬрд╛рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рдзрд┐ рдЬреЛрдбрд╝реЗрдВ ред рд╡рд╣рд╛рдВ рд╕реЗ рд╣рдо рдХреЛрдб рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ setup
редрдФрд░ рд╣рдо рдПрдХ рдкрдВрдХреНрддрд┐ рднреА рдЬреЛрдбрд╝реЗрдВрдЧреЗ рддрд╛рдХрд┐ рдЬрдм рдЖрдк рд╕рд╛рдордЧреНрд░реА рд╕реЗрдЯ рдХрд░реЗрдВ рддреЛ рд╡рд╣ centerItemView
рддреБрд░рдВрдд рдХреЗрдВрджреНрд░рд┐рдд рд╣реЛ рдЬрд╛рдПред horizontalItemOffsetFromSuperView
рд╣рдордиреЗ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИ layoutSubviews
, рдЗрд╕рд▓рд┐рдП рд╣рдо рдЗрд╕реЗ рд╕реНрдерд┐рд░рд╛рдВрдХ рдореЗрдВ рд░рдЦрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рдлрд┐рд░ рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВредfunc set(imageURLs: [URL]) {
let imageViews = [self.leftItemView, self.centerItemView, self.rightItemView]
imageViews.enumerated().forEach { key, view in
view.setImage(with: imageURLs[key])
}
self.scrollView.contentOffset.x = self.centerItemView.frame.minX - Constants.horizontalItemOffsetFromSuperView
}
рд╣рдо рдЗрд╕ рд╡рд┐рдзрд┐ рдХреЛ рдмрд╛рд╣рд░ рдХрд╣реЗрдВрдЧреЗ UIViewController.viewDidAppear
ред рдпрд╛ рдЖрдк рдкрд╣рд▓реЗ рд╕рдВрд░реЗрдЦрдг рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ layoutSubviews
, рд▓реЗрдХрд┐рди рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдпрд╣ рдХреЗрд╡рд▓ рдкреВрд░реЗ рджреГрд╢реНрдп рдХреЗ рдлреНрд░реЗрдо рдХреЛ рдмрджрд▓рддреЗ рд╕рдордп рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдХрд╛рд░реНрдп рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдкрд╣рд▓реА рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ: рддреЛ ... рдПрдХ рддреЗрдЬ рд╕реНрдХреНрд░реЙрд▓ рдХреЗ рд╕рд╛рде, рдХреЗрдВрджреНрд░рд┐рдд рдЯреВрдЯ рдЧрдпрд╛редрддрдереНрдп рдпрд╣ рд╣реИ рдХрд┐ рдордЬрдмреВрдд рд╕реНрдХреНрд░реЙрд▓рд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдЗрд╕реЗ рдЕрдирджреЗрдЦрд╛ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ targetContentOffset
ред рдЖрдЗрдП рд╡реГрджреНрдзрд┐ рдХрд░реЗрдВ contentInset
, рдЗрд╕рдХреЗ рдмрд╛рдж рд╕рдм рдХреБрдЫ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдХреЗрдВрджреНрд░реАрдп рджреГрд╢реНрдп рд╣рдореЗрд╢рд╛ рдХреЗрдВрджреНрд░рд┐рдд рд░рд╣реЗрдЧрд╛редself.scrollView.contentInset = UIEdgeInsets(top: 0.0, left: 300.0, bottom: 0.0, right: 300.0)
рд╣рдо рд╕рд╛рдордЧреНрд░реА рдХреЛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд░рддреЗ рд╣реИрдВ
рдХрд╛рд░реНрдп рдПрдХ contentOffset
рд╣реА рд╕рдордп рдореЗрдВ рдСрдлрд╝рд╕реЗрдЯ рдкрд░ рджреГрд╢реНрдп рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдирд╛ рд╣реИред рджрд╛рдИрдВ рдУрд░ рд╕реНрдХреНрд░реЙрд▓ рдХрд░рдиреЗ рдкрд░, рджрд╛рдИрдВ рдЫрд╡рд┐ рдХреЗрдВрджреНрд░реАрдп рд╣реЛ рдЬрд╛рдПрдЧреА, рдХреЗрдВрджреНрд░ рдмрд╛рдПрдВ рд╣реЛ рдЬрд╛рдПрдЧрд╛, рдФрд░ рдмрд╛рдПрдВ рджрд╛рдИрдВ рдУрд░ рд╣реЛ рдЬрд╛рдПрдЧрд╛ред 1 - 2 - 3 | 2 - 3 - 1.рд╕реБрд╡рд┐рдзрд╛ рдХреЗ рд▓рд┐рдП, рдПрдХ ViewModel рдмрдирд╛рдПрдВ:struct BannersViewModel {
let items: [URL] = ImageURLFactory.makeImageURLS()
}
рдпрд╣ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдЕрдм рдХреМрди рд╕рд╛ рддрддреНрд╡ рдХреЗрдВрджреНрд░ рдореЗрдВ рд╣реИ, BannersView
рдкреНрд░рддреНрдпреЗрдХ рджреГрд╢реНрдп рдХреЗ рд▓рд┐рдП рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╕рд╛рде рдПрдХ рдЪрд░ рдФрд░ рдЪрд░ рдЬреЛрдбрд╝реЗрдВ : private var currentCenterItemIndex: Int = 0
private var viewModel: BannersViewModel?
private var leftItemViewModel: URL {
guard let items = self.viewModel?.items else { fatalError("not ready") }
let leftIndex = items.index(before: self.currentCenterItemIndex)
return leftIndex < 0 ? items.last! : items[leftIndex]
}
private var centerItemViewModel: URL {
guard let items = self.viewModel?.items else { fatalError("not ready") }
return items[self.currentCenterItemIndex]
}
private var rightItemViewModel: URL {
guard let items = self.viewModel?.items else { fatalError("not ready") }
let rightIndex = items.index(after: self.currentCenterItemIndex)
return rightIndex >= items.count ? items.first! : items[rightIndex]
}
leftItemViewModel
, centerItemViewModel
, rightItemViewModel
- рдХреЗ рдЖрдзрд╛рд░ рдкрд░ currentCenterItemIndex
рдкреНрд░рддреНрдпреЗрдХ рджреГрд╢реНрдп рдХреЗ рд▓рд┐рдП рд╡рд╛рдкрд╕реА рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рд╕рд╛рдордЧреНрд░реАред force unwrap
рдФрд░ fatal
рдпрд╣рд╛рдВ рд╣рдо рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рдХреНрдпреЛрдВрдХрд┐ рддрддреНрд╡реЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ if 3 рд╣реИ (рдпрджрд┐ рд╡рд╛рдВрдЫрд┐рдд рд╣реИ, рддреЛ рдЖрдк рд╡рд┐рдзрд┐ рдореЗрдВ рдПрдХ рдЪреЗрдХ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ set
)редрд╡рд┐рдЪрд╛рд░реЛрдВ рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЛ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ рддреЛ рд╡реЗ рд╡рд┐рдзрд┐рдпрд╛рдБ рдЬреЛрдбрд╝реЗрдВ: 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)
}
рд╕рд╛рдордЧреНрд░реА рдХреЛ рдЙрдЬрд╛рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╛рд╣рд░реА рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ: func set(viewModel: BannersViewModel) {
self.viewModel = viewModel
self.updateViews()
self.scrollView.contentOffset.x = self.centerItemView.frame.minX - Constants.horizontalItemOffsetFromSuperView
}
рдФрд░ рд╣рдо рдХреЙрд▓ рдХрд░реЗрдВрдЧреЗ nextItem
, рдФрд░ prevItem
рдмрджрд▓рддреЗ рд╕рдордп рд╡рд┐рдзрд┐ рдореЗрдВ рдкреНрд░рддрд┐рдирд┐рдзрд┐ contentOffset
: func scrollViewDidScroll(_ scrollView: UIScrollView) {
.......
if (self.rightItemView.frame.maxX - gap) < currentRightOffset {
scrollView.contentOffset.x -= self.centerItemView.frame.width + spacing
self.nextItem()
} else if (self.leftItemView.frame.minX + gap) > scrollView.contentOffset.x {
scrollView.contentOffset.x += self.centerItemView.frame.width + spacing
self.prevItem()
}
}
рдЖрдЗрдП рдЫрд╡рд┐рдпреЛрдВ рдХреЗ рдЗрдирдкреБрдЯ рд▓рд┐рдВрдХ рдХреА рд╕рдВрдЦреНрдпрд╛ рдмрдврд╝рд╛рдХрд░ 5 рдХрд░реЗрдВ (рд╕реБрд╡рд┐рдзрд╛ рдХреЗ рд▓рд┐рдП рддреАрди рдереЗ):рдЕрдВрддрд┐рдо рдЪрд░рдг
рдпрд╣ UIView
рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдЪрд┐рддреНрд░ рдХреЗ рдмрдЬрд╛рдп рдХрд╕реНрдЯрдо рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИ ред рдпрд╣ рд╢реАрд░реНрд╖рдХ, рдЙрдкрд╢реАрд░реНрд╖рдХ рдФрд░ рдЫрд╡рд┐ рд╣реЛрдЧреАредрдмрдврд╝рд╛рдПрдБ ViewModel
:struct BannersViewModel {
let items: [Item]
struct Item {
let title: String
let subtitle: String
let imageUrl: URL
}
}
рдФрд░ рдПрдХ рдмреИрдирд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд▓рд┐рдЦреЗрдВ: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("init(coder:) has not been implemented")
}
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
}
}
}
рдмрджрд▓реЗрдВ UIImageView
рдФрд░ ViewModel
рдореЗрдВ BannersView
::
.......
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)
}
.......
рдкрд░рд┐рдгрд╛рдо:рдЬрд╛рдБрдЪ - рдкрд░рд┐рдгрд╛рдо
рдмреИрдирд░ рдХреЗ рд╕рд╛рде рдПрдХ рдЕрдВрддрд╣реАрди рд▓реВрдкрд┐рдВрдЧ рд╕реНрдХреНрд░реЙрд▓ рдмрдирд╛рдирд╛ рдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рдХрд╛рдо рдерд╛ред рдореБрдЭреЗ рдпрдХреАрди рд╣реИ рдХрд┐ рд╣рд░ рдХреЛрдИ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдирд┐рд╖реНрдХрд░реНрд╖ рдирд┐рдХрд╛рд▓рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдЧрд╛ рдпрд╛ рдХреЗрд╡рд▓ рддреАрди рдкреБрди: рдкреНрд░рдпреЛрдЬреНрдп рд▓реЛрдЧреЛрдВ рдХреЗ рд╕рд╛рде рд╣рдорд╛рд░реЗ рдирд┐рд░реНрдгрдп рд╕реЗ рдХреЛрдИ рд╡рд┐рдЪрд╛рд░ рдЖрдХрд░реНрд╖рд┐рдд рдХрд░реЗрдЧрд╛ UIView
редрдПрдХ рдмрд╛рд░ рдлрд┐рд░, рд╣рдо рдЖрд╢реНрд╡рд╕реНрдд рдереЗ рдХрд┐ рд╕рдорд╛рдзрд╛рди рдЬреЛ рдкрд╣рд▓реЗ рджрд┐рдорд╛рдЧ рдореЗрдВ рдЖрддреЗ рд╣реИрдВ рдФрд░ рдЬреЛ рд╕рдорд╛рдзрд╛рди рдЖрдк рдЗрдВрдЯрд░рдиреЗрдЯ рдкрд░ рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рд╡реЗ рд╣рдореЗрд╢рд╛ рдЗрд╖реНрдЯрддрдо рдирд╣реАрдВ рд╣реЛрддреЗ рд╣реИрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдбрд░рддреЗ рдереЗ рдХрд┐ рд╕реНрдХреНрд░реЙрд▓рд┐рдВрдЧ рдХреЗ рджреМрд░рд╛рди рд╕рд╛рдордЧреНрд░реА рдХреЛ рдмрджрд▓рдиреЗ рд╕реЗ рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рд╣реЛрдЧреА, рд▓реЗрдХрд┐рди рд╕рдм рдХреБрдЫ рд╕реБрдЪрд╛рд░реВ рд░реВрдк рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рдЖрдкрдХреЛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рд╕рд╣реА рд╣реИ, рддреЛ рдЕрдкрдиреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдгреЛрдВ рдХреЛ рдЖрдЬрд╝рдорд╛рдиреЗ рд╕реЗ рдбрд░реЛ рдорддред рдЕрдкрдиреЗ рдЦреБрдж рдХреЗ рд╕рд┐рд░ рдХреЗ рд╕рд╛рде рд╕реЛрдЪреЛ :)ред