spro / TwitterProfileClone

Swift clone of Twitter's iOS profile view with a stretchy header
44 stars 6 forks source link

Passing touches to ProfileViewController #1

Closed acegreen closed 8 years ago

acegreen commented 8 years ago

Hey,

I'm using a similar implementation for my profile UI. But in my ViewController I have a segmentedControl that floats. This all works except my touches aren't registered.

Did you try adding more than a UIImageView to the ViewController. For example a segmentedControl like Twitter UI has it?

spro commented 8 years ago

What I'd do is add another view to the containing ViewController and manage its position similarly to the header view. I've just commited an example implementation here: https://github.com/spro/TwitterProfileClone/commit/7be1abd7d78c8ea769a18392464765f0982f56c4

acegreen commented 8 years ago

Ahh got it!! Oh how I hate wasting time on such small things. so my scrolling was like this, which was making my control unclickable (for some weird reason)

        if offset < 0 {
            print(offset)

            var headerTransform = CATransform3DIdentity
            headerTransform = CATransform3DTranslate(headerTransform, 0, -offset, 0)
            segmentedControl.layer.transform = headerTransform

        } else {
            var headerTransform = CATransform3DIdentity
            headerTransform = CATransform3DTranslate(headerTransform, 0, max(-differenceToView, -offset), 0)
            segmentedControl.layer.transform = headerTransform
        }

when all I needed was

        var segmentedControlTransform = CATransform3DIdentity
        segmentedControlTransform = CATransform3DTranslate(segmentedControlTransform, 0, max(-differenceToView, -offset), 0)
        segmentedControl.layer.transform = segmentedControlTransform

PS You can change your code to this

    override func viewDidLoad() {
        super.viewDidLoad()
        UIApplication.sharedApplication().statusBarStyle = .LightContent
        headerView.layer.zPosition = 1
        containerView.layer.zPosition = 2
        barView.layer.zPosition = 3
    }

    func subScrollViewDidScroll(scrollView: UIScrollView) {
        let offset = scrollView.contentOffset.y

        if offset < 0 {
            var headerTransform = CATransform3DIdentity
            let headerScaleFactor:CGFloat = -(offset) / headerView.bounds.height
            let headerSizevariation = ((headerView.bounds.height * (1.0 + headerScaleFactor)) - headerView.bounds.height)/2.0
            headerTransform = CATransform3DTranslate(headerTransform, 0, headerSizevariation, 0)
            headerTransform = CATransform3DScale(headerTransform, 1.0 + headerScaleFactor, 1.0 + headerScaleFactor, 0)
            headerView.layer.transform = headerTransform
        } else {
            var headerTransform = CATransform3DIdentity
            headerTransform = CATransform3DTranslate(headerTransform, 0, max(-(headerView.bounds.height-min_header), -offset), 0)
            headerView.layer.transform = headerTransform
        }

        if (headerView.bounds.height-min_header) < offset {
            headerView.layer.zPosition = 3
        } else {
            headerView.layer.zPosition = 0
        }

        var barTransform = CATransform3DIdentity
        barTransform = CATransform3DTranslate(barTransform, 0, max(-(headerView.bounds.height-min_header+bar_offset), -offset), 0)
        barView.layer.transform = barTransform
    }
spro commented 8 years ago

Nice, glad you figured it out. The extra barView zPosition logic was just to avoid the slight visual issue of the bar overlapping the scrollbar.

acegreen commented 8 years ago

A side question. Did you ever try to segue to ViewController and in the prepareForSegue tap into the ProfileViewController (specifically set a property there) ?

spro commented 8 years ago

I haven't... maybe it could work by saving the ProfileViewController as a property on the ViewController within the ViewController's prepareForSegue? I'm not sure of the order of an embedded prepareForSegue.

acegreen commented 8 years ago

Not sure I follow. I'm trying to set a user property in ProfileViewController from outside. So as I performSegue to ViewController I want o set the user so that ProfileViewController can deal with it. The problem is I can't tap into ViewController's container view's child?

spro commented 8 years ago

Just tried it, and yeah you can't get at the container view child until the ViewController is fully initialized. A workaround might be to first set a property on the ViewController from the OtherViewController's prepareForSegue, then copy it over to the ProfileViewController in the ViewController's prepareForSegue (ugly but effective).

acegreen commented 8 years ago

Yea pretty ugly. how did you get container view child when it was fully initialized? through ViewController's prepareForSegue ?

acegreen commented 8 years ago

I wonder how twitter and the rest do it. I mean they must have a similar setup and need to set/pass a user their ProfileViewController.

spro commented 8 years ago

I'm starting to think the ugly way is the right way. If you're doing custom header images, or showing other sub-views, the containing ViewController will need a reference to the user anyway. So the ViewController.user can be set in the OtherViewController.prepareForSegue, and ProfileViewController.user in ViewController.prepareForSegue.

acegreen commented 8 years ago

Yea for now, I guess that will do. This container approach is the only way to do all this i guess. I mean we could have put it in UITableViewHeader and implement the functions to make it sticky, but then everything would be sticky. (Just thinking out loud)

acegreen commented 8 years ago

There is a glitch with floating segmentedControl when you

self.tableView.insertRowsAtIndexPaths(newIndexPaths, withRowAnimation: .None)

That seems to call scrollViewDidScroll which calls out delegate.

spro commented 8 years ago

Interesting... can you add as another issue with a little more info?