A Library that adds a sticky behavior to the SwiftUI
's ScrollView
, while triggering a smooth haptic feedback as you scroll through the views.
Requires iOS 14.0+
MagneticScroll currently can only be installed through the Swift Package Manager.
Swift Package Manager
Add the Package URL: |
|
As you scroll, when the ScrollView
's velocity is lesser than MagneticScrollView
's velocity, magnetic scroll automatically sticks to the predicted end location.
![regular](https://private-user-images.githubusercontent.com/69051988/282249792-a6105c9b-ea59-42aa-9091-b6a5097ae47d.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQzNTMxMjYsIm5iZiI6MTcyNDM1MjgyNiwicGF0aCI6Ii82OTA1MTk4OC8yODIyNDk3OTItYTYxMDVjOWItZWE1OS00MmFhLTkwOTEtYjZhNTA5N2FlNDdkLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODIyVDE4NTM0NlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTJkNGNhNmRlZDljYWM3MDcxOGJlNjg1NmE5MzQwYWZmMGJhNGQ0N2VmZmQ5YTg5ZDRmNzA4ZWRlZjc1M2U0YzAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.lIff_idSgrIUPVjknWjCRdeeoqkeApOb_UrA98U8J7Q)
![manual](https://private-user-images.githubusercontent.com/69051988/282249813-01df66a2-9d39-48f5-9e02-c0a1ec9266af.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQzNTMxMjYsIm5iZiI6MTcyNDM1MjgyNiwicGF0aCI6Ii82OTA1MTk4OC8yODIyNDk4MTMtMDFkZjY2YTItOWQzOS00OGY1LTllMDItYzBhMWVjOTI2NmFmLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODIyVDE4NTM0NlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTgxODllZjY3MmJiYzRjOGRlZTYxMGFhMzE4MTk2NzYxZjhmZjRkMmY4MDE3NjUwYWMwOGEyMjRhNjY5MDc2ZjkmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.9rtlT0ga76Dr2CnnyFEwb_Enj1I0eF5a7SUm9eBvtHY)
![mached](https://private-user-images.githubusercontent.com/69051988/282249819-f694f466-e17e-472f-a955-c0d762584fba.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQzNTMxMjYsIm5iZiI6MTcyNDM1MjgyNiwicGF0aCI6Ii82OTA1MTk4OC8yODIyNDk4MTktZjY5NGY0NjYtZTE3ZS00NzJmLWE5NTUtYzBkNzYyNTg0ZmJhLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODIyVDE4NTM0NlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTE0NjgwY2Y4MTg4ODI1OTk0NTkwNGE5NGQzOWU0MjYwMjEzMmYyMGIyMWI5YzY0ODgyYjlhYzY4ZjA4NTRkZjImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.m8k2LUEi311l3SQLfVK70ET-2a51QE6rie-RNt9V7jk)
If you set the velocityThreshold
to .infinity
, MagneticScroll becomes a carousel.
![carousel](https://private-user-images.githubusercontent.com/69051988/282290286-feadbb7b-817d-48cd-9a27-469c46b6aacd.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQzNTMxMjYsIm5iZiI6MTcyNDM1MjgyNiwicGF0aCI6Ii82OTA1MTk4OC8yODIyOTAyODYtZmVhZGJiN2ItODE3ZC00OGNkLTlhMjctNDY5YzQ2YjZhYWNkLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODIyVDE4NTM0NlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTI3OWVlZDliMWVhZTY3MWJiMThjNTI5N2Y2YmY3YjYyYzU4OTM1MDlkOTkzYzJiMTlkNzJjNDliMmU0MjAwNDkmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.41XKF7V4RzBmBE-LEB5RUnkOvBw5ndtJJ4yvMNb1wYg)
MagneticScroll is designed to operate with a view called Block
. For MagneticScroll to detect scroll changes, it requires your content to be wrapped within Block
elements.
import SwiftUI
import MagneticScroll
struct ContentView: View {
// If you were to set activeBlock to "second" or "first" manually, MagneticScroll would automatically scroll to the block with that id.
@State private var activeBlock = "first"
var body: some View {
MagneticScrollView(activeBlock: $activeBlock) { organizer in
Block(id: "first", height: 400, inActiveHeight: 300) { // All of these fields are optional, except the ID, but magnetic scroll works x5 better with constant heights.
Text("Hello World")
}
Block(id: "second", height: 400, inActiveHeight: 300) {
Text("Hello World")
}
}
}
}
Here are the methods available for configuring the behavior of MagneticScrollView
:
Sets whether the active block should be changed on a tap gesture.
Sets the velocity threshold for MagneticScrollView
to react to scroll view velocity.
Sets whether haptic feedback should be triggered when the active block changes.
Sets whether haptic feedback should be triggered when the active block changes.
Sets whether the form style should be enabled or not.
Sets the scroll animation duration when changing the active block.
Sets the timeout duration needed to change a block to another.
MagneticScrollView
gives an organizer to control the behavior of itself. Organizer contains a ScrollViewProxy
so if you want to control the ScrollView
itself, you can use that.
Activates a block with given ID. But doesn't scroll to it
Scrolls and activates a block with given id and anchor
Scrolls to the nearest block with the current offset of the MagneticScrollView
.