opensource

Dejal Open Source

Like anything else, source code can get a bit untidy and crusty after a while. My Cocoa code is about a decade old now, so it's been well overdue for a cleanup. I have just completed a process of reorganizing all of the source code for future Lion and iOS 5 editions of Dejal projects.

One of the changes was to rename the open source and shared code to use a "Dejal" prefix rather than "DS" as before. Although I could have left the old prefix, the new one fits better with Apple's naming guidelines: they reserve all two-letter prefixes for themselves.

I also rearranged the code. I used to have separate Subversion repositories for iOS and Mac projects. Now I have code for iOS, Mac and cross-platform mixed in a repository, since there is a lot of code that works on both platforms.

Another big change was to move the open source projects from Subversion to Git. I've long resisted Git, but it really seems the most popular version control system for open source projects. And GitHub is a very nice way to share Git projects, with handy online viewing of documentation and source code, plus useful additions like issue tracking.

So now my open source projects are hosted on GitHub. You can view my GitHub page. Initially I have two iOS projects there: the small DejalView (formerly DSView) project, plus the very popular DejalActivityView (formerly DSActivityView) project. I will add more over time.

These projects have been updated for iOS 5 and ARC, plus general code improvements. They also have new README and license files. They use a standard BSD license.

I also took this opportunity to redesign the Dejal Developer page. The design was inspired by Matt Gemmell's excellent open source page (I got his permission to copy his design, but it ended up somewhat different).

Take a look at the new pages:

  • Dejal Open Source: the main Developer page, with general information at the top, followed by information on each project (with more to come).
  • Dejal Open Source License: a summary of my intention with the license for the source code, suggested attribution format, and the legal text.
  • Developer Store: enables you to donate in appreciation for the open source, or buy non-attribution licenses.

This last is interesting — the open source is available completely free, provided that you give Dejal credit in your app's About view, documentation, or website. If the code helps you, it's often nice to give something back, so now you can express appreciation via a donation or (just for fun, also inspired by Matt) a gift from my Amazon.com Wish List. But if you can't or don't want to give credit, you can purchase licenses that allow you to use the code without having to give credit. Hopefully that'll cover everyone's needs, but if you have some other requirement, let me know.

I hope you find my open source code useful. Keep an eye out for future additions; I have a Mac project coming soon (a feature that will appear in Time Out 2).

You can follow @dejalopen on Twitter to get notifications of updates, or follow @dejal for general Dejal news. You can also subscribe to the RSS feed of the Dejal Blog filtered for Open Source topics.

DejalActivityView: open source iOS project to display an activity indicator with adjustable text

Note: this is an updated post based on an older one, due to renaming the project (was "DSActivityView") and moving it from Subversion to GitHub.

DejalActivityViewI wrote a reusable class for a couple of iOS apps I was working on, called DejalActivityView. I decided to release it as open source. It has proven quite popular with others, too. Read on for details (including a demo movie).

Firstly, I should say that this work was inspired in part by Matt Gallagher's excellent article, Showing a "Loading..." message over the iPhone keyboard. My code only uses the -keyboardView method from his article, but he deserves credit and thanks for that and many other helpful articles. If you're not reading his blog, Cocoa with Love, you're doing yourself a disservice.

Back to my class. Actually, there are four classes: DejalActivityView, DejalWhiteActivityView, DejalBezelActivityView, and DejalKeyboardActivityView. They provide four styles of activity view, and could easily be extended to support more.

DejalActivityView

DejalActivityViewThis does a simple horizontal-style loading view, intended for situations where you have a blank view while loading data. It can be displayed very easily — for the default "Loading..." label text, simply use:

[DejalActivityView activityViewForView:self.view];

The activity view is automatically added as a subview of the specified view (e.g. the current content view). No need to save the result to an ivar. It automatically supports rotation to any orientation, too.

You can specify a custom label via:

[DejalActivityView activityViewForView:self.view withLabel:@"Processing..."];

Or specify a custom width, e.g. so you can change the label while it is being displayed without upsetting the geometry, via:

[DejalActivityView activityViewForView:self.view withLabel:@"Connecting..." width:100];

You can also have it manage the network activity indicator in the status bar, via a showNetworkActivityIndicator boolean property. It is NO by default, but if set to YES the network activity indicator in the status bar will be displayed, and automatically hidden when the DejalActivityView is removed. For example:

[DejalActivityView activityViewForView:self.view].showNetworkActivityIndicator = YES;

You can also toggle it on an already-visible activity view:

[DejalActivityView currentActivityView].showNetworkActivityIndicator = YES;

When you're done with the activity view, simply invoke this to get rid of it:

[DejalActivityView removeView];

DejalWhiteActivityView

This is the same as DejalActivityView, but with a white indicator and text instead of black, for use in dark views.

DejalBezelActivityView

DejalBezelActivityViewThis is a subclass of DejalActivityView, which displays an animated round-rect-enclosed variation: it animates into view by zooming from full-screen, with a gray background fading in to cover the passed view, and animates out by zooming to half size and fading out the background (see below for a movie showing it in action). It is ideal for situations where you have content visible already, but want to do a network operation to validate or send data, or some other time-consuming activity.

Display it the same way as DejalActivityView:

[DejalBezelActivityView activityViewForView:self.view];

The [DejalBezelActivityView activityViewForView:withLabel:] and [DejalBezelActivityView activityViewForView:withLabel:width:] variations are also available.

You can also split the label over multiple lines, thanks to a change contributed by Suleman Sidat. Thank you! Simply include one or more \n sequences in the label text, e.g.

[DejalBezelActivityView activityViewForView:self.view withLabel:@"Split over\nMultiple lines..."]

Similarly, to display an activity view with just the activity indicator, and no label, simply specify a blank label:

[DejalBezelActivityView activityViewForView:self.view withLabel:@""]

To remove with animation, call:

[DejalBezelActivityView removeViewAnimated:YES];

DejalKeyboardActivityView

DejalKeyboardActivityViewThis is a subclass of DejalBezelActivityView, which displays over the keyboard, somewhat like the iOS 2 Text app used to do. It is useful to simply prevent further typing while validating a field or sending data (though you might also want to disable the field, to prevent pasteboard operations on it). No need to specify a view to use for this, since it uses the keyboard. (This class may be removed in the future, since it isn't that useful nowadays; let me know if you need it.)

[DejalKeyboardActivityView activityView];

Plus a [DejalKeyboardActivityView activityViewWithLabel:] variation for custom text. Remove it the same as for the bezel style:

[DejalKeyboardActivityView removeViewAnimated:YES];

Demo

I've included a demo project that builds an app to show the various options: the four styles, default or custom label text, covering just the content view or whole window, etc. It requires iOS 5. Here's a movie of an earlier version of the demo, showing the demo app running (this project used to be called "DSActivityView"):

You can get the code and more information from the Dejal Open Source page.

DejalView: open source project for iOS to detect a tap outside a button

Note: this is an updated post based on an older one, due to renaming the project (was "DSView") and moving it from Subversion to GitHub.

In Tweeps I have a button that I wanted to behave like the Delete button in a table view. You know, when you tap the delete toggle to the left of a cell, a red Delete button appears. And tapping anywhere other than that button will hide it without doing anything else:

Table Delete button
(Contacts app)

I couldn't see any obvious way to do it, so asked on the iPhone Developer forums, and got a helpful reply suggesting a UIWindow subclass, overriding -sendEvent:.

I tried implementing that, but what I really wanted was to override -hitTest:withEvent:, since I wanted to block taps on views other than a specific button, and the documentation says one should always invoke the superclass of -sendEvent:.

Then I noticed that -hitTest:withEvent: is actually defined in UIView, and further experimenting with the table Delete feature showed that it appears to be implemented UITableView, since the cancel tap behavior only occurs in the table, not the navigation bar or toolbar. Besides, implementing in a UIView subclass is more focal, so a better choice.

So here is my UIView subclass to do this. It uses a delegate approach, with a protocol to declare the method:

@class DejalView;

@protocol DejalViewDelegate <NSObject>
@optional

- (UIView *)view:(DejalView *)view hitTest:(CGPoint)point withEvent:(UIEvent *)event hitView:(UIView *)hitView;

@end

And the actual subclass interface:

@interface DejalView : UIView

@property (nonatomic, weak) id <DejalViewDelegate> viewDelegate;

@end

With the implementation just overriding the hit test method. It simply invokes the superclass then gives the delegate a chance to change it (or perform some other action) if it implements the delegate protocol method:

#import "DejalView.h"


@implementation DejalView

@synthesize viewDelegate = dejalViewDelegate;

/*
  hitTest:withEvent:
 
  Overrides this method to add support for the -view:hitTest:withEvent:hitView view delegate behavior.
 
  Written by DJS 2009-09.
*/

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
{
    UIView *hitView = [super hitTest:point withEvent:event];
   
    if ([self.viewDelegate respondsToSelector:@selector(view:hitTest:withEvent:hitView:)])
        return [self.viewDelegate view:self hitTest:point withEvent:event
            hitView:hitView];
    else
        return hitView;
}

@end

To use this, simply change a container UIView to DejalView in the view hierarchy, then set the delegate property to your view controller (via code or IB):

self.view.viewDelegate = self;

Then implement the -view:hitTest:withEvent:hitView: delegate method in your view controller, e.g. as follows — this will cause a tap on some special control (or if that control is hidden) to go through as normal, but tapping anywhere else in the view will hide the special control, without passing the tap on to whatever was actually tapped:

- (UIView *)view:(DSView *)view hitTest:(CGPoint)point
        withEvent:(UIEvent *)event hitView:(UIView *)hitView;
{
    if (someSpecialControl.hidden || hitView == someSpecialControl)
        return hitView;
   
    someSpecialControl.hidden = YES;
   
    return nil;
}

I hope this is useful to someone else too.

You can get the code and more information from the Dejal Open Source page.

DSActivityView updated to support multiple label lines, and demo of no label

This blog post has been replaced by a newer edition.

Please see blog posts on DejalActivityView.

DSActivityViewI've committed a minor update to the DSActivityView open source project for iOS. See the DSActivityView introductory post for more information, including a video demo.

This update adds support for splitting the label over multiple lines for the DSBezelActivityView variation. This change was contributed by Suleman Sidat. Thank you!

To use multiple lines for the label, simply include one or more \n sequences in the label text, e.g.


[DSBezelActivityView newActivityViewForView:self.view withLabel:@"Split over\nMultiple lines..."]

Similarly, to display an activity view with just the activity indicator, and no label, simply specify a blank label:


[DSBezelActivityView newActivityViewForView:self.view withLabel:@""]

DSActivityView is compatible with iOS 3.0 and later, including iOS 4 (and I believe iOS 5), on iPad, iPhone and iPod touch.

You can get the project from my Dejal Open Source Subversion repository via this Terminal command:


svn checkout http://dejal.svn.beanstalkapp.com/open/DSActivityView

Or browse the source directly on the web.

If you make any enhancements to DSActivityView, please contribute them back to me so I can share with other developers.

DSActivityView updated for iOS 4

This blog post has been replaced by a newer edition.

Please see blog posts on DejalActivityView.

DSActivityViewI've committed a minor update to the DSActivityView open source project for iOS. See the DSActivityView introductory post for more information, including a video demo.

This update adds a new prefix to the class methods to create the activity view, to make it more clear that they return a retained object, rather than autoreleased.

So you'd now display the activity view via something like this:


[DSActivityView newActivityViewForView:self.view]

This update also includes a bug fix for iOS 4, where the activity view would appear behind the keyboard.

It is compatible with iOS 3.0 and later, including iOS 4, on iPad, iPhone and iPod touch.

You can get the project from my Dejal Open Source Subversion repository via this Terminal command:


svn checkout http://dejal.svn.beanstalkapp.com/open/DSActivityView

Or browse the source directly on the web.

A fork of DSActivityView: WTFeedbackView

iPhone developers: you may have seen my DSActivityView open source project. Another developer was inspired by it, and created his own variation, WTFeedbackView, with support for progress bars, among other changes.

Here's his introduction:

WTFeedbackView is a class to display a HUD-like view with either an activity indicator view or a progress view. It's based on DSActivityView by David Sinclair (http://www.dejal.com/developer/dsactivityview), with some significant additions and modifications.

More specifically, WTFeedbackView offers:

  • Client access through a single class, by means of class methods only, for all features;
  • Changes to the text being shown trigger an animation that resizes the HUD view appropriately;
  • Three built-in styles (like DSActivityView):
    • Simple style: displays a transparent view containing an activity indicator view next to the text explaining the ongoing activity;
    • Bezel style: displays a dark semi-transparent view containing either an activity indicator view or a progress view, above the text explaining the ongoing activity;
    • Keyboard style: same as the Bezel style, but covering only the keyboard;
  • Three built-in kinds:
    • Activity kind: displays only an activity indicator view, plus the text explaining the ongoing activity;
    • Progress kind: displays only a progress view, plus the text explaining the ongoing activity;
    • Flexible kind: contains both an activity indicator view and a progress view (plus the text explaining the ongoing activity), but displays only one at a time, on demand. This is useful when the ongoing activity has parts whose lengths are sometimes known and sometimes unknown. Rather than create a new feedback view for each part, a single one can be used, minimizing screen distractions;
  • Easy updating of the progress view, through a class method +updateProgress: (CGFloat) progress;
  • Thread-safety where needed. For instance, +updateProgress: can be safely invoked from a background thread;
  • Possibility to subclass WTFeedbackView to create custom feedback views having the general behavior of WTFeedbackView but looking differently.

Although iPhoneOS 3.x isn't a requirement, WTFeedbackView and the demo were compiled using iPhoneOS 3.1.2. They were *not* tested on any version prior to 3.x, so don't assume they will work with 2.x.

Enjoy!
Wagner

I'm hosting it for him: download now.

iPhone Open Source: detect tap outside a button like table's Delete

This blog post has been replaced by a newer edition.

Please see blog posts on DejalView.

Sorry customers, another development blog post. :)

For a new iPhone app I'm working on (shh), I have a button that I wanted to behave like the Delete button in a table view. You know, when you tap the delete toggle to the left of a cell, a red Delete button appears. And tapping anywhere other than that button will hide it without doing anything else:

Table Delete button
(Contacts app)

I couldn't see any obvious way to do it, so asked on the iPhone Developer forums, and got a helpful reply suggesting a UIWindow subclass, overriding -sendEvent:.

I tried implementing that, but what I really wanted was to override -hitTest:withEvent:, since I wanted to block taps on views other than a specific button, and the documentation says one should always invoke the superclass of -sendEvent:.

Then I noticed that -hitTest:withEvent: is actually defined in UIView, and further experimenting with the table Delete feature showed that it appears to be implemented UITableView, since the cancel tap behavior only occurs in the table, not the navigation bar or toolbar. Besides, implementing in a UIView subclass is more focal, so a better choice.

So here is my UIView subclass to do this. It uses a delegate approach, with a protocol to declare the method:


@class DSView;

@protocol DSViewDelegate
@optional

- (UIView *)view:(DSView *)view hitTest:(CGPoint)point
withEvent:(UIEvent *)event hitView:(UIView *)hitView;

@end

And the actual subclass interface; as conventional, the delegate is not retained:


@interface DSView : UIView
{
id DS_viewDelegate;
}

@property (nonatomic, assign) id viewDelegate;

@end

With the implementation just overriding the hit test method. It simply invokes the superclass then gives the delegate a chance to change it (or perform some other action) if it implements the delegate protocol method:


#import "DSView.h"

@implementation DSView

@synthesize viewDelegate = DS_viewDelegate;

/*
hitTest:withEvent:

Overrides this method to add support for the -view:hitTest:withEvent:hitView view delegate behavior.

Written by DJS 2009-09.
*/

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
{
UIView *hitView = [super hitTest:point withEvent:event];

if ([self.viewDelegate respondsToSelector:
@selector(view:hitTest:withEvent:hitView:)])
return [self.viewDelegate view:self hitTest:point
withEvent:event hitView:hitView];
else
return hitView;
}

@end

To use this, simply change a container UIView to DSView in the view hierarchy, then set the delegate property to your view controller (via code or IB):

self.view.viewDelegate = self;

Then implement the -view:hitTest:withEvent:hitView: delegate method in your view controller, e.g. as follows — this will cause a tap on some special control to go through as normal, but tapping anywhere else in the view will hide the special control, without passing the tap on to whatever was actually tapped:


- (UIView *)view:(DSView *)view hitTest:(CGPoint)point
withEvent:(UIEvent *)event hitView:(UIView *)hitView;
{
if (hitView == someSpecialControl)
return hitView;

someSpecialControl.hidden = YES;

return nil;
}

I hope this is useful to someone else too.

You can get the code from my Dejal Open Source Subversion repository via this Terminal command:


svn checkout http://dejal.svn.beanstalkapp.com/open/DSView

Or browse the source directly on the web.

If you haven't seen it already, check out DSActivityView, too.

DSActivityView updated

This blog post has been replaced by a newer edition.

Please see blog posts on DejalActivityView.

DSActivityViewI've committed a minor update to the DSActivityView open source project for iPhone. See the DSActivityView introductory post for more information, including a video demo.

This update adds a showNetworkActivityIndicator boolean property. It is NO by default, but if set to YES the network activity indicator in the status bar will be displayed, and automatically hidden when the DSActivityView is removed.

You can toggle this property as needed while the activity view is in use. For example, you might have the network activity indicator appear while fetching some data from the internet, then disable it while parsing it (while the activity view is still visible).

Of course, you can easily show and hide the network activity indicator yourself, but this tweak saves having to remember to disable both it and the DSActivityView.

You can set this property via:


[DSActivityView activityViewForView:self.view].showNetworkActivityIndicator = YES;

or to toggle it on an already-visible activity view:


[DSActivityView currentActivityView].showNetworkActivityIndicator = YES;

You can get the project from my Dejal Open Source Subversion repository via this Terminal command:


svn checkout http://dejal.svn.beanstalkapp.com/open/DSActivityView

Or browse the source directly on the web.

Announcing DSActivityView: open source for iPhone developers

This blog post has been replaced by a newer edition.

Please see blog posts on DejalActivityView.

DSActivityViewI recently wrote a reusable class for a couple of iPhone apps I'm currently working on, called DSActivityView. I decided to release it as open source. Read on for details.

Firstly, I should say that this work was inspired in part by Matt Gallagher's excellent article, Showing a "Loading..." message over the iPhone keyboard. My code only uses the -keyboardView method from his article, but he deserves credit and thanks for that and many other helpful articles. If you're not reading his blog, Cocoa with Love, you're doing yourself a disservice.

Back to my class. Actually, there are three classes: DSActivityView, DSBezelActivityView, and DSKeyboardActivityView. They provide three styles of activity view, and could easily be extended to support more.

DSActivityView

DSActivityViewThis does a simple horizontal-style loading view, intended for situations where you have a blank view while loading data. It can be displayed very easily — for the default "Loading..." label text, simply use:

[DSActivityView activityViewForView:self.view];

The activity view is automatically added as a subview of the specified view (e.g. the current content view). No need to save the result to an ivar. It automatically supports rotation to any orientation, too.

You can specify a custom label via:

[DSActivityView activityViewForView:self.view withLabel:@"Processing..."];

Or specify a custom width, e.g. so you can change the label while it is being displayed without upsetting the geometry, via:

[DSActivityView activityViewForView:self.view withLabel:@"Connecting..." width:100];

Then when you're done with it, simply invoke this to get rid of it:

[DSActivityView removeView];

DSBezelActivityView

DSBezelActivityViewThis is a subclass of DSActivityView, which displays an animated round-rect-enclosed variation: it animates into view by zooming from full-screen, with a gray background fading in to cover the passed view, and animates out by zooming to half size and fading out the background (see below for a movie showing it in action). It is ideal for situations where you have content visible already, but want to do a network operation to validate or send data, or some other time-consuming activity.

Display it via:

[DSBezelActivityView activityViewForView:self.view];

The [DSBezelActivityView activityViewForView:withLabel:] and [DSBezelActivityView activityViewForView:withLabel:width:] variations are also available. To remove with animation, call:

[DSBezelActivityView removeViewAnimated:YES];

DSKeyboardActivityView

DSKeyboardActivityViewThis is a subclass of DSBezelActivityView, which displays over the keyboard, somewhat like the OS 2 Text app used to do. It is useful to simply prevent further typing while validating a field or sending data (though you might also want to disable the field, to prevent pasteboard operations on it). No need to specify a view to use for this, since it uses the keyboard:

[DSKeyboardActivityView activityView];

Plus a [DSKeyboardActivityView activityViewWithLabel:] variation for custom text. Remove it the same as for the bezel style:

[DSKeyboardActivityView removeViewAnimated:YES];

Demo

I've included a demo project that builds an app to show the various options: the three styles, default or custom label text, covering just the content view or whole window, etc. It requires iPhone OS 3. Here's a movie showing the demo app running:

You can get the project from my Dejal Open Source Subversion repository via this Terminal command:

svn checkout http://dejal.svn.beanstalkapp.com/open/DSActivityView

Or browse the source directly on the web.

You can also download a snapshot, though it may not remain up-to-date; using Subversion is the recommended approach.

Follow @dejalopen on Twitter for automated Subversion commit message updates. You may also like to follow @dejaldevdiary for my behind-the-scenes development diary, and @dejal for general Dejal and personal tweets. Finally, there's also a RSS feed for the repository.

I hope these classes are useful. You are welcome to use them in any project, commercial or otherwise. I just ask that you give me credit; see the DSActivityView header for the easy and free licensing terms. If you do use this code in any form, please tell me (or comment here).

If you make improvements, e.g. to add other activity styles or fix bugs, please send them to me so I can share them with the community. Thanks.

Enjoy!

Update: see also an update to optionally support the network indicator, and an update for iOS 4.

Syndicate content