How to add image with parallax effect above UITableView header and keep header sticky?

后端 未结 3 1490
旧时难觅i
旧时难觅i 2020-12-24 10:27

Here is an image that explains everything I want to do:

\"enter

My question is

相关标签:
3条回答
  • 2020-12-24 10:31

    You can add image view to the view like -

    let imageView = UIImageView()
    let lblName = UILabel()
    
    imageView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 300)
    imageView.image = UIImage.init(named: "poster")
    imageView.contentMode = .scaleAspectFill
    imageView.clipsToBounds = true
    view.addSubview(imageView)
    
    lblName.frame = CGRect(x: 20, y: 100, width: 200, height: 22)
    lblName.text = "Steve Jobs"
    lblName.textColor = UIColor.white
    lblName.font = UIFont.systemFont(ofSize: 26)
    lblName.clipsToBounds = true
    imageView.addSubview(lblName)
    

    After that in tableview delegate method you can add scrollviewDidScroll method like -

    let y = 300 - (scrollView.contentOffset.y + 300)
    let height = min(max(y, 60), 400)
    imageView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: height)
    lblName.frame = CGRect(x: 20, y: height - 30, width: 200, height: 22)
    

    I hope this will be helpful. Please correct me if I am wrong.

    0 讨论(0)
  • 2020-12-24 10:35

    Swift 5

    as of my requirement i have used https://github.com/maxep/MXParallaxHeader

    i explained you the things step by step

    you need to install the above mentioned third party library by using this pod command

    1.)
    
    pod "MXParallaxHeader"
    

    open up commannd manager(Terminal) go to your target folder and run this command:

    2.)
    
    pod install
    

    you need a parallax effect of your image view and stick the header on the top you need to create the custom .xib file to user as a parallax header.

    3.) 
    
    Add new file choose a (User Interface) View as a new template and name the 
    file. eg.. ParallaxView and tap on the create.
    

    you have created UIView now you need to add the Cocoa Touch Class file for your custom view.

    4.) 
    
    Add new file choose a (Cocoa Touch Class) View as a new template and name the file. eg.. ParallaxView and tap on the Next.
    

    now you have pair of class file with its custom UIView eg.(ParallaxView.xib & ParallaxView.swift)

    and according to my project requirement i need to add a pagemenu in the bottom of the parallaxheader so i use a another third party library named CAPSPageMenu

    5.)
    
    just visit this https://github.com/PageMenu/PageMenu/blob/master/Classes/CAPSPageMenu.swift and download the CAPSPageMenu.swift file and drag from your downloads and drop to your project destination folder.
    

    now we are ready to go for the code part.

    Goto your ViewController file and import the frame work

    6.)
    
    import MXParallaxHeader
    

    delegate methods

     7.)
    
     class MyParralax: UIViewController, MXScrollViewDelegate, CAPSPageMenuDelegate 
     {// Parant Controller Code }
    

    Define the class (MyParralax.swift) variables for the controllers (for page menu )and (MXParallaxHeader)like this

    var scrollView      : MXScrollView!
    let Parallax        = Bundle.main.loadNibNamed("ParallaxView", owner: nil, options: nil)?.first as? ParallaxView
    let controller1     : VC1 = VC1.instantiateFromStoryboard()
    let controller2     : VC2 = VC2.instantiateFromStoryboard()
    var controllerArray : [UIViewController] = []
    var pageMenu        : CAPSPageMenu?
    

    you have to create two view controller file as a child view controller of the pagemenu and storyboard too.these both controller.swift (VC1 & VC2) will look like this.

    import UIKit
    
    class VC1: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
           // child conroller 
        }
    
        class func instantiateFromStoryboard() -> VC1
        {
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            return storyboard.instantiateViewController(withIdentifier: "VC1") as! VC1
        }
    }
    

    put this three functions in your parent controller(MyParralax.swift)

    func setParallaxMenu(){
            self.scrollView = MXScrollView()
            self.scrollView.backgroundColor  = UIColor.green
            self.scrollView.delegate = self
            self.scrollView.parallaxHeader.view = Parallax // You can set the parallax header view from a nib.
            self.scrollView.parallaxHeader.height = 446.0 // desired hieght or hight of the xib file
            self.scrollView.parallaxHeader.mode = MXParallaxHeaderMode.fill
            self.scrollView.parallaxHeader.minimumHeight = UIApplication.shared.statusBarFrame.size.height + (self.navigationController?.navigationBar.frame.height)!
            let newFrame = CGRect(x: 0,y: UIApplication.shared.statusBarFrame.size.height + (self.navigationController?.navigationBar.frame.height)!, width: self.view.frame.size.width, height: self.view.frame.size.height - (UIApplication.shared.statusBarFrame.size.height + (self.navigationController?.navigationBar.frame.height)!)) // scrollview's frame calculation
            scrollView.frame = newFrame
            scrollView.contentSize = newFrame.size
            self.scrollView.delegate = self
            view.addSubview(scrollView)
            self.pagemenuSetup()
        }
    
    
    func pagemenuSetup()
        {
            controllerArray.removeAll()
            controllerArray.append(controller1)
            controllerArray.append(controller2)
    
            controller1.title = "ORANGE"
            controller2.title = "YELLOW"
    
    
            // Customize menu (Optional)
            let parameters: [CAPSPageMenuOption] = [
                .menuItemSeparatorWidth(4.3),
                .scrollMenuBackgroundColor(UIColor(red: 25.0/255.0, green: 26.0/255.0, blue: 36.0/255.0, alpha: 1.0)),
                .viewBackgroundColor(UIColor.clear),
                .selectionIndicatorColor(UIColor.white),
                .bottomMenuHairlineColor(UIColor.clear),
                .unselectedMenuItemLabelColor(UIColor(red: 255.0/255.0, green: 255.0/255.0, blue: 255.0/255.0, alpha: 0.5)),
                .menuItemFont(UIFont(name: "Helvetica", size: 16.0)!),
                .enableHorizontalBounce(false),
                .menuHeight(52.0),
                .menuMargin(0.0),
                .menuItemWidth(self.view.bounds.width/2),
                .selectionIndicatorHeight(15.0),
                .menuItemSeparatorPercentageHeight(0.1),
                .iconIndicator(true),
                .iconIndicatorView(self.getIndicatorView())
            ]
            // Initialize scroll menu
            var frame = view.frame
            scrollView.frame = frame
            scrollView.contentSize = frame.size
            let Height = self.view.frame.size.height - (UIApplication.shared.statusBarFrame.size.height + (self.navigationController?.navigationBar.frame.height)!)
            frame.size.height = Height
            self.pageMenu = CAPSPageMenu(viewControllers: controllerArray, frame: frame, pageMenuOptions: parameters)
            pageMenu!.delegate = self
            self.scrollView.addSubview(pageMenu!.view)
            view.addSubview(scrollView)
        }
    
    
    private func getIndicatorView()->UIView
        {
            let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width/2, height: 15.0))
            imgView.image = UIImage(named: "Indicator")
            imgView.contentMode = .scaleAspectFit
            return imgView
        }
    

    check this output.

    0 讨论(0)
  • 2020-12-24 10:44

    I have wondering how to achieve a parallax sticky header and I found this post that does the work.

    The post is in Swift 2 but I have recode it for swift 4.2

    CustomHeaderView

    import UIKit
    
    class CustomHeaderView: UIView {
    
        //MARK:- Variables
        //MARK: Constants
    
    
        //MARK: Variables
        var imageView:UIImageView!
        var colorView:UIView!
        var bgColor = UIColor(red: 235/255, green: 96/255, blue: 91/255, alpha: 1)
        var titleLabel = UILabel()
        var articleIcon:UIImageView!
    
    
    
        //MARK:- Constructor
        init(frame:CGRect, title: String) {
    
            self.titleLabel.text = title.uppercased()
            super.init(frame: frame)
    
            setUpView()
    
        }
    
        required init?(coder aDecoder: NSCoder) {
    
            fatalError("init(coder:) has not been implemented")
    
        }
    
    
    
        //MARK:- Private methods
        private func setUpView() {
            backgroundColor = UIColor.white
    
            imageView = UIImageView()
            imageView.translatesAutoresizingMaskIntoConstraints = false
            addSubview(imageView)
    
            colorView = UIView()
            colorView.translatesAutoresizingMaskIntoConstraints = false
            addSubview(colorView)
    
            let constraints:[NSLayoutConstraint] = [
                imageView.topAnchor.constraint(equalTo: self.topAnchor),
                imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
                imageView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
                imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
                colorView.topAnchor.constraint(equalTo: self.topAnchor),
                colorView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
                colorView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
                colorView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
            ]
            NSLayoutConstraint.activate(constraints)
    
    
            imageView.image = UIImage(named: "bg-header")
            imageView.contentMode = .scaleAspectFill
    
            colorView.backgroundColor = bgColor
            colorView.alpha = 0.6
    
            titleLabel.translatesAutoresizingMaskIntoConstraints = false
            self.addSubview(titleLabel)
            let titlesConstraints:[NSLayoutConstraint] = [
                titleLabel.centerXAnchor.constraint(equalTo: self.centerXAnchor),
                titleLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 28),
                ]
            NSLayoutConstraint.activate(titlesConstraints)
    
            titleLabel.font = UIFont.systemFont(ofSize: 15)
            titleLabel.textAlignment = .center
    
            articleIcon = UIImageView()
            articleIcon.translatesAutoresizingMaskIntoConstraints = false
            addSubview(articleIcon)
            let imageConstraints:[NSLayoutConstraint] = [
                articleIcon.centerXAnchor.constraint(equalTo: self.centerXAnchor),
                articleIcon.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 6),
                articleIcon.widthAnchor.constraint(equalToConstant: 40),
                articleIcon.heightAnchor.constraint(equalToConstant: 40)
            ]
    
            NSLayoutConstraint.activate(imageConstraints)
            articleIcon.image = UIImage(named: "article")
        }
    
    
        //MARK:- Public methods
        func decrementColorAlpha(offset: CGFloat) {
    
            if self.colorView.alpha <= 1 {
    
                let alphaOffset = (offset/500)/85
                self.colorView.alpha += alphaOffset
    
            }
        }
    
        func decrementArticleAlpha(offset: CGFloat) {
    
            if self.articleIcon.alpha >= 0 {
    
                let alphaOffset = max((offset - 65)/85.0, 0)
                self.articleIcon.alpha = alphaOffset
    
            }
    
        }
    
        func incrementColorAlpha(offset: CGFloat) {
    
            if self.colorView.alpha >= 0.6 {
    
                let alphaOffset = (offset/200)/85
                self.colorView.alpha -= alphaOffset
    
            }
    
        }
    
        func incrementArticleAlpha(offset: CGFloat) {
    
            if self.articleIcon.alpha <= 1 {
    
                let alphaOffset = max((offset - 65)/85, 0)
                self.articleIcon.alpha = alphaOffset
    
            }
    
        }
    
    }
    

    And then VieController

    import UIKit
    
    class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
        //MARK:- Variables
        //MARK: Constants
    
    
        //MARK: Variables
        var tableView:UITableView!
        var headerView:CustomHeaderView!
        var headerHeightConstraint:NSLayoutConstraint!
    
    
    
        //MARK: - Lifecycle methods
        override func viewDidLoad() {
            super.viewDidLoad()
    
            setUpHeader()
            setUpTableView()
    
        }
    
    
    
        //MARK: - Private methods
        private func setUpHeader() {
    
            headerView = CustomHeaderView(frame: CGRect.zero, title: "Articles")
            headerView.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(headerView)
    
            headerHeightConstraint = headerView.heightAnchor.constraint(equalToConstant: 150)
            headerHeightConstraint.isActive = true
    
            let constraints:[NSLayoutConstraint] = [
                headerView.topAnchor.constraint(equalTo: view.topAnchor),
                headerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                headerView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
            ]
    
            NSLayoutConstraint.activate(constraints)
    
        }
    
        private func setUpTableView() {
    
            tableView = UITableView()
            tableView.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(tableView)
    
            let constraints:[NSLayoutConstraint] = [
                tableView.topAnchor.constraint(equalTo: headerView.bottomAnchor),
                tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
                tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
            ]
    
            NSLayoutConstraint.activate(constraints)
            tableView.register(UITableViewCell.self,forCellReuseIdentifier: "cell")
    
            tableView.dataSource = self
            tableView.delegate = self
    
        }
    
        private func animateHeader() {
    
            self.headerHeightConstraint.constant = 150
            UIView.animate(withDuration: 0.4, delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5, options: [.curveEaseInOut], animations: {
                self.view.layoutIfNeeded()
            }, completion: nil)
    
        }
    
    
    
        //MARK: - UITableView implementation
        //MARK: UITableViewDataSource implementation
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 100
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell",   for: indexPath)
            cell.textLabel?.text = "Article \(indexPath.row)"
            return cell
    
        }
    
    
        //MARK: UITableViewDelegate implementation
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
    
            if scrollView.contentOffset.y < 0 {
    
                self.headerHeightConstraint.constant += abs(scrollView.contentOffset.y)
                headerView.incrementColorAlpha(offset: self.headerHeightConstraint.constant)
                headerView.incrementArticleAlpha(offset: self.headerHeightConstraint.constant)
    
            }
            else if scrollView.contentOffset.y > 0 && self.headerHeightConstraint.constant >= 65 {
    
                self.headerHeightConstraint.constant -= scrollView.contentOffset.y/100
                headerView.decrementColorAlpha(offset: scrollView.contentOffset.y)
                headerView.decrementArticleAlpha(offset: self.headerHeightConstraint.constant)
    
                if self.headerHeightConstraint.constant < 65 {
                    self.headerHeightConstraint.constant = 65
                }
    
            }
    
        }
    
        func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    
            if self.headerHeightConstraint.constant > 150 {
                animateHeader()
            }
    
        }
    
        func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    
            if self.headerHeightConstraint.constant > 150 {
                animateHeader()
            }
    
        }
    
    }
    

    Resulting to the video that shows the link provided. Next steps would add the safe area constraint and maybe add nib to the header but that it is completely up to you.

    0 讨论(0)
提交回复
热议问题