Overview

This document provides an overview of the SEssentialsPullToAction control. It describes the features of the control and its associated concepts, together with some step-by-step guides for achieving common tasks.

The SEssentialsPullToAction is used in conjunction with a UIScrollView allowing users to trigger an event (such as refreshing content) by pulling the scroll view down past a custom threshold. Whilst your users interact with the scroll view, the Pull to Action control will pass through various states, updating its appearance accordingly. You can specify the threshold at which the pulldown will trigger an event and you can also implement methods in the SEssentialsPullToActionDelegate to react to events. By default, the Pull to Action control will display a ‘status view’ hidden offscreen on top of the scroll view it tracking.

If you simply want to get up and running, follow the Quick Start Guide - Objective-C, or the Quick Start Guide - Swift. Alternatively, for a more detailed description of how the Pull to Action control works and the features it presents, head over to the ShinobiEssentials Pull to Action Control Overview. Finally, for guides that tackle specific usage scenarios, head on over to the ~!@[ShinobiEssentials](../../../Classes/ShinobiEssentials.html) Pull to Action How-to Guides@!~ Pull to Action How-to Guides).

The Pull to Action control has a complete set of Xamarin.iOS bindings, allowing you to make use of all of its features from within applications written in C#. In order to get up and running, follow the Quick Start Guide for Xamarin iOS.

Quick Start Guide - Objective-C

Introduction

The following guide will get you up-and-running with the SEssentialsPullToAction component as quickly as possible. In this guide, we will introduce you to the key features of the Pull to Action control, including initial project setup and adding items. You can follow along with the related code sample: PullToActionGettingStarted.xcodeproj.

Creating a Pull to Action Control

Start up Xcode and create a new project (File / New / Single View Application).

Within your newly created project, add a reference to the ShinobiEssentials framework. Instructions for doing this can be found in the first section of the EssentialsUserGuide.

Firstly, we want to import in the correct headers to work with the control. At the top of the ViewController, add

#import <ShinobiEssentials/ShinobiEssentials.h>

In the viewDidLoad method, create a UIScrollview to attach ourselves to.

- (void)viewDidLoad
{
     [super viewDidLoad];

     //Create a scrollview to attach ourselves to
     UIScrollView *scrollview = [[UIScrollView alloc] initWithFrame:self.view.bounds];
     [self.view addSubview:scrollview];

     //Force the scrollview to allow scrolling when contentSize < bounds
     scrollview.alwaysBounceVertical = YES;
}

In this example, we set alwaysBounceVertical to make sure that we can pull down the UIScrollView, even when the content of the scrollview is fully on-screen.

Add the Pull to Action control, and attach it to the scroll view with the initWithScrollView: method.

//Create the Pull to Action control, and attach to the scroll view
SEssentialsPullToAction *pullToAction = [[SEssentialsPullToAction alloc] initWithScrollView:scrollview];
[scrollview addSubview:pullToAction];

With this, we can pull the UIScrollView down, and see the control at work.

Adding a Delegate

However the Pull to Action control does not disappear at this point. This is because it is still waiting to be told that the triggered action has been completed. To make this work, we need to add ourselves as the delegate, and implement the pullToActionTriggeredAction: method.

@interface ViewController () SEssentialsPullToActionDelegate
...
@end

@implementation ViewController

- (void)viewDidLoad
{
    ...
    //Register for "actionTriggered" updates
    pullToAction.delegate = self;
}

-(void)pullToActionTriggeredAction:(SEssentialsPullToAction *)pullToAction
{
    //Put your custom action here

    //Tell the Pull to Action that we've finished our processing
    [pullToAction actionCompleted];
}

@end

Now when you pull the UIScrollView down, it will execute your action before calling actionCompleted, informing the Pull to Action that it can disappear.

If you got stuck at any point, take a look at our related code sample: PullToActionGettingStarted.xcodeproj.

Quick Start Guide - Swift

Introduction

The following guide will get you up-and-running with the SEssentialsPullToAction component as quickly as possible. In this guide, we will introduce you to the key features of the Pull to Action control, including initial project setup and adding items. You can follow along with the related code sample: PullToActionGettingStartedSwift.xcodeproj.

Setting up the project

Start up Xcode and create a new project (File / New / Single View Application).

Within your newly created project, add a reference to the ShinobiEssentials framework, and the bundle which contains its resources. Instructions for doing this can be found in the first section of the EssentialsUserGuide.

Linking to the bridging header file

In order for Xcode to use an Objective-C based framework in Swift, it needs to have a bridging header file. We have included a bridging header file in our framework. To link to it, you must open the build settings for the your new target, and search for the Objective-C Bridging Header setting. You must then provide the path to the ShinobiEssentials-Bridging-Header.h file, which is inside the Headers directory of the ShinobiEssentials.framework.

Setting the Swift project's bridging header file

In the screenshot above, the framework is three directories above the root of the project, hence it is set to

$(SRCROOT)/../../../ShinobiEssentials.framework/Headers/ShinobiEssentials-Bridging-Header.h

Note that this path will vary based on the location of the framework on your file system.

Adding a Pull to Action Control

In the viewDidLoad() method of ViewController.swift, create a UIScrollview to attach ourselves to.

override func viewDidLoad() {
    super.viewDidLoad()

    // Create a scrollview to attach ourselves to
    let scrollView = UIScrollView(frame: view.bounds)
    scrollView.alwaysBounceVertical = true // Force the scrollview to allow scrolling when contentSize < bounds
    view.addSubview(scrollView)
    ...

In this example, we set alwaysBounceVertical to make sure that we can pull down the UIScrollView, even when the content of the scrollview is fully on-screen.

Also add the Pull to Action control, and attach it to the scroll view using it’s scrollView: constructor.

let pullToAction = SEssentialsPullToAction(scrollView: scrollView)
scrollView.addSubview(pullToAction)

With this, we can pull the UIScrollView down, and see the control at work.

Adding a Delegate

Currently, the Pull to Action control does not disappear. This is because it is still waiting to be told that the triggered action has been completed. To make this work, we need to add ourselves as the delegate, and implement the pullToActionTriggeredAction: method. First, conform to the SEssentialsPullToActionDelegate protocol.

class ViewController: UIViewController, SEssentialsPullToActionDelegate {

Now we can tell the pullToAction control to use self as the delegate.

pullToAction.delegate = self

This allows us to receive a notification that the pullToAction control has triggered through the pullToActionTriggeredAction method. Add the following code to your pullToActionTriggered method:

func pullToActionTriggeredAction(pullToAction: SEssentialsPullToAction!) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
        // Simulate some "processing time" before executing the action
        NSThread.sleepForTimeInterval(3.0)
        dispatch_async(dispatch_get_main_queue(), {
            // Tell the Pull to Action that we've finished our processing
            pullToAction.actionCompleted()
        });
    });
}

Now when you pull the UIScrollView down, it will wait 3 seconds before calling actionCompleted, which will make the Pull to Action control disappear.

If you got stuck at any point, take a look at our related code sample: PullToActionGettingStartedSwift.xcodeproj.

Quick Start Guide for Xamarin.iOS

Xamarin.iOS: Introduction

The following guide will get you up-and-running with the SEssentialsPullToAction control using Xamarin.iOS as quickly as possible. In this guide, we will introduce you to the key features of the Pull to Action, including initial project setup and adding items. You can follow along with the related code sample: PullToActionGettingStarted.csproj.

Xamarin.iOS: Creating a Pull to Action Control

Start up Xamarin Studio and create a new project (File / New / Solution), selecting the option iOS / Universal / Single View Application.

Within your newly created project, add a reference to the ShinobiEssentials.dll. To do this, right click the References folder under your newly create project and choose ‘Edit References…’. Then select ‘.Net Assembly’ and browse to your ShinobiEssentials installation. The dll can be found within the Xamarin.iOS / lib folder. Be sure to click ‘Add’ after selecting the dll to add it to your project, and close the window.

To check that the dll is correctly referenced, expand the References folder and you should see the ShinobiEssentials.dll listed as a reference.

Firstly, we want to add a using directive to work with the Pull to Action. At the top of the ViewController, add

using ShinobiEssentials;

In the ViewDidLoad method, create a UIScrollview to attach the Pull to Action to.

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();

    // Create a scrollview to attach ourselves to
    UIScrollView scrollView = new UIScrollView (View.Bounds);
    View.AddSubview (scrollView);
    // Force the scrollview to allow scrolling when contentSize < bounds
    scrollView.AlwaysBounceVertical = true;
}

In this example, we set AlwaysBounceVertical to make sure that we can pull down the UIScrollView, even when the content of the scrollview is fully on-screen.

Still in the ViewDidLoad method, add the Pull to Action control, and attach it to the scrollview with the constructor.

// Create the Pull to Action control, and attach to the scrollview
SEssentialsPullToAction pullToAction = new SEssentialsPullToAction (scrollView);
scrollView.AddSubview(pullToAction);

With this, we can pull the UIScrollView down, and see the Pull to Action at work.

Xamarin.iOS: Adding a Delegate

However the Pull to Action does not disappear at this point. This is because it is still waiting to be told that the triggered action has been completed. To make this work, we need to add ourselves as the delegate, and implement the TriggeredAction method.

We do this using the new Protocol style recently introduced in Xamarin, to make the ViewController itself the delegate for the Pull to Action. You could equally implement this in the old style by sub-classing SEssentialsPullToActionDelegate. Note that the Export attribute is automatically added if you type the override keyword and choose the TriggeredAction method from the intellisense.

public partial class PullToActionGettingStartedViewController : UIViewController, ISEssentialsPullToActionDelegate
{
    public override void ViewDidLoad ()
    {
        ...
        // Register from "actionTriggered" updates
        pullToAction.Delegate = this;
    }

    [Export ("pullToActionTriggeredAction:")]
    public void TriggeredAction (SEssentialsPullToAction pullToAction)
    {
        // Tell the Pull to Action that we've finished our processing
        pullToAction.ActionCompleted ();
    }
}

Now when you pull the UIScrollView down, it will execute your action before calling ActionCompleted, informing the Pull to Action that it can disappear.

If you got stuck at any point, take a look at our related code sample: PullToActionGettingStarted.csproj.

Xamarin.iOS: Pull to Action and async

The Pull to Action control works well with the async features in C#.

Adding support is as simple as prepending the async keyword to the TriggeredAction method, and then adding an await call for some async task. In the below example, we simply do nothing for one second:

[Export ("pullToActionTriggeredAction:")]
async public void TriggeredAction (SEssentialsPullToAction pullToAction)
{
    // Simulate some "processing time" before executing the action
    await Task.Delay (1000);

    // Tell the Pull to Action that we've finished our processing
    pullToAction.ActionCompleted ();
}

ShinobiEssentials Pull to Action Control Overview

The SEssentialsPullToAction controls a UIView which can react to state changes of the scroll view it is observing.

The diagram above shows a fully extended Pull to Action control using a ‘slide out’ type effect where it’s status view is fixed in size and sticks to the top of the scroll view’s content (SEssentialsPullToActionStatusViewAlignmentBottom).

The Pull to Action control pictured above is using our default status view SEssentialsDefaultStatusView which contains a pullingIcon and a statusLabel. By default the pulling icon is a SEssentialsPullToActionArrow which is rotated by 180 degees when the scroll view it goes past the specified pullThreshold.

Further Details

Visualizer

The Pull to Action control itself is essentially a state machine that is responsible for tracking a scroll view and forwarding out events to its delegate. To handle visual changes, each Pull to Action control has a visualizer. The visualizer is informed about changes to the Pull to Action component, and is responsible for forwarding pulling / state change events to the status view, handling the positioning of the Pull to Action, handling size changes, as well as taking care of animation.

We provide two status view alignments, SEssentialsPullToActionStatusViewAlignmentStretch and SEssentialsPullToActionStatusViewAlignmentBottom. Under the hood, these provide two different visualizer implementations.

The SEssentialsPullToAction class has a property called visualizer allowing you to write and assign your own class that implements the SEssentialsPullToActionVisualizer protocol, customizing your Pull to Action to do pretty much whatever you like!

As a guide, you’ll want to implement the following methods on the SEssentialsPullToActionVisualizerProtocol:

  • -(void)pullToAction:(SEssentialsPullToAction*)pullToAction pulledAmountChanged:(CGFloat)pulledAmount;

    Here you can reposition and resize the Pull to Action component. If your status view has any visual effects (such as an arrow rotation) that change at different pull-down amounts you should notify your status view by calling its updateForPulledAmountChanged:pullThreshold: method.

  • -(void)layoutStatusView:(UIViewSEssentialsPullToActionStatusView *)statusView;

    This method is called by the Pull to Action component when a new status view is set. You can implement this method to position, set autoresizing masks, or any other initial setup that the status view may need.

  • -(void)pullToActionActionCompleted:(SEssentialsPullToAction *)pullToAction;

    This method is called by the Pull to Action component when an action has been completed. You can implement this method to perform any visual effects, such as animating back to the idle position.

Status View

Each Pull to Action control also has a status view. We provide the SEssentialsPullToActionDefaultStatusView as a default implementation. You can use this, subclass it, or create your own from scratch. To create your own status view, simply assign an UIView that implements the SEssentialsPullToActionStatusView to your Pull to Action’s statusView property.

As a guide, you’ll want to implement the following methods on the SEssentialsPullToActionStatusViewProtocol when creating your own status view:

  • -(void)updateForState:(SEssentialsPullToActionState)state;

    The update for state method is called by the visualizer whenever the Pull to Action component changes state. Use this opportunity to update your status view to reflect the new state.

  • -(void)updateForPulledAmountChanged:(CGFloat)pulledAmount pullThreshold:(CGFloat)pullThreshold;

    This method is called by the visualizer whenever the scroll view being observed is pulled. Use this opportunity to adjust anything visually that depends on the pulledAmount. An example would be to rotate an arrow partially as a user pulls downwards.

  • -(void)applyStyle:(SEssentialsPullToActionStyle *)style;

    This method is called by the Pull to Action component whenever the style is updated or a theme is applied. Use this opportunity to react to this style change.

The Delegate

The SEssentialsPullToAction uses a delegate as per the standard UIKit pattern, to notify your application when the user is interacting with the Pull to Action control. In order to react to the user interactions, you need to supply the Pull to Action with a class adopting the SEssentialsPullToActionDelegate protocol.

The methods on the delegate protocol follow these conventions;

  • will - delegate methods prefixed with ‘will’ are invoked just before the interaction is processed. These are not cancellable. You typically implement a ‘will’ method if you need to capture the state just before a change occurs.
  • did - delegate methods prefixed with ‘did’ are invoked after the interaction has been processed. When the ‘did’ method is invoked the PullToAction state will have changed to reflect the change due to the user interaction.

Styling

The SEssentialsPullToActionStyle defines the look and feel for an instance of the SEssentialsPullToAction class. If you wish to update how a Pull to Action looks, you should update its style object. The style object allows you to configure the following visual aspects of a Pull to Action control:

  • The color of the Pull to Action background.
  • The color, font, and text-color of the status view.
  • The color, border color and border width of the status view’s arrow.

Default style settings

SEssentialsPullToActionStyle derives from SEssentialsStyle, and so it is initialized with an SEssentialsTheme object. The theme provides the default settings for the style.

The following default settings are provided by the theme:

  • The activeTintColor on the theme is used for the background color of the Pull to Action.
  • The secondaryTintColor on the theme is used for the background of the status view.
  • The primaryFont on the theme is used for the status view’s status labels' font.
  • The primaryFontColor on the theme is used for the status view’s status labels' text color.
  • The inactiveTintColor on the theme is used for the status view`s arrow color.
  • The inactiveTintColor on the theme is used for the status view`s arrow border color.

ShinobiEssentials Pull to Action How-to Guides

How to create a Pull to Action with a custom Visualizer

The SEssentialsPullToAction is very flexible visually, allowing various different components to be switched in and out. The visualizer is responsible for a lot of the visual transitions, as well as layout of the statusView.

The SEssentialsPullToAction features two possible visualizer modes, which can be accessed through the constructor with the statusViewAlignment argument. SEssentialsPullToActionStatusViewAlignmentStretch will cause the status view to stretch or shrink to fill the available space when the UIScrollView the Pull to Action is attached to is scrolled. SEssentialsPullToActionStatusViewAlignmentBottom will keep the statusView at its initial size, and instead move it down as the Pull to Action grows and shrinks, keeping it aligned to the bottom edge of the Pull to Action.

For our example, we will create a new kind of visualizer, which keeps the statusView centered as the Pull to Action expands, but without changing its size. It may help to follow along with our related code sample: PullToActionHowToCustomizeVisualizer.xcodeproj.

We first create a class adopting the SEssentialsPullToActionVisualizer protocol.

#import <Foundation/Foundation.h>
#import <ShinobiEssentials/ShinobiEssentials.h>

@interface CustomVisualizer : NSObjectSEssentialsPullToActionVisualizer
@end

There are 5 methods we need to implement on this class:

  • pullToActionTriggeredAction:
  • pullToActionActionCompleted:
  • pullToAction:didChangeFromState:toState:
  • pullToAction:pulledAmountChanged:
  • pullToAction:layoutStatusView:

For pullToActionTriggeredAction: and pullToActionActionCompleted:, these methods give us time to animate to the new state before the action begins executing, and after the action finishes executing.

-(void)pullToActionTriggeredAction:(SEssentialsPullToAction *)pullToAction
{
    //Do any animation to begin action execution here

    //Tell our pullToAction that we are ready to execute the action
    [pullToAction executeAction];
}

-(void)pullToActionActionCompleted:(SEssentialsPullToAction *)pullToAction
{
    //Do any animation to finish action execution here

    //Tell our pullToAction that our completion animation has finished, and that we can reset to the idle state.
    [pullToAction resetToIdle];
}

If we were using the UIView animation methods (such as animateWithDuration:animations:completion:), then we would call executeAction in the completion block of pullToActionTriggeredAction:, and resetToIdle in the completion block of pullToActionActionCompleted:. For this sample, we will keep it simple and just call the “completion” methods.

Next, pullToAction:didChangeFromState:toState: is used to update the visuals of the Pull to Action on a state transition. After rendering our own visual changes, we need to tell the statusView to do the same.

-(void)pullToAction:(SEssentialsPullToAction *)pullToAction didChangeFromState:(SEssentialsPullToActionState)oldState toState:(SEssentialsPullToActionState)newState
{
    //Render any state transitions here

    //Tell the statusView to update its appearance for the new state.
    if ([pullToAction.statusView respondsToSelector:@selector(updateForState:)])
        [pullToAction.statusView updateForState:newState];
}

Because the statusView methods are optional, we need to wrap the call in a respondsToSelector: if-block. The default implementation of statusView implements all of the methods on the API, but if you use a custom statusView, you will either need to do the same, or use respondsToSelector: too.

The pullToAction:pulledAmountChanged: allows us to update more frequently during a gesture, rather than just on a state change. For example, if you have a progress bar telling the user how close they are to the pullThreshold.

It is also here that we update the size of the Pull to Action, to make it take up all of the space above the UIScrollView.

-(void)pullToAction:(SEssentialsPullToAction *)pullToAction pulledAmountChanged:(CGFloat)pulledAmount
{
    //Adjust the Pull to Action control to take up the entire content offset above the scrollview
    CGRect frame = pullToAction.frame;
    frame.size.height = pulledAmount;
    frame.origin.y = -pulledAmount;
    pullToAction.frame = frame;

    //Tell the statusView to update its appearance for the new pulledAmount
    if ([pullToAction.statusView respondsToSelector:@selector(updateForPulledAmountChanged:pullThreshold:)])
        [pullToAction.statusView updateForPulledAmountChanged:pulledAmount pullThreshold:pullToAction.pullThreshold];
}

Again, the updateForPulledAmountChanged:pullThreshold: method is an optional method which needs to be called when our own visualization updates have finished, so either needs to be implemented on the statusView, or checked with respondsToSelector:.

The final method, pullToAction:layoutStatusView:, is where the real meat of the visualizer is implemented. It is only called when the statusView or visualizer is changed, so it is recommended to use the autoresizingMask here to keep the statusView in the correct position. For our example, we keep it centered.

-(void)pullToAction:(SEssentialsPullToAction *)pullToAction layoutStatusView:(UIViewSEssentialsPullToActionStatusView *)statusView
{
    statusView.center = pullToAction.center;
    statusView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
}

With these five methods, you can customize how the Pull to Action looks as the user interacts with it. If you got stuck at any point, take a look at our related code sample: PullToActionHowToCustomizeVisualizer.xcodeproj.

How to create a Pull to Action with a custom Status view

The SEssentialsPullToAction is very flexible visually, allowing various different components to be switched in and out. The statusView, by default, displays some text, arrows, and a loading indicator when the Pull to Action is in different states. For different behaviour, it can be very easy to make it look however you need it to look.

At the most basic level, you can use the textForStates property of the SEssentialsPullToActionDefaultStatusView to change the text displayed for different states. For example, to change the text, we could set:

SEssentialsPullToActionDefaultStatusView *defaultStatusView = pullToAction.statusView;
defaultStatusView.textForStates = @{
    @(SEssentialsPullToActionStateIdle) : @"Idle"
    @(SEssentialsPullToActionStatePulling) : @"Pulling"
    @(SEssentialsPullToActionStateRetracting) : @"Retracting"
    @(SEssentialsPullToActionStateTriggered) : @"Triggered"
    @(SEssentialsPullToActionStateExecuting) : @"Executing"};

For this how-to guide though, we will be looking more in-depth at how to customize the Status view. It may help to follow along with our related code sample: PullToActionHowToCustomizeStatusView.xcodeproj.

After setting up the Pull to Action in the same way that we did in the Quickstart Guide, create a Custom Status view class, as a UIView adopting the SEssentialsPullToActionStatusView protocol.

#import <UIKit/UIKit.h>
#import <ShinobiEssentials/ShinobiEssentials.h>

@interface CustomStatusView : UILabel < SEssentialsPullToActionStatusView >

@end

Our Status view will change colour as the state changes, using the updateForState: method. In “Pulling” mode it will be red, then change to green when it crosses the pullThreshold and becomes “Triggered”. When the gesture finishes, it will begin “Executing” and become grey, before “Retracting” with a purple background and returning to “Idle”.

@implementation CustomStatusView

-(void)updateForState:(SEssentialsPullToActionState)state
{
    //Change the appearance of the statusView, depending on the state.
    switch (state)
    {
        case SEssentialsPullToActionStateIdle:
            self.backgroundColor = [UIColor whiteColor];
            break;

        case SEssentialsPullToActionStatePulling:
            self.backgroundColor = [UIColor redColor];
            break;

        case SEssentialsPullToActionStateTriggered:
            self.backgroundColor = [UIColor greenColor];
            break;

        case SEssentialsPullToActionStateExecuting:
            self.backgroundColor = [UIColor lightGrayColor];
            break;

        case SEssentialsPullToActionStateRetracting:
            self.backgroundColor = [UIColor purpleColor];
    }
}

@end

Simple enough! You should have something like the example below:

However sometimes, you need to show a change whenever the user drags. For this, we can use the updateForPulledAmountChanged:pullThreshold: method. In our example, we will just display how far the user has pulled the scrollview down.

-(void)updateForPulledAmountChanged:(CGFloat)pulledAmount pullThreshold:(CGFloat)pullThreshold
{
    self.text = [NSString stringWithFormat:@"Pulled by %.f points", pulledAmount];
}

Now you have a Status view which will change state, as well as reacting to the user gestures.

If you got stuck at any point, take a look at our related code sample: PullToActionHowToCustomizeStatusView.xcodeproj.