CrownControl is a tiny accessory that makes scrolling through scrollable content possible without lifting your thumb.

Overview

CrownControl

Platform Language Version codecov License

Overview

Inspired by Apple Watch Digital Crown, CrownControl is a tiny accessory view that makes scrolling through scrollable content possible without lifting your thumb.

Features

The crown consists of background and foreground surfaces. The foreground is an indicator which spins around the center as the attached scroll view offset changes.

  • Can be repositioned either using force touch or long press.
  • Can be spinned clockwise and counter clockwise.
  • Most of the user interaction actions are configurable.
  • The background and foreground sizes are configurable.
  • Can be fully stylized.

Example Project

The example project contains samples where each demonstrates the CrownControl usability in a scrollable context.

Web View / PDF Contacts Photo Collection
pdf_example contacts_example photos_example

Requirements

  • iOS 9 or any higher version.
  • Swift 4.2 or any higher version.
  • CrownControl leans heavily on QuickLayout - A lightwight library written in Swift that is used to easily layout views programmatically.

Installation

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:

$ gem install cocoapods

To integrate CrownControl into your Xcode project using CocoaPods, specify it in your Podfile:

source 'https://github.com/cocoapods/specs.git'
platform :ios, '9.0'
use_frameworks!

pod 'CrownControl', '1.0.0'

Then, run the following command:

$ pod install

Usage

Quick Usage

Using CrownControl is really simple.

In your view:

  1. Define and bind CrownAttributes to a scroll view instance, and optionally customize the attributes.
  2. Instantiate and bind the CrownControl instance to the CrownAttributes instance.
  3. Setup the CrownControl instance in a given superview using constraints to determine its position.
private var crownControl: CrownControl!
private var scrollView: UIScrollView!

private func setupCrownViewController() {
    let attributes = CrownAttributes(scrollView: scrollView, scrollAxis: .vertical)
    
    // Cling the bottom of the crown to the bottom of a view with -50 offset
    let verticalConstraint = CrownAttributes.AxisConstraint(crownEdge: .bottom, anchorView: scrollView, anchorViewEdge: .bottom, offset: -50)
    
    // Cling the trailing edge of the crown to the trailing edge of a view with -50 offset
    let horizontalConstraint = CrownAttributes.AxisConstraint(crownEdge: .trailing, anchorView: scrollView, anchorViewEdge: .trailing, offset: -50)

    // Setup the crown control within *self*
    crownControl = CrownControl(attributes: attributes, delegate: self)
    crownControl.layout(in: view, horizontalConstaint: horizontalConstraint, verticalConstraint: verticalConstraint)
}

To make the crown respond to scrolling events that emanates from any other invoker but the crown, add to scrollViewDidScroll(_:) the following:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    crownControl?.spinToMatchScrollViewOffset()
}

Crown Attributes

CrownAttributes is the crown appearance descriptor. Its nested properties describe the look and feel of the crown.

Scroll Axis

The axis of the scroll view is a .horizontal or .vertical. It must be set during CrownAttributes initialization.

Anchor Position

The anchor position of the foreground indicator. Indicates where the foreground is initially positioned.

attributes.anchorPosition = .left

The posssible values are .left, .right, .top, .bottom. The default value is .top.

Spin Direction

The direction to which the the indicator spins.

Example for setting the spin direction to be counter-clockwise.

attributes.spinDirection = .counterClockwise

The default value is clockwise.

User Interaction

Describes the user interaction with the crown. Currently supported user interaction gestures: tap, double tap, long-press, and force-touch events.

Tap Gestures

When a single tap event occurs, scroll forward with the specified offset value:

attributes.userInteraction.singleTap = .scrollsForwardWithOffset(value: 20, animated: true)

When a single tap event occurs, perform a custom action.

attributes.userInteraction.singleTap = .custom(action: {
    /* Do something */
})

When a double tap event occurs, scroll to the leading edge of the scroll view.

attributes.userInteraction.doubleTap = .scrollsToLeadingEdge
Drag and Drop

The crown can be dragged and dropped using force-touch if the force-touch trait is supported by the device hardware. If not, there is a fallback to long-press gesture.

attributes.repositionGesture = .prefersForceTouch(attributes: .init())

Style

The background and foreground surfaces can be customized with various styles.

Example for setting the crown background to a gradient style, and its border to a specific color and width.

attributes.backgroundStyle.content = .gradient(gradient: .init(colors: [.white, .gray], startPoint: .zero, endPoint: CGPoint(x: 1, y: 1)))
attributes.backgroundStyle.border = .value(color: .gray, width: 1)

Sizes

Describes the size of the crown and relations between the foreground and the background surfaces.

In the following example, setting scrollRelation property to 10 means that 10 full spins of the foreground would make the scroll view offset reach its trailing edge.

attributes.sizes.scrollRelation = 10

Example for setting the edge size (width and height) of the crown to 60pts, and the foreground edge ratio to 25 precent of that size, which is 15pts.

attributes.sizes.backgroundSurfaceDiameter = 60
attributes.sizes.foregroundSurfaceEdgeRatio = 0.25

Feedback

Feedback descriptor for the foreground when it reaches the anchor point on the crown surface.

The device generates impact-haptic-feedback when the scroll-view offset reaches the leading edge. The background surface of the crown flashes with color.

attributes.feedback.leading.impactHaptic = .light
attributes.feedback.leading.backgroundFlash = .active(color: .white, fadeDuration: 0.3)

Author

Daniel Huri, [email protected]

License

CrownControl is available under the MIT license. See the LICENSE file for more info.

You might also like...
Scrollable UINavigationBar that follows the scrolling of a UIScrollView
Scrollable UINavigationBar that follows the scrolling of a UIScrollView

A custom UINavigationController that enables the scrolling of the navigation bar alongside the scrolling of an observed content view Versioning notes

SDWebImageMockPlugin makes possible the creation of snapshot testing with views using SDWebImage to configure images
SDWebImageMockPlugin makes possible the creation of snapshot testing with views using SDWebImage to configure images

SDWebImageMockPlugin makes possible the creation of snapshot testing with views using SDWebImage to configure images.

Infinite paging controller, scrolling through contents and title bar scrolls with a delay
Infinite paging controller, scrolling through contents and title bar scrolls with a delay

PageController PageController is infinite paging controller, scrolling through contents and title bar scrolls with a delay. Then it provide user inter

Infinite paging controller, scrolling through contents and title bar scrolls with a delay
Infinite paging controller, scrolling through contents and title bar scrolls with a delay

PageController PageController is infinite paging controller, scrolling through contents and title bar scrolls with a delay. Then it provide user inter

πŸŽ€ A simple cross-platform toolbar/custom input accessory view library for iOS & macOS.
πŸŽ€ A simple cross-platform toolbar/custom input accessory view library for iOS & macOS.

Ribbon πŸŽ€ A simple cross-platform toolbar/custom input accessory view library for iOS & macOS. Written in Swift. Looking for... A type-safe, XPC-avail

The perfect accessory for Mantle and AFNetworking.

Overcoat We are finding maintainers, contact @sodastsai :) Overcoat is a small but powerful library that makes creating REST clients simple and fun. I

A tiny library makes uploading and downloading easier

Features uploading/downloading multiple files concurrently or sequentially grouping tasks with awesome custom operators (||| and --) supports backgro

πŸ’¬ A tiny extension for UIAlertController that makes working with it very simple. Only 150 lines of code.
πŸ’¬ A tiny extension for UIAlertController that makes working with it very simple. Only 150 lines of code.

AlertController πŸ’¬ A tiny extension for UIAlertController that makes working with it very simple. Only 150 lines of code. Alert let alert = UIAlertCon

XcodeJSONValidator - XcodeJSONValidator is your script to to check for possible wrongly formed JSON files
XcodeJSONValidator - XcodeJSONValidator is your script to to check for possible wrongly formed JSON files

XcodeJSONValidator XcodeJSONValidator is your script to to check for possible wr

🌐 Makes Internet connectivity detection more robust by detecting Wi-Fi networks without Internet access.
🌐 Makes Internet connectivity detection more robust by detecting Wi-Fi networks without Internet access.

Connectivity is a wrapper for Apple's Reachability providing a reliable measure of whether Internet connectivity is available where Reachability alone

Library that makes it easy to create multiple environments within a single app. You can switch environments without deleting the application.

AppContainer Library that makes it easy to create multiple environments within a single app. You can switch environments without deleting the applicat

Decodable Simple and strict, yet powerful object mapping made possible by Swift 2's error handling.

Decodable Simple and strict, yet powerful object mapping made possible by Swift 2's error handling. Greatly inspired by Argo, but without a bizillion

KeyPathKit is a library that provides the standard functions to manipulate data along with a call-syntax that relies on typed keypaths to make the call sites as short and clean as possible.

KeyPathKit Context Swift 4 has introduced a new type called KeyPath, with allows to access the properties of an object with a very nice syntax. For in

πŸ“±πŸ’¬πŸš¦ TinyConsole is a micro-console that can help you log and display information inside an iOS application, where having a connection to a development computer is not possible.
πŸ“±πŸ’¬πŸš¦ TinyConsole is a micro-console that can help you log and display information inside an iOS application, where having a connection to a development computer is not possible.

TinyConsole TinyConsole is a tiny log console to display information while using your iOS app and written in Swift. Usage Wrap your Main ViewControlle

Returns true for all possible feature flags within the Twitter Mac app!

twitterinject Returns true for all possible feature flags within the Twitter Mac app! On Apple platforms, the default feature flags are present within

KeyPathKit is a library that provides the standard functions to manipulate data along with a call-syntax that relies on typed keypaths to make the call sites as short and clean as possible.

KeyPathKit Context Swift 4 has introduced a new type called KeyPath, with allows to access the properties of an object with a very nice syntax. For in

Custom & highly configurable seek slider with sliding intervals, disabled state and every possible setting to tackle!
Custom & highly configurable seek slider with sliding intervals, disabled state and every possible setting to tackle!

iLabeledSeekSlider Custom & highly configurable seek slider with sliding intervals, disabled state and every possible setting to tackle! Minimum iOS v

I'm trying to make Flutter based Audio Unit Extensions possible.
I'm trying to make Flutter based Audio Unit Extensions possible.

Flutter AUv3 Audio Unit Error Demo Motivation We are the developers of Audanika, a professional MIDI Controller app written in Flutter. Many of our us

Tapper - simple app for iOS and iPadOS allows a user to tap a button as many times as possible in 20 seconds
Tapper - simple app for iOS and iPadOS allows a user to tap a button as many times as possible in 20 seconds

Tapper Table of Contents Description Screenshots Installation Usage Code Contact

Owner
Daniel Huri
@daniel-huri at @facebook. Ex @blockchain
Daniel Huri
ScrollingFollowView is a simple view which follows UIScrollView scrolling.

ScrollingFollowView ScrollingFollowView is a simple view which follows UIScrollView scrolling. ScrollingFollowView Sample Images SearchBarSample : Sea

Tanaka Kenji 186 Dec 21, 2022
Multi-tier UIScrollView nested scrolling solution. πŸ˜‹πŸ˜‹πŸ˜‹

Multi-tier UIScrollView nested scrolling solution. Snapshots Requirements iOS 9.0+ Xcode 10.0+ Swift 4.2+ Installation CocoaPods CocoaPods is a depend

Jiar 1.2k Dec 30, 2022
Simultaneously scrolling ScrollViews with SwiftUI support

SimultaneouslyScrollView Simultaneously scrolling ScrollViews with SwiftUI support Installation Swift Package Manager Usage SwiftUI support Example In

David Steinacher 8 Aug 19, 2022
A SwiftUI ScrollView Designed to imitate the App Store and Apple Music ScrollViews (with or without a Parallax Header)

FancyScrollView I spent a lot of time looking for a way to recreate the UI of the ScrollViews in Stock Apple Apps (i.e. App Store and Apple Music) ins

Mathias Quintero 696 Dec 30, 2022
AutoKeyboardScrollView is an UIScrollView subclass which makes showing and dismissing keyboard for UITextFields much easier. So called keyboard avoidance.

AutoKeyboardScrollView AutoKeyboardScrollView is a smart UIScrollView which can: Scroll to proper position and make sure the active textField is visib

HongHao Zhang 120 Jul 31, 2022
This is a control that helps you dramatically ease your infinite scroll processing.

InfiniteScrollControl Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements Installat

Minseok Kang 0 Nov 15, 2021
Add validations to your text fields, Group them together and navigate through them via keyboard's return button and accessory view.

TFManager Let's say you have multiple UITextFields to get data from users. You need to handle each field keyboard's return key and add an accessory vi

Hosein Abbaspour 16 Sep 29, 2022
Repository with base samples for playing HLS/DASH with CMAF video, across as many platforms as possible. Includes steps for encoding and packaging your own test content.

Video Everything Repository with minimal samples for playing HLS/DASH with CMAF video, across as many platforms as possible. Content and License All t

Alex Dodge 3 Jul 4, 2021
A few drop-in SwiftUI components for easily importing and thumb-nailing files

FilesUI A few drop-in SwiftUI components for easily importing and thumb-nailing files Usage 1. Import Files To import files you can use the FileImport

Brianna Zamora 3 Oct 19, 2022
Scrollable UINavigationBar that follows the scrolling of a UIScrollView

A custom UINavigationController that enables the scrolling of the navigation bar alongside the scrolling of an observed content view Versioning notes

Andrea Mazzini 6.1k Dec 24, 2022