Deprecated: trim(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/html/extensions/Variables/includes/ExtVariables.php on line 198
SBIconView: Difference between revisions - iPhone Development Wiki

SBIconView: Difference between revisions

From iPhone Development Wiki
m (Formatting)
(Update for iOS 9)
Line 27: Line 27:
iconView.icon = appIcon;
iconView.icon = appIcon;
iconView.delegate = <an object conforming to SBIconViewDelegate>; // [%c(SBIconController) sharedInstance]
iconView.delegate = <an object conforming to SBIconViewDelegate>; // [%c(SBIconController) sharedInstance]
// iOS 9
SBIconView*iconView = [[%c(SBIconView) alloc] initWithContentType:<Icon View Content Type?> /* SB uses 0 by default */];
iconView.icon = appIcon;
iconView.delegate = <an object conforming to SBIconViewDelegate>; // [%c(SBIconController) sharedInstance];
</source>
</source>



Revision as of 05:27, 15 October 2015

SBIconView is a very versatile UIView subclass introduced in iOS 5 that is used to display icons in SpringBoard. In iOS 5 Apple split up icons into SBIcon (an abstract class) and SBIconView, introducing some degree of sanity with it. SBIconView conforms to the SBIconObserver protocol, and in turn exposes a protocol of its own: SBIconViewObserver. A lot of SpringBoard's home screen functionality can be modified by hooking the methods in SBIconView. One of the most magical methods in SBIconView is -setIcon:. It takes an instance of SBIcon and uses the information therein to create a semi-functional icon view.

Creating an Instance

// iOS 5
SBIcon *icon = [[%c(SBIconModel) sharedInstance] applicationIconForDisplayIdentifier:@"com.apple.MobileSafari"];

// iOS 6
SBIconModel *model = [[%c(SBIconController) sharedInstance] model];
SBIcon *appIcon = [model expectedIconForDisplayIdentifier:@"com.apple.MobileSafari"]; // expectedIconForDisplayIdentifier: has a larger scope than -applicationIconForDisplayIdentifier:
SBIconView *view = [[%c(SBIconView) alloc] initWithDefaultSize];
view.icon = appIcon;
view.delegate = <an object conforming to SBIconViewDelegate>; // SBIconController conforms to this protocol, and SBIconViewMap conforms to SBIconViewObserver.

// iOS 7
SBApplication *app = [[%c(SBApplicationController) sharedInstance] applicationWithDisplayIdentifier:@"com.apple.MobileSafari"];
SBApplicationIcon *appIcon = [[%c(SBApplicationIcon) alloc] initWithApplication:app];
SBIconView *iconView = [[%c(SBIconView) alloc] initWithDefaultSize];
iconView.icon = appIcon;
iconView.delegate = <an object conforming to SBIconViewDelegate>; // [%c(SBIconController) sharedInstance]

// iOS 8
SBApplication *app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:@"com.apple.MobileSafari"];
SBApplicationIcon *appIcon = [[%c(SBApplicationIcon) alloc] initWithApplication:app];
SBIconView *iconView = [[%c(SBIconView) alloc] initWithDefaultSize];
iconView.icon = appIcon;
iconView.delegate = <an object conforming to SBIconViewDelegate>; // [%c(SBIconController) sharedInstance]

// iOS 9
SBIconView*iconView = [[%c(SBIconView) alloc] initWithContentType:<Icon View Content Type?> /* SB uses 0 by default */];
iconView.icon = appIcon;
iconView.delegate = <an object conforming to SBIconViewDelegate>; // [%c(SBIconController) sharedInstance];

Getting a home screen icon view

Generally, creating a new instance of SBIconView is not what you'd want. To manipulate the icon views in an SBIconListView, you need to use SBIconViewMap to get a specific instance of an icon view.

// For >= iOS 6.0
SBIcon *icon = [[objc_getClass("SBIconController") sharedInstance].model expectedIconForDisplayIdentifier:@"com.apple.AppStore"];
SBIconView *iconView = [[objc_getClass("SBIconViewMap") homescreenMap] mappedIconViewForIcon:icon];
// Beware of icon view recycling. If `icon` is more than one page away from the current page on SB, this method will return nil
// This is not recommended, but to bypass this, use -[SBIconViewMap iconViewForIcon:], which creates a new icon view if one doesn't exist, adds it to its backing store, and returns it.
// This icon view will not have a superview since the SBIconListView instance for it simply doesn't exist!

SBIconViewLocation

// pre iOS 7
typedef enum {
	SBIconViewLocationNormal   = 0,
	SBIconViewLocationDock     = 1,
	SBIconViewLocationSwitcher = 2
} SBIconViewLocation;

// iOS 7
typedef enum {
	SBIconViewLocationNormal   = 0,
	SBIconViewLocationStark    = 1,
	SBIconViewLocationDock     = 2,
	SBIconViewLocationSwitcher = 3,
	SBIconViewLocationFolder   = 4
} SBIconViewLocation;

// iOS 8.0 - 8.3
typedef enum {
	SBIconViewLocationNormal    = 0,
	SBIconViewLocationStark     = 1,
	SBIconViewLocationDock      = 2,
	SBIconViewLocationSwitcher  = 3,
	SBIconViewLocationSwitcherLandscape = 4,
	SBIconViewLocationFolder    = 5
} SBIconViewLocation;

// iOS 8.4+
typedef enum {
	SBIconViewLocationNormal    = 1,
	SBIconViewLocationStark     = 2,
	SBIconViewLocationDock      = 3,
	SBIconViewLocationSwitcher  = 4,
	SBIconViewLocationSwitcherLandscape = 5,
	SBIconViewLocationFolder    = 6
} SBIconViewLocation;
@property (nonatomic, assign) SBIconViewLocation location;

SBIconView uses an enum for its location property. There are up to 6 kinds of locations (these are not the names Apple uses): The location is used by SBIconView to decide what kind of shadow to use, badge text (handled by SBIcon's badgeTextForLocation: (pre iOS 7) or accessoryTextForLocation: (iOS 7+)), and a few other things.

Ghosting (iOS 6 and earlier)

SBIconView also handles all the "ghosting" that is done when a folder or the switcher is opened. The way ghosting works is as follows:

SBIconView *iconView = ...;
[iconView prepareGhostlyImageIfNeeded]; // creates grayscale image used 
[iconView prepareGhostlyImageView]; // prepares a UIImageView with the grayscale image which is the same size as the current icon view image. Grayscale images are cached in NSTemporaryDirectory()
[iconView setGhostly:YES requester:kGhostlyRequesterFolder /* 1 */];
// Or, to fade icons out
[iconView setPartialGhostly:/* CGFloat from 0.0 to 1.0 */ requester:/* a requester */];

The last two calls in the above code place the ghostly image view under the current icon image view, and the main icon image view and badge (if one exists) are faded out. All methods for ghosting usually take an integer argument, requester. This is for the cases when the switcher is opened when there is already an open folder. Both the folder and switcher need the icon to be ghosted, and that's where the requester comes in. SBIconView uses requesters to keep track of how many clients have asked for it to be ghosted. In SpringBoard, there are only 2: folders (requester id 1) and the switcher (requester id 2). Use either one based on your needs.

Delegate Methods

- (BOOL)iconPositionIsEditable:(id)iconView { 
	return NO;
}
- (BOOL)iconShouldAllowTap:(id)iconView {
	return YES;
}
- (void)iconTapped:(id)iconView {
	[iconView.icon launchFromViewSwitcher];
}
- (void)iconHandleLongPress:(id)iconView {
	[iconView setIsJittering:YES];
}
- (void)iconTouchBegan:(id)arg1 {
	[iconView setHighlighted:YES];
}
- (void)icon:(id)iconView touchMovedWithEvent:(id)event{
	return;
}
- (void)icon:(id)iconView touchEnded:(BOOL)touchEnded {
	[iconView setHighlighted:NO delayUnhighlight:NO];
}
- (BOOL)icon:(id)iconView canReceiveGrabbedIcon:(id)iconView {
	return NO;
}
- (int)closeBoxTypeForIcon:(id)iconView {
	return 1;
}
- (void)iconCloseBoxTapped:(id)iconView {
	return;
}
- (BOOL)iconAllowJitter:(id)iconView {
	return YES;
}
- (BOOL)iconShouldPrepareGhostlyImage:(id)iconView {
	return YES;
}
- (BOOL)iconViewDisplaysBadges:(id)iconView {
	return NO;
}

Creating Modified Versions

The SBIconView class can be easily modified by subclassing.

These custom classes can be inserted into SpringBoard by hooking the following method in any class that conforms to the SBIconViewMapDelegate protocol:

- (Class)viewMap:(id)viewMap iconViewClassForIcon:(id)icon {
	return objc_getClass("MyClass");
}

References