рдмреИрдирд░ рдХреЗ рд╕рд╛рде рдЕрдирдВрдд рд╕реНрдХреНрд░реЙрд▓, рдпрд╛ рддреАрди рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЗ рд╕рд╛рде рдХреИрд╕реЗ рдХрд░реЗрдВ


рдореЛрдмрд╛рдЗрд▓ рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдХреЗ рд▓рд┐рдП рдкреНрд░рддреНрдпреЗрдХ рдбреЗрд╡рд▓рдкрд░ рдХреЛ рдПрдХ рдХрд╛рд░реНрдп рдХреЗ рд╕рд╛рде рд▓рдЧрд╛рддрд╛рд░ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝рддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рдПрдХ рд╣реА рддрд░реАрдХреЗ рд╕реЗ рд╣рд▓ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд╣рдореЗрд╢рд╛ рдХрдИ рддрд░реАрдХреЗ рд╣реЛрддреЗ рд╣реИрдВ, рдХреБрдЫ рддреНрд╡рд░рд┐рдд, рдХреБрдЫ рдЬрдЯрд┐рд▓, рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рдХреЗ рдЕрдкрдиреЗ рдлрд╛рдпрджреЗ рдФрд░ рдиреБрдХрд╕рд╛рди рд╣реЛрддреЗ рд╣реИрдВред

рдЖрдИрдУрдПрд╕ рдореЗрдВ рдЕрдВрддрд╣реАрди / рдЪрдХреНрд░реАрдп рд╕реНрдХреНрд░реЙрд▓ рдорд╛рдирдХ рдЙрдкрдХрд░рдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЖрдкрдХреЛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдЪрд╛рд▓ рдореЗрдВ рдЬрд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдЖрдкрдХреЛ рдмрддрд╛рдКрдВрдЧрд╛ рдХрд┐ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреМрди рд╕реЗ рд╡рд┐рдХрд▓реНрдк рд╕рддрд╣ рдкрд░ рд╣реИрдВ рдФрд░ рдХреМрди рд╕рд╛ рд╡рд┐рдХрд▓реНрдк рд╣рдордиреЗ рдЕрдВрддрддрдГ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ред

рдХрд╛рд░реНрдп


рддреИрдпрд╛рд░ рдЪрд┐рддреНрд░, рд╢реАрд░реНрд╖рдХ рдФрд░ рдЙрдкрд╢реАрд░реНрд╖рдХ рдХреЗ рд░реВрдк рдореЗрдВ рддрддреНрд╡реЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдЕрдВрддрд╣реАрди рдЪрдХреНрд░реАрдп рд╕реНрдХреНрд░реЙрд▓ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рдерд╛ред рдЗрдирдкреБрдЯ: рдХреЗрдВрджреНрд░реАрдп рдЫрд╡рд┐ 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:

  • decelerationRate- рдпрд╣ рдкреИрд░рд╛рдореАрдЯрд░ рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рд╕реНрдХреНрд░реЙрд▓ рдПрдиреАрдореЗрд╢рди рдХрд┐рддрдиреА рддреЗрдЬреА рд╕реЗ рдзреАрдорд╛ рд╣реЛ рдЬрд╛рдПрдЧрд╛ред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпрд╣ рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рд╣реИ .fastред
  • showsHorizontalScrollIndicator - рдпрд╣ рдкреИрд░рд╛рдореАрдЯрд░ рдХреНрд╖реИрддрд┐рдЬ рд╕реНрдХреНрд░реЙрд▓рдмрд╛рд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд╝рд┐рдореНрдореЗрджрд╛рд░ рд╣реИ:

    private func setupScrollView() {
        self.scrollView.decelerationRate = .fast
        self.scrollView.showsHorizontalScrollIndicator = false
    }
    

рдореВрд▓ рд╕реЗрдЯрдЕрдк рдХреЗ рдмрд╛рдж, рд╣рдо рд▓реЗрдЖрдЙрдЯ рдФрд░ рдкреНрд▓реЗрд╕рдореЗрдВрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ 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), рдЗрд╕реЗ contentOffsety рдкрд░рд┐рд╡рд░реНрддрди рд╣реЛрдиреЗ рдкрд░ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ 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ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ rightItemView100.0 рдЕрдВрдХ рдкреВрд░реНрдг рдкреНрд░рджрд░реНрд╢рди рддрдХ рд╕реНрдХреНрд░реЙрд▓ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ , рддреЛ рд╣рдо contentOffsetрдПрдХ рдмреИрдирд░ рдХреА рдЪреМрдбрд╝рд╛рдИ рд╕реЗ, рдкреАрдЫреЗ рдХреА рдУрд░ рд╢рд┐рдлреНрдЯ рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВ, рдмреИрдирд░ (рд░рд┐рдХреНрддрд┐) рдХреЗ рдмреАрдЪ рдХреА рджреВрд░реА рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрддреЗ рд╣реБрдП, рддрд╛рдХрд┐ рдпрд╣ centerItemViewрдЬрдЧрд╣ рдореЗрдВ рд╣реЛ rightItemViewред рдЗрд╕реА рддрд░рд╣, рд╣рдо рдЗрд╕рдХреЗ рд▓рд┐рдП рдХрд░рддреЗ рд╣реИрдВ leftItemView: рд╣рдо рдЙрд╕ рдмрд┐рдВрджреБ рдХреА рдЧрдгрдирд╛ рдХрд░рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХреЗ рдЪреМрд░рд╛рд╣реЗ рдХреЗ рдмрд╛рдж рд╣рдо рдмрджрд▓ рдЬрд╛рдПрдВрдЧреЗ contentOffsetред


func set(imageURLs: [URL])рдмрд╛рд╣рд░ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рдХреЛ рдЙрдЬрд╛рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рдзрд┐ рдЬреЛрдбрд╝реЗрдВ ред рд╡рд╣рд╛рдВ рд╕реЗ рд╣рдо рдХреЛрдб рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ setupред

рдФрд░ рд╣рдо рдПрдХ рдкрдВрдХреНрддрд┐ рднреА рдЬреЛрдбрд╝реЗрдВрдЧреЗ рддрд╛рдХрд┐ рдЬрдм рдЖрдк рд╕рд╛рдордЧреНрд░реА рд╕реЗрдЯ рдХрд░реЗрдВ рддреЛ рд╡рд╣ centerItemViewрддреБрд░рдВрдд рдХреЗрдВрджреНрд░рд┐рдд рд╣реЛ рдЬрд╛рдПред horizontalItemOffsetFromSuperViewрд╣рдордиреЗ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИ layoutSubviews, рдЗрд╕рд▓рд┐рдП рд╣рдо рдЗрд╕реЗ рд╕реНрдерд┐рд░рд╛рдВрдХ рдореЗрдВ рд░рдЦрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рдлрд┐рд░ рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред

func set(imageURLs: [URL]) {
    //    ImageView
    let imageViews = [self.leftItemView, self.centerItemView, self.rightItemView]
    imageViews.enumerated().forEach { key, view in
        view.setImage(with: imageURLs[key])
    }
    //    ,  centerItemView   
    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 {
    //     3     
    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ред

рдПрдХ рдмрд╛рд░ рдлрд┐рд░, рд╣рдо рдЖрд╢реНрд╡рд╕реНрдд рдереЗ рдХрд┐ рд╕рдорд╛рдзрд╛рди рдЬреЛ рдкрд╣рд▓реЗ рджрд┐рдорд╛рдЧ рдореЗрдВ рдЖрддреЗ рд╣реИрдВ рдФрд░ рдЬреЛ рд╕рдорд╛рдзрд╛рди рдЖрдк рдЗрдВрдЯрд░рдиреЗрдЯ рдкрд░ рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рд╡реЗ рд╣рдореЗрд╢рд╛ рдЗрд╖реНрдЯрддрдо рдирд╣реАрдВ рд╣реЛрддреЗ рд╣реИрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдбрд░рддреЗ рдереЗ рдХрд┐ рд╕реНрдХреНрд░реЙрд▓рд┐рдВрдЧ рдХреЗ рджреМрд░рд╛рди рд╕рд╛рдордЧреНрд░реА рдХреЛ рдмрджрд▓рдиреЗ рд╕реЗ рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рд╣реЛрдЧреА, рд▓реЗрдХрд┐рди рд╕рдм рдХреБрдЫ рд╕реБрдЪрд╛рд░реВ рд░реВрдк рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рдЖрдкрдХреЛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рд╕рд╣реА рд╣реИ, рддреЛ рдЕрдкрдиреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдгреЛрдВ рдХреЛ рдЖрдЬрд╝рдорд╛рдиреЗ рд╕реЗ рдбрд░реЛ рдорддред рдЕрдкрдиреЗ рдЦреБрдж рдХреЗ рд╕рд┐рд░ рдХреЗ рд╕рд╛рде рд╕реЛрдЪреЛ :)ред

All Articles