Difference between revisions of "SBIconView"

From iPhone Development Wiki
Jump to: navigation, search
(Creating an Instance: typo, looks and iOS 8 codes.)
(SBIconViewLocation: Updated for iOS 8.4+)
Line 56: Line 56:
 
  } SBIconViewLocation;
 
  } SBIconViewLocation;
  
// iOS 8
+
// iOS 8.0 - 8.3
 
  typedef enum {
 
  typedef enum {
 
     SBIconViewLocationNormal    = 0,
 
     SBIconViewLocationNormal    = 0,
Line 64: Line 64:
 
     SBIconViewLocationSwitcherLandscape = 4,
 
     SBIconViewLocationSwitcherLandscape = 4,
 
     SBIconViewLocationFolder    = 5
 
     SBIconViewLocationFolder    = 5
 +
} SBIconViewLocation;
 +
 +
// iOS 8.4+
 +
typedef enum {
 +
    SBIconViewLocationNormal    = 1,
 +
    SBIconViewLocationStark    = 2,
 +
    SBIconViewLocationDock      = 3,
 +
    SBIconViewLocationSwitcher  = 4,
 +
    SBIconViewLocationSwitcherLandscape = 5,
 +
    SBIconViewLocationFolder    = 6
 
  } SBIconViewLocation;
 
  } SBIconViewLocation;
 
  @property (nonatomic, assign) SBIconViewLocation location;
 
  @property (nonatomic, assign) SBIconViewLocation location;

Revision as of 12:43, 10 July 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]

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)iconAllowJitter:(SBIconView *)arg1 {
    
    return YES;
}
- (BOOL)iconPositionIsEditable:(id)arg1 { 
    return NO;
}
- (void)iconHandleLongPress:(SBIconView *)arg1 {
    
    [arg1 setIsJittering:YES];
}
- (void)iconTouchBegan:(SBIconView *)arg1 {
    [arg1 setHighlighted:YES];
    
    
}
- (void)icon:(id)arg1 touchMovedWithEvent:(id)arg2 {
    
    
}
- (void)icon:(SBIconView *)arg1 touchEnded:(BOOL)arg2 {
    [arg1 setHighlighted:NO delayUnhighlight:NO];

}
- (BOOL)iconShouldAllowTap:(id)arg1 {
    return YES;
}
- (void)iconTapped:(SBIconView *)arg1 {
    [arg1.icon launchFromViewSwitcher];
}
- (BOOL)icon:(id)arg1 canReceiveGrabbedIcon:(id)arg2 {
    return NO;
}

- (int)closeBoxTypeForIcon:(id)arg1 {
    
    return 1;
}
- (void)iconCloseBoxTapped:(id)arg1 {
    
}
- (BOOL)iconShouldPrepareGhostlyImage:(id)arg1 {
    
    return YES;
}
- (BOOL)iconViewDisplaysBadges:(id)arg1 {
    
    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)arg1 iconViewClassForIcon:(id)arg2
{
    return objc_getClass("MyClass");
}