{"id":17255665,"url":"https://github.com/billcarsonfr/scrollviewparallax","last_synced_at":"2025-04-14T05:31:56.644Z","repository":{"id":23519670,"uuid":"26885886","full_name":"BillCarsonFr/ScrollviewParallax","owner":"BillCarsonFr","description":"Illustration of Pete Share's post on domesticcat.com","archived":false,"fork":false,"pushed_at":"2014-11-20T14:29:57.000Z","size":4756,"stargazers_count":78,"open_issues_count":3,"forks_count":10,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-27T19:51:09.698Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BillCarsonFr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-11-19T23:02:44.000Z","updated_at":"2023-02-15T07:43:30.000Z","dependencies_parsed_at":"2022-07-07T18:48:29.485Z","dependency_job_id":null,"html_url":"https://github.com/BillCarsonFr/ScrollviewParallax","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BillCarsonFr%2FScrollviewParallax","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BillCarsonFr%2FScrollviewParallax/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BillCarsonFr%2FScrollviewParallax/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BillCarsonFr%2FScrollviewParallax/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BillCarsonFr","download_url":"https://codeload.github.com/BillCarsonFr/ScrollviewParallax/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248826707,"owners_count":21167730,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-15T07:12:17.464Z","updated_at":"2025-04-14T05:31:56.157Z","avatar_url":"https://github.com/BillCarsonFr.png","language":"Objective-C","funding_links":[],"categories":[],"sub_categories":[],"readme":"Scrollview Parallax/Zoom/Stretch\n================\n\nCreating parallax effect on UIScrollView only using Auto Layout.\nThis sample project is just an illustration of the article written by Pete Hare, that you can find here:\n\n[PETE SHARE's post on domesticcat.com](http://blog.domesticcat.com.au/ios/2014/03/19/creating-parallax-effect-on-uiscrollview-using-simple-constraints/)\n\nI saw in the comments that some people were asking for the code, so i think i could share this.\n\n![preview](capture.gif \"Preview\")\n\nI tried to do it first by only using IB (Interface Builder), i rarely use IB, i usually do these things programmatically.\nAnd i must say that i am really not confortable with it, i had to restart from scratch several times. That's why i decided to also do the same thing with code, you might have a look, i think it makes it more clear.\nIn the rest of the document i might also use visual format when i find it more easy to understand than screenshots of the IB.\n\n## Step by Step notes\n\nThere are some key points that you need to understand if you want to try to do this.\nI'd recommand you to first start by setting up the scrollview with the image view in top of the scrollcontent.\nOnce you have this working you can start to setup the cool effect.\n\n### Step 1 : Add the UIScrollview \n\nAdd 4 constraints between the scrollview and the parent view in order to make it full screen.\nIn my sample i am using the top layout guide to pin the view, but if you want something full screen (or transparency effect under navbar) you can attach to the top of the parent view.\n\n ![step1](docs/step1.png \"Step 1\")\n\n\n### Step 2 : Add the Content View\n\nIn this sample i am using a single child view to put all the scrollable content (notice that you can do differently).\n\nHere we are doing something very not intuitive for the content constraint.\nIn order to make the scroll work you must put also four '0' space constraints (top, bottom, left, right) between the scroll content and the scrollview.\n\n![step2](docs/contentView.gif \"Step 2\")\n\n### Step 3 : Setup the content\n\nNow let's add the imageView as a child of the content view.\n\nLet's set the constraints on the image view, we add again 4 constraints to the image, 0 top, 0 left, 0 right, and let's put the height to some arbritary size (150).\n\n![step3](docs/step3.gif \"Step 3\")\n\nAt this point you should have a lot of warning in IB, we will fix it later.\nIf you run you should see nothing, simply because a zero size view will respect all your constraint.\n\nSo let's now set the content size.\nIn the article Pete is giving a nice tip to set the width. We can just say that the width of the image should be equal to the with of the main controller view width (that is full screen :)\nIn order to do that, you have to Control-drag from the main view to the imageview in the Interface Builder outline view.\n\n\n![step3.1](docs/step3.1.gif \"Step 3.1\")\n\nLet's set the content height.\nYou have now to add any additional views to the content.\nAnd As stated in apple doc:\n\u003e You must make sure you create constraints for all the subviews inside a scroll view. For example, when defining the constraints for a view that doesn’t have an intrinsic content size, you’ll need more than just a leading edge \n\u003e constraint—you must also create trailing edge, width, and height constraints. \n\n\u003e *There cannot be any missing constraints, starting from one edge of the scroll view to the other.*\n\nIn visual format, it could be expressed like that:\n\n    V:|-0-[imageView(150)]-0-[subContentView(700)]-0-|\n    \n    |-0-[topImageView(==super)]-0-|\n\n    |-0-[subContentView]-0-|\n\n![step3.2](docs/step3.2.gif \"Fully define the content size\")\n\nIf your subviews have intrinsic height, you can remove the height constraint.\n\nIf you run now, you should have classic scrolling\n\n![step3.3](docs/step3.3.gif \"Classic scroll\")\n\n\n\n### Step 4 : Do the magic\n\nOk here is the interesting part.\nWhat we want to do is to remove the top constraint of the image view to the parent view (scrollcontent view), and instead attach to the topGuide, and also to remove the height constraint:\n\n    V:|-0-[imageView(150)]..   --- replaced By --\u003e   V:[topGuide]-0-[imageView]..\n\nBut by doing this we are violating the scroll content rule:\n\n\u003e *There cannot be any missing constraints, starting from one edge of the scroll view to the other.*\n\nBecause there is no more constraint starting from the top of the content view going to one of the subview (we broke the one going to the imageView).\n\nSo as explained by Pete Hare in the article, we have to replace this missing constraint with a new one:\n\n    V:|-0-[imageView(150)]-0-[subContentView(700)]-0-| --- replaced By --\u003e @\"V:|-150-[subContentView(700)]-0-|\"\n\nYou can find here an animated gif capture of this step, i don't know if it's really helpfull :), please let me know if you find it usefull.\n\n\n![step4](docs/step4.gif \"Final setup\")\n\n\nIf you try to run now, you will already have the cool effect.\nBut if you try to scroll down, at some point you will have an exception in the console:\n\n     Unable to simultaneously satisfy constraints.\n\nThis is simply because at some point, when the bottom of the imageView reach the top of the screen, the top constraint to the topGuide cannot be satisfied, it would mean that the imageHeight is negative.\n\nThe solution is to add an additional constraint to the top layout guide:\n   \n    V:[topGuide]-\u003c=0-[imageView]\n\n    in addition to\n\n    V:[topGuide]-0-[imageView]\n\nAnd as we want the image top to stick as long as possible to the top of the screen, but to break when necessary, we just need to lower the priority:\n\n    V:[topGuide]-=0@750-[imageView]\n\n(The default priority is 1000)\n\n\n![step4.1](docs/step4.1.gif \"Fix the statisfy error\")\n\n\nBut what happened to the image height?\n\nWe removed the height constraint, so it's not managed by a constraint. Instead of that the first time the view is rendered the image will take the space available between the top guide and the other view in the content. And starting from that the layout engine will use the Content Compression Resistance Priority to decide how to resize the image?. As by default the priority is 750, it seems to be OK but it's probably better to lower the priority to 749 (it depends on the exact effect you want to achieve).\n\n## Misc\n\nIf you have some issues with the scroll bar not going to the top (leaving a small gap), you may have to disable the 'Adjust Scroll View Insets' in the property view of the ViewController. \n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbillcarsonfr%2Fscrollviewparallax","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbillcarsonfr%2Fscrollviewparallax","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbillcarsonfr%2Fscrollviewparallax/lists"}