Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

First Commit

  • Loading branch information...
commit 51651f964c8a1c56681477bb4b21372467080ba5 1 parent 9ae0a64
@junpluse authored
View
31 JTListView.xcodeproj/project.pbxproj
@@ -14,6 +14,8 @@
BF60EB9B1374000700B0603C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BF60EB9A1374000700B0603C /* main.m */; };
BF60EB9E1374000700B0603C /* JTListViewAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BF60EB9D1374000700B0603C /* JTListViewAppDelegate.m */; };
BF60EBA11374000700B0603C /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = BF60EB9F1374000700B0603C /* MainWindow.xib */; };
+ BF60EBD6137400E800B0603C /* JTListView.m in Sources */ = {isa = PBXBuildFile; fileRef = BF60EBD5137400E800B0603C /* JTListView.m */; };
+ BFB77303137670EC00983A93 /* JTListViewDemoController.m in Sources */ = {isa = PBXBuildFile; fileRef = BFB77302137670EC00983A93 /* JTListViewDemoController.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -21,13 +23,18 @@
BF60EB8D1374000600B0603C /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
BF60EB8F1374000700B0603C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
BF60EB911374000700B0603C /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
- BF60EB951374000700B0603C /* JTListView-Info.plist */ = {isa = PBXFileReference; path = "JTListView-Info.plist"; sourceTree = "<group>"; };
+ BF60EB951374000700B0603C /* JTListView-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "JTListView-Info.plist"; sourceTree = "<group>"; };
BF60EB971374000700B0603C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
- BF60EB991374000700B0603C /* JTListView-Prefix.pch */ = {isa = PBXFileReference; path = "JTListView-Prefix.pch"; sourceTree = "<group>"; };
+ BF60EB991374000700B0603C /* JTListView-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JTListView-Prefix.pch"; sourceTree = "<group>"; };
BF60EB9A1374000700B0603C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
- BF60EB9C1374000700B0603C /* JTListViewAppDelegate.h */ = {isa = PBXFileReference; path = JTListViewAppDelegate.h; sourceTree = "<group>"; };
+ BF60EB9C1374000700B0603C /* JTListViewAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JTListViewAppDelegate.h; sourceTree = "<group>"; };
BF60EB9D1374000700B0603C /* JTListViewAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JTListViewAppDelegate.m; sourceTree = "<group>"; };
BF60EBA01374000700B0603C /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainWindow.xib; sourceTree = "<group>"; };
+ BF60EBD4137400E800B0603C /* JTListView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JTListView.h; sourceTree = "<group>"; };
+ BF60EBD5137400E800B0603C /* JTListView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JTListView.m; sourceTree = "<group>"; };
+ BFB77301137670EC00983A93 /* JTListViewDemoController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JTListViewDemoController.h; sourceTree = "<group>"; };
+ BFB77302137670EC00983A93 /* JTListViewDemoController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JTListViewDemoController.m; sourceTree = "<group>"; };
+ BFB773321376F3ED00983A93 /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -76,6 +83,10 @@
children = (
BF60EB9C1374000700B0603C /* JTListViewAppDelegate.h */,
BF60EB9D1374000700B0603C /* JTListViewAppDelegate.m */,
+ BFB77301137670EC00983A93 /* JTListViewDemoController.h */,
+ BFB77302137670EC00983A93 /* JTListViewDemoController.m */,
+ BF60EBD4137400E800B0603C /* JTListView.h */,
+ BF60EBD5137400E800B0603C /* JTListView.m */,
BF60EB9F1374000700B0603C /* MainWindow.xib */,
BF60EB941374000700B0603C /* Supporting Files */,
);
@@ -89,6 +100,7 @@
BF60EB961374000700B0603C /* InfoPlist.strings */,
BF60EB991374000700B0603C /* JTListView-Prefix.pch */,
BF60EB9A1374000700B0603C /* main.m */,
+ BFB773321376F3ED00983A93 /* .gitignore */,
);
name = "Supporting Files";
sourceTree = "<group>";
@@ -119,7 +131,7 @@
BF60EB801374000600B0603C /* Project object */ = {
isa = PBXProject;
attributes = {
- ORGANIZATIONNAME = "東京工科大学";
+ ORGANIZATIONNAME = "Jun Tanaka";
};
buildConfigurationList = BF60EB831374000600B0603C /* Build configuration list for PBXProject "JTListView" */;
compatibilityVersion = "Xcode 3.2";
@@ -157,6 +169,8 @@
files = (
BF60EB9B1374000700B0603C /* main.m in Sources */,
BF60EB9E1374000700B0603C /* JTListViewAppDelegate.m in Sources */,
+ BF60EBD6137400E800B0603C /* JTListView.m in Sources */,
+ BFB77303137670EC00983A93 /* JTListViewDemoController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -186,6 +200,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_OPTIMIZATION_LEVEL = 0;
@@ -195,6 +210,7 @@
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
+ PROVISIONING_PROFILE = "";
SDKROOT = iphoneos;
};
name = Debug;
@@ -203,6 +219,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_VERSION = com.apple.compilers.llvmgcc42;
@@ -210,6 +227,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 4.3;
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
+ PROVISIONING_PROFILE = "";
SDKROOT = iphoneos;
};
name = Release;
@@ -223,7 +241,9 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "JTListView/JTListView-Prefix.pch";
INFOPLIST_FILE = "JTListView/JTListView-Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 4.3;
PRODUCT_NAME = "$(TARGET_NAME)";
+ TARGETED_DEVICE_FAMILY = "1,2";
WRAPPER_EXTENSION = app;
};
name = Debug;
@@ -236,7 +256,9 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "JTListView/JTListView-Prefix.pch";
INFOPLIST_FILE = "JTListView/JTListView-Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 4.3;
PRODUCT_NAME = "$(TARGET_NAME)";
+ TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
WRAPPER_EXTENSION = app;
};
@@ -261,6 +283,7 @@
BF60EBA61374000700B0603C /* Release */,
);
defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
View
34 JTListView.xcodeproj/xcuserdata/Jun.xcuserdatad/xcschemes/JTListView.xcscheme
@@ -4,6 +4,22 @@
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "BF60EB881374000600B0603C"
+ BuildableName = "JTListView.app"
+ BlueprintName = "JTListView"
+ ReferencedContainer = "container:JTListView.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
@@ -21,6 +37,15 @@
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "BF60EB881374000600B0603C"
+ BuildableName = "JTListView.app"
+ BlueprintName = "JTListView"
+ ReferencedContainer = "container:JTListView.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
@@ -31,6 +56,15 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "BF60EB881374000600B0603C"
+ BuildableName = "JTListView.app"
+ BlueprintName = "JTListView"
+ ReferencedContainer = "container:JTListView.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
View
14 JTListView/.gitignore
@@ -0,0 +1,14 @@
+# Xcode
+build/*
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+*.xcworkspace
+!default.xcworkspace
+profile
+*.moved-aside
View
1  JTListView/JTListView-Info.plist
@@ -31,6 +31,7 @@
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
View
102 JTListView/JTListView.h
@@ -0,0 +1,102 @@
+//
+// JTListView.h
+// JTListView
+//
+// Created by Jun on 5/6/11.
+// Copyright 2011 Jun Tanaka. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+@class JTListView;
+
+
+typedef enum {
+ JTListViewLayoutLeftToRight,
+ JTListViewLayoutRightToLeft,
+ JTListViewLayoutTopToBottom,
+ JTListViewLayoutBottomToTop
+} JTListViewLayout;
+
+
+typedef enum {
+ JTListViewScrollPositionNone = UITableViewScrollPositionNone,
+ JTListViewScrollPositionCenter = UITableViewRowAnimationMiddle,
+ JTListViewScrollPositionCenterElseNone // center if the view size is smaller than bounds size, else none
+} JTListViewScrollPosition;
+
+
+@protocol JTListViewDataSource <NSObject>
+@required
+- (NSUInteger)numberOfItemsInListView:(JTListView *)listView;
+- (UIView *)listView:(JTListView *)listView viewForItemAtIndex:(NSUInteger)index;
+
+@end
+
+
+@protocol JTListViewDelegate <UIScrollViewDelegate>
+@optional
+- (void)listView:(JTListView *)listView willDisplayView:(UIView *)view forItemAtIndex:(NSUInteger)index;
+
+- (CGFloat)listView:(JTListView *)listView widthForItemAtIndex:(NSUInteger)index; // for horizontal layouts
+- (CGFloat)listView:(JTListView *)listView heightForItemAtIndex:(NSUInteger)index; // for vertical layouts
+
+@end
+
+
+@interface JTListView : UIScrollView {
+@package
+ NSMutableArray *_itemRects;
+ NSRange _visibleRange;
+ NSMutableArray *_visibleViews;
+ NSMutableSet *_reuseableViews;
+}
+
+@property (nonatomic, assign) IBOutlet id <JTListViewDataSource> dataSource;
+@property (nonatomic, assign) IBOutlet id <JTListViewDelegate> delegate;
+
+@property (nonatomic) JTListViewLayout layout;
+@property (nonatomic) CGFloat itemWidth; // for horizontal layouts. default is 44.0
+@property (nonatomic) CGFloat itemHeight; // for vertical layouts. default is 44.0
+@property (nonatomic) CGFloat gapBetweenItems; // default is zero
+@property (nonatomic) UIEdgeInsets visibleInsets; // set negative values to load views outside bounds. default is UIEdgeInsetsZero
+
+- (id)initWithFrame:(CGRect)frame layout:(JTListViewLayout)layout; // must specify style at creation. -initWithFrame: calls this with JTListViewLayoutLeftToRight
+
+- (void)reloadData;
+- (void)reloadItemsAtIndexes:(NSIndexSet *)indexes;
+
+- (void)updateItemSizes;
+- (void)updateItemSizesAtIndexes:(NSIndexSet *)indexes;
+
+- (NSUInteger)numberOfItems;
+
+- (CGRect)rectForItemAtIndex:(NSUInteger)index; // returns CGRectNull if index is out of range
+- (UIView *)viewForItemAtIndex:(NSUInteger)index; // returns nil if view is not visible or index is out of range
+
+- (NSUInteger)indexForView:(UIView *)view; // returns NSNotFound if view is not visible
+- (NSUInteger)indexForItemAtPoint:(CGPoint)point; // returns NSNotFound if point is outside list
+- (NSUInteger)indexForItemAtCenterOfBounds;
+- (NSIndexSet *)indexesForItemsInRect:(CGRect)rect; // returns nil if rect is outside list
+
+- (CGRect)visibleRect;
+- (NSArray *)visibleViews;
+- (NSIndexSet *)indexesForVisibleItems;
+
+- (void)scrollToItemAtIndex:(NSUInteger)index atScrollPosition:(JTListViewScrollPosition)scrollPosition animated:(BOOL)animated;
+
+// smart paging
+- (void)goBack:(BOOL)animated;
+- (void)goForward:(BOOL)animated;
+
+- (UIView *)dequeueReusableView; // similar to UITableView's dequeueReusableCellWithIdentifier:
+
+@end
+
+
+@interface JTListViewController : UIViewController <JTListViewDataSource, JTListViewDelegate>
+
+@property (nonatomic, retain) IBOutlet JTListView *listView;
+
+@end
View
949 JTListView/JTListView.m
@@ -0,0 +1,949 @@
+//
+// JTListView.m
+// JTListView
+//
+// Created by Jun on 5/6/11.
+// Copyright 2011 Jun Tanaka. All rights reserved.
+//
+
+#import "JTListView.h"
+
+
+BOOL JTListViewLayoutIsHorizontal(JTListViewLayout layout)
+{
+ return (layout == JTListViewLayoutLeftToRight || layout == JTListViewLayoutRightToLeft);
+}
+
+BOOL JTListViewLayoutIsVertical(JTListViewLayout layout)
+{
+ return (layout == JTListViewLayoutTopToBottom || layout == JTListViewLayoutBottomToTop);
+}
+
+
+#pragma mark -
+@interface JTListView (Private)
+
+- (BOOL)isHorizontalLayout;
+- (BOOL)isVerticalLayout;
+
+- (void)sharedInit;
+
+- (void)layoutItemRectsAtIndexes:(NSIndexSet *)indexes;
+- (void)layoutVisibleItems;
+- (void)loadItemAtIndex:(NSUInteger)index;
+- (void)loadItemAtIndexes:(NSIndexSet *)indexes;
+- (void)recycleView:(UIView *)view;
+- (void)recycleItemAtIndexes:(NSIndexSet *)indexes;
+
+- (NSUInteger)leftItemIndex;
+- (NSUInteger)rightItemIndex;
+- (NSUInteger)upperItemIndex;
+- (NSUInteger)lowerItemIndex;
+
+- (void)goLeft:(BOOL)animated;
+- (void)goRight:(BOOL)animated;
+- (void)goUp:(BOOL)animated;
+- (void)goDown:(BOOL)animated;
+
+@end
+
+
+#pragma mark -
+@implementation JTListView
+
+@synthesize dataSource = _dataSource;
+@synthesize layout = _layout;
+@synthesize itemWidth = _itemWidth;
+@synthesize itemHeight = _itemHeight;
+@synthesize gapBetweenItems = _gapBetweenItems;
+@synthesize visibleInsets = _visibleInsets;
+
+- (void)dealloc
+{
+ [_itemRects release], _itemRects = nil;
+ [_visibleViews release], _visibleViews = nil;
+ [_reuseableViews release], _reuseableViews = nil;
+
+ [super dealloc];
+}
+
+- (id)initWithCoder:(NSCoder *)aDecoder
+{
+ self = [super initWithCoder:aDecoder];
+ if (self)
+ {
+ [self sharedInit];
+ }
+ return self;
+}
+
+- (id)initWithFrame:(CGRect)frame
+{
+ return [self initWithFrame:frame layout:JTListViewLayoutLeftToRight];
+}
+
+- (id)initWithFrame:(CGRect)frame layout:(JTListViewLayout)layout;
+{
+ self = [super initWithFrame:frame];
+ if (self)
+ {
+ [self sharedInit];
+ [self setLayout:layout];
+ }
+ return self;
+}
+
+
+#pragma mark - JTListView (Private)
+
+- (BOOL)isHorizontalLayout
+{
+ return JTListViewLayoutIsHorizontal(_layout);
+}
+
+- (BOOL)isVerticalLayout
+{
+ return JTListViewLayoutIsVertical(_layout);
+}
+
+- (void)sharedInit
+{
+ _itemRects = [[NSMutableArray alloc] init];
+ _visibleRange = NSMakeRange(0, 0);
+ _visibleViews = [[NSMutableArray alloc] init];
+ _reuseableViews = [[NSMutableSet alloc] init];
+ _itemWidth = 44.0;
+ _itemHeight = 44.0;
+ _gapBetweenItems = 0.0;
+ _visibleInsets = UIEdgeInsetsZero;
+
+ self.directionalLockEnabled = YES;
+
+ [self addObserver:self forKeyPath:@"itemWidth" options:0 context:nil];
+ [self addObserver:self forKeyPath:@"itemHeight" options:0 context:nil];
+ [self addObserver:self forKeyPath:@"gapBetweenItems" options:0 context:nil];
+
+ [self setLayout:JTListViewLayoutLeftToRight];
+}
+
+- (void)layoutItemRects
+{
+ __block CGPoint contentOffset = CGPointZero;
+ __block CGSize contentSize = CGSizeZero;
+
+ NSEnumerationOptions enumerationOptions;
+
+ if (_layout == JTListViewLayoutLeftToRight || _layout == JTListViewLayoutTopToBottom)
+ {
+ enumerationOptions = 0;
+ }
+ else if (_layout == JTListViewLayoutRightToLeft || _layout == JTListViewLayoutBottomToTop)
+ {
+ enumerationOptions = NSEnumerationReverse;
+ }
+
+ void(^contentUpdater)(CGRect);
+
+ if ([self isHorizontalLayout])
+ {
+ contentUpdater = ^(CGRect itemRect)
+ {
+ CGFloat step = itemRect.size.width + _gapBetweenItems;
+ contentOffset.x += step;
+ contentSize.width += step;
+ };
+ }
+ else if ([self isVerticalLayout])
+ {
+ contentUpdater = ^(CGRect itemRect)
+ {
+ CGFloat step = itemRect.size.height + _gapBetweenItems;
+ contentOffset.y += step;
+ contentSize.height += step;
+ };
+ }
+
+ NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfItems])];
+
+ [indexSet enumerateIndexesWithOptions:enumerationOptions usingBlock:^(NSUInteger idx, BOOL *stop)
+ {
+ CGRect itemRect = [[_itemRects objectAtIndex:idx] CGRectValue];
+ itemRect.origin.x = contentOffset.x;
+ itemRect.origin.y = contentOffset.y;
+ [_itemRects replaceObjectAtIndex:idx withObject:[NSValue valueWithCGRect:itemRect]];
+ contentUpdater(itemRect);
+ }];
+
+ self.contentSize = contentSize;
+
+ [self layoutVisibleItems];
+}
+
+- (void)layoutVisibleItems
+{
+ NSIndexSet *oldVisibleIndexes = [NSIndexSet indexSetWithIndexesInRange:_visibleRange];
+ NSIndexSet *newVisibleIndexes = [self indexesForItemsInRect:[self visibleRect]];
+
+ if (![oldVisibleIndexes isEqualToIndexSet:newVisibleIndexes])
+ {
+ NSIndexSet *indexesForRecycle = [oldVisibleIndexes indexesPassingTest:^BOOL(NSUInteger idx, BOOL *stop)
+ {
+ return ![newVisibleIndexes containsIndex:idx];
+ }];
+ [self recycleItemAtIndexes:indexesForRecycle];
+
+ NSUInteger firstIndex = [newVisibleIndexes firstIndex];
+ NSUInteger lastIndex = [newVisibleIndexes lastIndex];
+ _visibleRange = NSMakeRange(firstIndex, lastIndex - firstIndex + 1);
+
+ NSIndexSet *indexesForLoad = [newVisibleIndexes indexesPassingTest:^BOOL(NSUInteger idx, BOOL *stop)
+ {
+ return ![oldVisibleIndexes containsIndex:idx];
+ }];
+ [self loadItemAtIndexes:indexesForLoad];
+ }
+
+ BOOL animationsEnabled = [UIView areAnimationsEnabled];
+
+ [newVisibleIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop)
+ {
+ UIView *view = [self viewForItemAtIndex:idx];
+ CGRect itemRect = [self rectForItemAtIndex:idx];
+
+ if (!CGPointEqualToPoint(view.frame.origin, itemRect.origin))
+ {
+ [UIView setAnimationsEnabled:NO];
+ }
+
+ if (!CGRectEqualToRect(view.frame, itemRect))
+ {
+ view.frame = itemRect;
+ }
+
+ if (!view.superview)
+ {
+ if (self.delegate && [self.delegate respondsToSelector:@selector(listView:willDisplayView:forItemAtIndex:)])
+ {
+ [self.delegate listView:self willDisplayView:view forItemAtIndex:idx];
+ }
+ [self insertSubview:view atIndex:1];
+ }
+
+ [UIView setAnimationsEnabled:animationsEnabled];
+ }];
+}
+
+- (void)loadItemAtIndex:(NSUInteger)index
+{
+ UIView *view = [self.dataSource listView:self viewForItemAtIndex:index];
+ [_visibleViews insertObject:view atIndex:index - _visibleRange.location];
+}
+
+- (void)loadItemAtIndexes:(NSIndexSet *)indexes
+{
+ [indexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop)
+ {
+ [self loadItemAtIndex:idx];
+ }];
+}
+
+- (void)recycleView:(UIView *)view
+{
+ if (!view)
+ {
+ return;
+ }
+
+ [view retain];
+ [view removeFromSuperview];
+ [_visibleViews removeObject:view];
+ [_reuseableViews addObject:view];
+ [view release];
+}
+
+- (void)recycleItemAtIndexes:(NSIndexSet *)indexes
+{
+ [indexes enumerateIndexesWithOptions:NSEnumerationReverse usingBlock:^(NSUInteger idx, BOOL *stop)
+ {
+ [self recycleView:[self viewForItemAtIndex:idx]];
+ }];
+}
+
+- (NSUInteger)leftItemIndex
+{
+ NSUInteger centerItemIndex = [self indexForItemAtCenterOfBounds];
+
+ if (_layout == JTListViewLayoutLeftToRight)
+ {
+ if (centerItemIndex == 0)
+ {
+ return NSNotFound;
+ }
+ return centerItemIndex - 1;
+ }
+ else if (_layout == JTListViewLayoutRightToLeft)
+ {
+ if (centerItemIndex == [self numberOfItems] - 1)
+ {
+ return NSNotFound;
+ }
+ return centerItemIndex + 1;
+ }
+
+ return NSNotFound;
+}
+
+- (NSUInteger)rightItemIndex
+{
+ NSUInteger centerItemIndex = [self indexForItemAtCenterOfBounds];
+
+ if (_layout == JTListViewLayoutLeftToRight)
+ {
+ if (centerItemIndex == [self numberOfItems] - 1)
+ {
+ return NSNotFound;
+ }
+ return centerItemIndex + 1;
+ }
+ else if (_layout == JTListViewLayoutRightToLeft)
+ {
+ if (centerItemIndex == 0)
+ {
+ return NSNotFound;
+ }
+ return centerItemIndex - 1;
+ }
+
+ return NSNotFound;
+}
+
+- (NSUInteger)upperItemIndex
+{
+ NSUInteger centerItemIndex = [self indexForItemAtCenterOfBounds];
+
+ if (_layout == JTListViewLayoutTopToBottom)
+ {
+ if (centerItemIndex == 0)
+ {
+ return NSNotFound;
+ }
+ return centerItemIndex - 1;
+ }
+ else if (_layout == JTListViewLayoutBottomToTop)
+ {
+ if (centerItemIndex == [self numberOfItems] - 1)
+ {
+ return NSNotFound;
+ }
+ return centerItemIndex + 1;
+ }
+
+ return NSNotFound;
+}
+
+- (NSUInteger)lowerItemIndex
+{
+ NSUInteger centerItemIndex = [self indexForItemAtCenterOfBounds];
+
+ if (_layout == JTListViewLayoutTopToBottom)
+ {
+ if (centerItemIndex == [self numberOfItems] - 1)
+ {
+ return NSNotFound;
+ }
+ return centerItemIndex + 1;
+ }
+ else if (_layout == JTListViewLayoutBottomToTop)
+ {
+ if (centerItemIndex == 0)
+ {
+ return NSNotFound;
+ }
+ return centerItemIndex - 1;
+ }
+
+ return NSNotFound;
+}
+
+- (void)goLeft:(BOOL)animated;
+{
+ CGPoint contentOffset;
+
+ NSUInteger currentItemIndex = [self indexForItemAtCenterOfBounds];
+ CGRect currentItemRect = [self rectForItemAtIndex:currentItemIndex];
+ CGFloat currentItemMinX = CGRectGetMinX(currentItemRect);
+
+ if (CGRectGetMinX(self.bounds) > currentItemMinX)
+ {
+ if (self.bounds.size.width > CGRectGetMinX(self.bounds) - currentItemMinX)
+ {
+ contentOffset = CGPointMake(currentItemMinX, self.contentOffset.y);
+ }
+ else
+ {
+ contentOffset = CGPointMake(self.contentOffset.x - self.bounds.size.width, self.contentOffset.y);
+ }
+ [self setContentOffset:contentOffset animated:animated];
+ }
+ else
+ {
+ NSUInteger nextItemIndex = [self leftItemIndex];
+ [self scrollToItemAtIndex:nextItemIndex atScrollPosition:JTListViewScrollPositionCenterElseNone animated:animated];
+ }
+}
+
+- (void)goRight:(BOOL)animated;
+{
+ CGPoint contentOffset;
+
+ NSUInteger currentItemIndex = [self indexForItemAtCenterOfBounds];
+ CGRect currentItemRect = [self rectForItemAtIndex:currentItemIndex];
+ CGFloat currentItemMaxX = CGRectGetMaxX(currentItemRect);
+
+ if (CGRectGetMaxX(self.bounds) < currentItemMaxX)
+ {
+ if (self.bounds.size.width > currentItemMaxX - CGRectGetMaxX(self.bounds))
+ {
+ contentOffset = CGPointMake(currentItemMaxX - self.bounds.size.width, self.contentOffset.y);
+ }
+ else
+ {
+ contentOffset = CGPointMake(self.contentOffset.x + self.bounds.size.width, self.contentOffset.y);
+ }
+ [self setContentOffset:contentOffset animated:animated];
+ }
+ else
+ {
+ NSUInteger nextItemIndex = [self rightItemIndex];
+ [self scrollToItemAtIndex:nextItemIndex atScrollPosition:JTListViewScrollPositionCenterElseNone animated:animated];
+ }
+}
+
+- (void)goUp:(BOOL)animated;
+{
+ CGPoint contentOffset;
+
+ NSUInteger currentItemIndex = [self indexForItemAtCenterOfBounds];
+ CGRect currentItemRect = [self rectForItemAtIndex:currentItemIndex];
+ CGFloat currentItemMinY = CGRectGetMinY(currentItemRect);
+
+ if (CGRectGetMinY(self.bounds) > currentItemMinY)
+ {
+ if (self.bounds.size.height > CGRectGetMinY(self.bounds) - currentItemMinY)
+ {
+ contentOffset = CGPointMake(self.contentOffset.x, currentItemMinY);
+ }
+ else
+ {
+ contentOffset = CGPointMake(self.contentOffset.x, self.contentOffset.y - self.bounds.size.height);
+ }
+ [self setContentOffset:contentOffset animated:animated];
+ }
+ else
+ {
+ NSUInteger nextItemIndex = [self upperItemIndex];
+ [self scrollToItemAtIndex:nextItemIndex atScrollPosition:JTListViewScrollPositionCenterElseNone animated:animated];
+ }
+}
+
+- (void)goDown:(BOOL)animated;
+{
+ CGPoint contentOffset;
+
+ NSUInteger currentItemIndex = [self indexForItemAtCenterOfBounds];
+ CGRect currentItemRect = [self rectForItemAtIndex:currentItemIndex];
+ CGFloat currentItemMaxY = CGRectGetMaxY(currentItemRect);
+
+ if (CGRectGetMaxY(self.bounds) < currentItemMaxY)
+ {
+ if (self.bounds.size.height > currentItemMaxY - CGRectGetMaxY(self.bounds))
+ {
+ contentOffset = CGPointMake(self.contentOffset.x, currentItemMaxY - self.bounds.size.height);
+ }
+ else
+ {
+ contentOffset = CGPointMake(self.contentOffset.x, self.contentOffset.y + self.bounds.size.height);
+ }
+ [self setContentOffset:contentOffset animated:animated];
+ }
+ else
+ {
+ NSUInteger nextItemIndex = [self lowerItemIndex];
+ [self scrollToItemAtIndex:nextItemIndex atScrollPosition:JTListViewScrollPositionCenterElseNone animated:animated];
+ }
+}
+
+
+#pragma mark - JTListView (Public)
+
+- (id <JTListViewDelegate>)delegate
+{
+ return (id <JTListViewDelegate>)[super delegate];
+}
+
+- (void)setDelegate:(id<JTListViewDelegate>)delegate
+{
+ [super setDelegate:delegate];
+}
+
+- (void)setLayout:(JTListViewLayout)layout
+{
+ NSUInteger indexCache = [self indexForItemAtCenterOfBounds];
+
+ _layout = layout;
+
+ if (JTListViewLayoutIsHorizontal(layout))
+ {
+ self.showsHorizontalScrollIndicator = YES;
+ self.showsVerticalScrollIndicator = NO;
+ self.alwaysBounceHorizontal = YES;
+ self.alwaysBounceVertical = NO;
+ self.itemWidth = 40;
+ self.itemHeight = self.frame.size.height;
+ }
+ else if (JTListViewLayoutIsVertical(layout))
+ {
+ self.showsHorizontalScrollIndicator = NO;
+ self.showsVerticalScrollIndicator = YES;
+ self.alwaysBounceHorizontal = NO;
+ self.alwaysBounceVertical = YES;
+ self.itemWidth = self.frame.size.width;
+ self.itemHeight = 40;
+ }
+
+ [self reloadData];
+ [self scrollToItemAtIndex:indexCache atScrollPosition:JTListViewScrollPositionCenter animated:NO];
+}
+
+- (void)reloadData
+{
+ if (!self.dataSource)
+ {
+ return;
+ }
+
+ for (UIView *view in [_visibleViews reverseObjectEnumerator])
+ {
+ [self recycleView:view];
+ }
+
+ _visibleRange = NSMakeRange(0, 0);
+ [_itemRects removeAllObjects];
+
+ NSUInteger numberOfItems = [self.dataSource numberOfItemsInListView:self];
+
+ for (int i = 0; i < numberOfItems; i ++)
+ {
+ [_itemRects addObject:[NSValue valueWithCGRect:CGRectNull]];
+ }
+
+ [self updateItemSizes];
+}
+
+- (void)reloadItemsAtIndexes:(NSIndexSet *)indexes
+{
+ if (!self.dataSource)
+ {
+ return;
+ }
+
+ [self recycleItemAtIndexes:indexes];
+ [self updateItemSizesAtIndexes:indexes];
+}
+
+- (void)updateItemSizes
+{
+ NSIndexSet *allIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfItems])];
+ [self updateItemSizesAtIndexes:allIndexes];
+}
+
+- (void)updateItemSizesAtIndexes:(NSIndexSet *)indexes
+{
+ CGSize(^sizeForItemAtIndex)(NSUInteger);
+
+ if ([self isHorizontalLayout])
+ {
+ if (self.delegate && [self.delegate respondsToSelector:@selector(listView:widthForItemAtIndex:)])
+ {
+ sizeForItemAtIndex = ^CGSize(NSUInteger idx)
+ {
+ return CGSizeMake([self.delegate listView:self widthForItemAtIndex:idx], self.frame.size.height);
+ };
+ }
+ else
+ {
+ sizeForItemAtIndex = ^CGSize(NSUInteger idx)
+ {
+ return CGSizeMake(_itemWidth, self.frame.size.height);
+ };
+ }
+ }
+ else if ([self isVerticalLayout])
+ {
+ if (self.delegate && [self.delegate respondsToSelector:@selector(listView:heightForItemAtIndex:)])
+ {
+ sizeForItemAtIndex = ^CGSize(NSUInteger idx)
+ {
+ return CGSizeMake(self.frame.size.width, [self.delegate listView:self heightForItemAtIndex:idx]);
+ };
+ }
+ else
+ {
+ sizeForItemAtIndex = ^CGSize(NSUInteger idx)
+ {
+ return CGSizeMake(self.frame.size.width, _itemHeight);
+ };
+ }
+ }
+
+ [indexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop)
+ {
+ CGRect itemRect = [self rectForItemAtIndex:idx];
+ itemRect.size = sizeForItemAtIndex(idx);
+ [_itemRects replaceObjectAtIndex:idx withObject:[NSValue valueWithCGRect:itemRect]];
+ }];
+
+ [self layoutItemRects];
+}
+
+- (NSUInteger)numberOfItems
+{
+ return [_itemRects count];
+}
+
+- (CGRect)rectForItemAtIndex:(NSUInteger)index
+{
+ if (index < [_itemRects count])
+ {
+ return [[_itemRects objectAtIndex:index] CGRectValue];
+ }
+ return CGRectNull;
+}
+
+- (UIView *)viewForItemAtIndex:(NSUInteger)index
+{
+ if (index - _visibleRange.location < [_visibleViews count])
+ {
+ return [_visibleViews objectAtIndex:index - _visibleRange.location];
+ }
+ return nil;
+}
+
+- (NSUInteger)indexForView:(UIView *)view
+{
+ if ([_visibleViews containsObject:view])
+ {
+ return [_visibleViews indexOfObject:view] + _visibleRange.location;
+ }
+ return NSNotFound;
+}
+
+- (NSUInteger)indexForItemAtPoint:(CGPoint)point
+{
+ NSIndexSet *indexes = [self indexesForItemsInRect:CGRectMake(point.x, point.y, 1, 1)];
+ if (indexes)
+ {
+ return [indexes lastIndex];
+ }
+ return NSNotFound;
+}
+
+- (NSUInteger)indexForItemAtCenterOfBounds
+{
+ return [self indexForItemAtPoint:CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds))];
+}
+
+- (NSIndexSet *)indexesForItemsInRect:(CGRect)rect
+{
+ if ([self numberOfItems] == 0)
+ {
+ return nil;
+ }
+
+ NSRange searchRange = NSMakeRange(0, [self numberOfItems]);
+
+ while (YES)
+ {
+ NSUInteger centerIndex = searchRange.location + searchRange.length / 2;
+ CGRect centerItemRect = [self rectForItemAtIndex:centerIndex];
+
+ if (CGRectIntersectsRect(centerItemRect, rect))
+ {
+ NSUInteger firstIndex = centerIndex;
+ NSUInteger lastIndex = centerIndex;
+
+ while (CGRectIntersectsRect([self rectForItemAtIndex:firstIndex - 1], rect))
+ {
+ if (firstIndex == 0)
+ {
+ break;
+ }
+ firstIndex --;
+ }
+ while (CGRectIntersectsRect([self rectForItemAtIndex:lastIndex + 1], rect))
+ {
+ if (lastIndex == [self numberOfItems] - 1)
+ {
+ break;
+ }
+ lastIndex ++;
+ }
+
+ NSRange indexRange = NSMakeRange(firstIndex, lastIndex - firstIndex + 1);
+ NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:indexRange];
+ return indexes;
+ }
+ else if (searchRange.length == 1)
+ {
+ return nil;
+ }
+ else
+ {
+ CGRect firstItemRect = [self rectForItemAtIndex:searchRange.location];
+ if (!CGRectIntersectsRect(CGRectUnion(firstItemRect, centerItemRect), rect))
+ {
+ searchRange.location = centerIndex + 1;
+ }
+ searchRange.length /= 2;
+ }
+ }
+}
+
+- (CGRect)visibleRect
+{
+ return UIEdgeInsetsInsetRect(self.bounds, _visibleInsets);
+}
+
+- (NSArray *)visibleViews
+{
+ return _visibleViews;
+}
+
+- (NSIndexSet *)indexesForVisibleItems
+{
+ return [NSIndexSet indexSetWithIndexesInRange:_visibleRange];
+}
+
+- (void)scrollToItemAtIndex:(NSUInteger)index atScrollPosition:(JTListViewScrollPosition)scrollPosition animated:(BOOL)animated
+{
+ if (index >= [self numberOfItems])
+ {
+ return;
+ }
+
+ CGPoint offset;
+ CGRect itemRect = [self rectForItemAtIndex:index];
+
+ if (scrollPosition == JTListViewScrollPositionNone)
+ {
+ if (CGRectContainsRect(itemRect, self.bounds))
+ {
+ return;
+ }
+ else if ([self isHorizontalLayout])
+ {
+ if ((itemRect.size.width < self.bounds.size.width && CGRectGetMidX(itemRect) < CGRectGetMidX(self.bounds)) ||
+ (itemRect.size.width > self.bounds.size.width && CGRectGetMidX(itemRect) > CGRectGetMidX(self.bounds)))
+ {
+ offset = CGPointMake(CGRectGetMinX(itemRect), self.contentOffset.y);
+ [self setContentOffset:offset animated:animated];
+ }
+ else if ((itemRect.size.width < self.bounds.size.width && CGRectGetMidX(itemRect) > CGRectGetMidX(self.bounds)) ||
+ (itemRect.size.width > self.bounds.size.width && CGRectGetMidX(itemRect) < CGRectGetMidX(self.bounds)))
+ {
+ offset = CGPointMake(CGRectGetMaxX(itemRect) - self.bounds.size.width, self.contentOffset.y);
+ [self setContentOffset:offset animated:animated];
+ }
+ }
+ else if ([self isVerticalLayout])
+ {
+ if ((itemRect.size.height < self.bounds.size.height && CGRectGetMidY(itemRect) < CGRectGetMidY(self.bounds)) ||
+ (itemRect.size.height > self.bounds.size.height && CGRectGetMidY(itemRect) > CGRectGetMidY(self.bounds)))
+ {
+ offset = CGPointMake(self.contentOffset.x, CGRectGetMinY(itemRect));
+ [self setContentOffset:offset animated:animated];
+ }
+ else if ((itemRect.size.height < self.bounds.size.height && CGRectGetMidY(itemRect) > CGRectGetMidY(self.bounds)) ||
+ (itemRect.size.height > self.bounds.size.height && CGRectGetMidY(itemRect) < CGRectGetMidY(self.bounds)))
+ {
+ offset = CGPointMake(self.contentOffset.x, CGRectGetMaxY(itemRect) - self.bounds.size.height);
+ [self setContentOffset:offset animated:animated];
+ }
+ }
+ }
+ else if (scrollPosition == JTListViewScrollPositionCenter)
+ {
+ if ([self isHorizontalLayout])
+ {
+ offset = CGPointMake((itemRect.origin.x - (self.frame.size.width - itemRect.size.width) / 2), self.contentOffset.y);
+ if (offset.x < 0)
+ {
+ offset.x = 0;
+ }
+ if (offset.x > self.contentSize.width - self.frame.size.width)
+ {
+ offset.x = self.contentSize.width - self.frame.size.width;
+ }
+ }
+ else if ([self isVerticalLayout])
+ {
+ offset = CGPointMake(self.contentOffset.x, itemRect.origin.y - (self.frame.size.height - itemRect.size.height) / 2);
+ if (offset.y < 0)
+ {
+ offset.y = 0;
+ }
+ if (offset.y > self.contentSize.height - self.frame.size.height)
+ {
+ offset.y = self.contentSize.height - self.frame.size.height;
+ }
+ }
+ [self setContentOffset:offset animated:animated];
+ }
+ else if (scrollPosition == JTListViewScrollPositionCenterElseNone)
+ {
+ if (([self isHorizontalLayout] && itemRect.size.width <= self.bounds.size.width) ||
+ ([self isVerticalLayout] && itemRect.size.height <= self.bounds.size.height))
+ {
+ [self scrollToItemAtIndex:index atScrollPosition:JTListViewScrollPositionCenter animated:animated];
+ }
+ else
+ {
+ [self scrollToItemAtIndex:index atScrollPosition:JTListViewScrollPositionNone animated:animated];
+ }
+ }
+}
+
+- (void)goBack:(BOOL)animated
+{
+ switch (_layout)
+ {
+ case JTListViewLayoutLeftToRight: [self goLeft:animated]; break;
+ case JTListViewLayoutRightToLeft: [self goRight:animated]; break;
+ case JTListViewLayoutTopToBottom: [self goUp:animated]; break;
+ case JTListViewLayoutBottomToTop: [self goDown:animated]; break;
+ }
+}
+
+- (void)goForward:(BOOL)animated
+{
+ switch (_layout)
+ {
+ case JTListViewLayoutLeftToRight: [self goRight:animated]; break;
+ case JTListViewLayoutRightToLeft: [self goLeft:animated]; break;
+ case JTListViewLayoutTopToBottom: [self goDown:animated]; break;
+ case JTListViewLayoutBottomToTop: [self goUp:animated]; break;
+ }
+}
+
+- (UIView *)dequeueReusableView
+{
+ UIView *reuseableView = [_reuseableViews anyObject];
+ if (reuseableView)
+ {
+ [[reuseableView retain] autorelease];
+ [_reuseableViews removeObject:reuseableView];
+ }
+ return reuseableView;
+}
+
+
+#pragma mark - UIView
+
+- (void)layoutSubviews
+{
+ [super layoutSubviews];
+
+ static CGSize frameSizeCache = {0.0, 0.0};
+
+ if (!CGSizeEqualToSize(self.frame.size, frameSizeCache))
+ {
+ [self updateItemSizes];
+ frameSizeCache = self.frame.size;
+ }
+ else
+ {
+ [self layoutVisibleItems];
+ }
+}
+
+
+#pragma mark - NSKeyValueObserving
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
+{
+ if (object == self)
+ {
+ if ([keyPath isEqualToString:@"itemWidth"] || [keyPath isEqualToString:@"itemHeight"])
+ {
+ [self updateItemSizes];
+ }
+ else if ([keyPath isEqualToString:@"gapBetweenItems"])
+ {
+ [self layoutItemRects];
+ }
+ }
+}
+
+@end
+
+
+#pragma mark -
+@implementation JTListViewController
+
+@synthesize listView = _listView;
+
+- (void)loadView
+{
+ self.view = self.listView = [[[JTListView alloc] init] autorelease];
+}
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+
+ if (self.listView)
+ {
+ self.listView.dataSource = self;
+ self.listView.delegate = self;
+ }
+}
+
+- (void)viewDidUnload
+{
+ [super viewDidUnload];
+
+ if (self.listView)
+ {
+ self.listView.dataSource = nil;
+ self.listView.delegate = nil;
+ self.listView = nil;
+ }
+}
+
+- (void)viewWillAppear:(BOOL)animated
+{
+ if ([self.listView numberOfItems] == 0)
+ {
+ [self.listView reloadData];
+ }
+}
+
+
+#pragma mark - JTListViewDataSource (Required)
+
+- (NSUInteger)numberOfItemsInListView:(JTListView *)listView
+{
+ return 0;
+}
+
+- (UIView *)listView:(JTListView *)listView viewForItemAtIndex:(NSUInteger)index
+{
+ UIView *view = [listView dequeueReusableView];
+ if (!view)
+ {
+ view = [[[UIView alloc] init] autorelease];
+ }
+ return view;
+}
+
+@end
View
3  JTListView/JTListViewAppDelegate.h
@@ -3,13 +3,12 @@
// JTListView
//
// Created by Jun on 5/6/11.
-// Copyright 2011 東京工科大学. All rights reserved.
+// Copyright 2011 Jun Tanaka. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface JTListViewAppDelegate : NSObject <UIApplicationDelegate> {
-
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
View
35 JTListView/JTListViewAppDelegate.m
@@ -3,66 +3,45 @@
// JTListView
//
// Created by Jun on 5/6/11.
-// Copyright 2011 東京工科大学. All rights reserved.
+// Copyright 2011 Jun Tanaka. All rights reserved.
//
#import "JTListViewAppDelegate.h"
@implementation JTListViewAppDelegate
+@synthesize window = _window;
-@synthesize window=_window;
+- (void)dealloc
+{
+ [_window release];
+ [super dealloc];
+}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
- // Override point for customization after application launch.
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
- /*
- Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
- Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
- */
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
- /*
- Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
- If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
- */
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
- /*
- Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
- */
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
- /*
- Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
- */
}
- (void)applicationWillTerminate:(UIApplication *)application
{
- /*
- Called when the application is about to terminate.
- Save data if appropriate.
- See also applicationDidEnterBackground:.
- */
-}
-
-- (void)dealloc
-{
- [_window release];
- [super dealloc];
}
@end
View
19 JTListView/JTListViewDemoController.h
@@ -0,0 +1,19 @@
+//
+// JTListViewDemoController.h
+// JTListView
+//
+// Created by Jun on 5/8/11.
+// Copyright 2011 Jun Tanaka. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "JTListView.h"
+
+
+@interface JTListViewDemoController : JTListViewController <UIActionSheetDelegate>
+
+- (IBAction)presentDirectionSelector:(id)sender;
+- (IBAction)goBack:(id)sender;
+- (IBAction)goForward:(id)sender;
+
+@end
View
105 JTListView/JTListViewDemoController.m
@@ -0,0 +1,105 @@
+//
+// JTListViewDemoController.m
+// JTListView
+//
+// Created by Jun on 5/8/11.
+// Copyright 2011 Jun Tanaka. All rights reserved.
+//
+
+#import "JTListViewDemoController.h"
+
+
+@implementation JTListViewDemoController
+
+- (void)viewWillAppear:(BOOL)animated
+{
+ [super viewWillAppear:animated];
+
+ //self.listView.gapBetweenItems = 44.0;
+ self.listView.visibleInsets = UIEdgeInsetsMake(-256, -256, -256, -256);
+}
+
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
+{
+ return YES;
+}
+
+- (IBAction)presentDirectionSelector:(id)sender
+{
+ UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Choose Direction" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Left to Right", @"Right to Left", @"Top to Bottom", @"Bottom to Top", nil];
+ [actionSheet showFromToolbar:self.navigationController.toolbar];
+}
+
+- (IBAction)goBack:(id)sender
+{
+ [self.listView goBack:YES];
+}
+
+- (IBAction)goForward:(id)sender
+{
+ [self.listView goForward:YES];
+}
+
+
+#pragma mark - UIActionSheetDelegate
+
+- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
+{
+ JTListViewLayout layout;
+ switch (buttonIndex) {
+ case 0: layout = JTListViewLayoutLeftToRight; break;
+ case 1: layout = JTListViewLayoutRightToLeft; break;
+ case 2: layout = JTListViewLayoutTopToBottom; break;
+ case 3: layout = JTListViewLayoutBottomToTop; break;
+ default: return; break;
+ }
+ self.listView.layout = layout;
+}
+
+
+#pragma mark - JTListViewDataSource
+
+- (NSUInteger)numberOfItemsInListView:(JTListView *)listView
+{
+ return 100;
+}
+
+- (UIView *)listView:(JTListView *)listView viewForItemAtIndex:(NSUInteger)index
+{
+ UIView *view = [listView dequeueReusableView];
+
+ if (!view) {
+ view = [[[UIView alloc] init] autorelease];
+
+ UILabel *label = [[[UILabel alloc] initWithFrame:view.bounds] autorelease];
+ label.center = view.center;
+ label.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+ label.backgroundColor = [UIColor clearColor];
+ label.textColor = [UIColor colorWithWhite:1.0 alpha:1.0];
+ label.font = [UIFont fontWithName:@"Helvetica-Bold" size:24.0];
+ label.textAlignment = UITextAlignmentCenter;
+ label.tag = 1;
+
+ [view addSubview:label];
+ }
+
+ view.backgroundColor = [UIColor colorWithHue:(float)(index % 7) / 7.0 saturation:0.75 brightness:1.0 alpha:1.0];
+ [(UILabel *)[view viewWithTag:1] setText:[NSString stringWithFormat:@"#%u", index]];
+
+ return view;
+}
+
+
+#pragma mark - JTListViewDelegate
+
+- (CGFloat)listView:(JTListView *)listView widthForItemAtIndex:(NSUInteger)index
+{
+ return (CGFloat)(index % 7 * 60 + 60);
+}
+
+- (CGFloat)listView:(JTListView *)listView heightForItemAtIndex:(NSUInteger)index
+{
+ return (CGFloat)(index % 7 * 60 + 60);
+}
+
+@end
View
256 JTListView/en.lproj/MainWindow.xib
@@ -1,18 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10">
<data>
- <int key="IBDocument.SystemTarget">800</int>
- <string key="IBDocument.SystemVersion">10D540</string>
- <string key="IBDocument.InterfaceBuilderVersion">760</string>
- <string key="IBDocument.AppKitVersion">1038.29</string>
- <string key="IBDocument.HIToolboxVersion">460.00</string>
+ <int key="IBDocument.SystemTarget">1056</int>
+ <string key="IBDocument.SystemVersion">10J869</string>
+ <string key="IBDocument.InterfaceBuilderVersion">1306</string>
+ <string key="IBDocument.AppKitVersion">1038.35</string>
+ <string key="IBDocument.HIToolboxVersion">461.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
- <string key="NS.object.0">81</string>
+ <string key="NS.object.0">301</string>
</object>
- <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <object class="NSArray" key="IBDocument.IntegratedClassDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="2"/>
+ <string>IBProxyObject</string>
+ <string>IBUINavigationController</string>
+ <string>IBUIViewController</string>
+ <string>IBUICustomObject</string>
+ <string>IBUIToolbar</string>
+ <string>IBUIWindow</string>
+ <string>IBUIBarButtonItem</string>
+ <string>IBUINavigationBar</string>
+ <string>IBUINavigationItem</string>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -23,9 +31,7 @@
<object class="NSArray" key="dict.sortedKeys" id="0">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
+ <reference key="dict.values" ref="0"/>
</object>
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -46,9 +52,10 @@
<object class="NSPSMatrix" key="NSFrameMatrix"/>
<string key="NSFrameSize">{320, 480}</string>
<reference key="NSSuperview"/>
+ <reference key="NSNextKeyView"/>
<object class="NSColor" key="IBUIBackgroundColor">
- <int key="NSColorSpace">1</int>
- <bytes key="NSRGB">MSAxIDEAA</bytes>
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
</object>
<bool key="IBUIOpaque">NO</bool>
<bool key="IBUIClearsContextBeforeDrawing">NO</bool>
@@ -56,6 +63,76 @@
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<bool key="IBUIResizesToFullScreen">YES</bool>
</object>
+ <object class="IBUINavigationController" id="850127441">
+ <object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
+ <object class="IBUISimulatedOrientationMetrics" key="IBUISimulatedOrientationMetrics">
+ <int key="IBUIInterfaceOrientation">1</int>
+ <int key="interfaceOrientation">1</int>
+ </object>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ <bool key="IBUIHorizontal">NO</bool>
+ <object class="IBUINavigationBar" key="IBUINavigationBar" id="229854155">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrameSize">{0, 0}</string>
+ <bool key="IBUIOpaque">NO</bool>
+ <bool key="IBUIClipsSubviews">YES</bool>
+ <bool key="IBUIMultipleTouchEnabled">YES</bool>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ </object>
+ <object class="IBUIToolbar" key="IBUIToolbar" id="552601387">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{0, 436}, {320, 44}}</string>
+ <reference key="NSSuperview"/>
+ <reference key="NSNextKeyView"/>
+ <bool key="IBUIOpaque">NO</bool>
+ <bool key="IBUIClipsSubviews">YES</bool>
+ <int key="IBUIContentMode">4</int>
+ <bool key="IBUIMultipleTouchEnabled">YES</bool>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ </object>
+ <object class="NSMutableArray" key="IBUIViewControllers">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBUIViewController" id="478299399">
+ <object class="NSArray" key="IBUIToolbarItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBUIBarButtonItem" id="444357647">
+ <string key="IBUITitle">Direction</string>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ <int key="IBUIStyle">1</int>
+ </object>
+ <object class="IBUIBarButtonItem" id="278964179">
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ <int key="IBUISystemItemIdentifier">5</int>
+ </object>
+ <object class="IBUIBarButtonItem" id="544879827">
+ <string key="IBUITitle">Back</string>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ <int key="IBUIStyle">1</int>
+ </object>
+ <object class="IBUIBarButtonItem" id="83540630">
+ <string key="IBUITitle">Forward</string>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ <int key="IBUIStyle">1</int>
+ </object>
+ </object>
+ <object class="IBUINavigationItem" key="IBUINavigationItem" id="486770921">
+ <string key="IBUITitle">JTListView</string>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ </object>
+ <reference key="IBUIParentViewController" ref="850127441"/>
+ <object class="IBUISimulatedToolbarMetrics" key="IBUISimulatedBottomBarMetrics"/>
+ <object class="IBUISimulatedOrientationMetrics" key="IBUISimulatedOrientationMetrics">
+ <int key="IBUIInterfaceOrientation">1</int>
+ <int key="interfaceOrientation">1</int>
+ </object>
+ <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+ <bool key="IBUIHorizontal">NO</bool>
+ </object>
+ </object>
+ <bool key="IBUIToolbarHidden">NO</bool>
+ </object>
</object>
<object class="IBObjectContainer" key="IBDocument.Objects">
<object class="NSMutableArray" key="connectionRecords">
@@ -76,6 +153,38 @@
</object>
<int key="connectionID">5</int>
</object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchOutletConnection" key="connection">
+ <string key="label">rootViewController</string>
+ <reference key="source" ref="380026005"/>
+ <reference key="destination" ref="850127441"/>
+ </object>
+ <int key="connectionID">14</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchEventConnection" key="connection">
+ <string key="label">goBack:</string>
+ <reference key="source" ref="544879827"/>
+ <reference key="destination" ref="478299399"/>
+ </object>
+ <int key="connectionID">26</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchEventConnection" key="connection">
+ <string key="label">goForward:</string>
+ <reference key="source" ref="83540630"/>
+ <reference key="destination" ref="478299399"/>
+ </object>
+ <int key="connectionID">27</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBCocoaTouchEventConnection" key="connection">
+ <string key="label">presentDirectionSelector:</string>
+ <reference key="source" ref="444357647"/>
+ <reference key="destination" ref="478299399"/>
+ </object>
+ <int key="connectionID">28</int>
+ </object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@@ -110,6 +219,68 @@
<reference key="object" ref="427554174"/>
<reference key="parent" ref="0"/>
</object>
+ <object class="IBObjectRecord">
+ <int key="objectID">10</int>
+ <reference key="object" ref="850127441"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="229854155"/>
+ <reference ref="478299399"/>
+ <reference ref="552601387"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">11</int>
+ <reference key="object" ref="229854155"/>
+ <reference key="parent" ref="850127441"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">12</int>
+ <reference key="object" ref="478299399"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="486770921"/>
+ <reference ref="83540630"/>
+ <reference ref="278964179"/>
+ <reference ref="444357647"/>
+ <reference ref="544879827"/>
+ </object>
+ <reference key="parent" ref="850127441"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">13</int>
+ <reference key="object" ref="486770921"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="parent" ref="478299399"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">15</int>
+ <reference key="object" ref="552601387"/>
+ <reference key="parent" ref="850127441"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">17</int>
+ <reference key="object" ref="544879827"/>
+ <reference key="parent" ref="478299399"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">18</int>
+ <reference key="object" ref="83540630"/>
+ <reference key="parent" ref="478299399"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">23</int>
+ <reference key="object" ref="278964179"/>
+ <reference key="parent" ref="478299399"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">16</int>
+ <reference key="object" ref="444357647"/>
+ <reference key="parent" ref="478299399"/>
+ </object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
@@ -118,9 +289,17 @@
<bool key="EncodedWithXMLCoder">YES</bool>
<string>-1.CustomClassName</string>
<string>-2.CustomClassName</string>
+ <string>10.IBPluginDependency</string>
+ <string>11.IBPluginDependency</string>
+ <string>12.CustomClassName</string>
+ <string>12.IBPluginDependency</string>
+ <string>16.IBPluginDependency</string>
+ <string>17.IBPluginDependency</string>
+ <string>18.IBPluginDependency</string>
<string>2.IBAttributePlaceholdersKey</string>
<string>2.IBEditorWindowLastContentRect</string>
<string>2.IBPluginDependency</string>
+ <string>23.IBPluginDependency</string>
<string>3.CustomClassName</string>
<string>3.IBPluginDependency</string>
</object>
@@ -128,15 +307,21 @@
<bool key="EncodedWithXMLCoder">YES</bool>
<string>UIApplication</string>
<string>UIResponder</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>JTListViewDemoController</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<object class="NSMutableDictionary">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
+ <reference key="dict.values" ref="0"/>
</object>
<string>{{198, 376}, {320, 480}}</string>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string>JTListViewAppDelegate</string>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
</object>
@@ -144,46 +329,18 @@
<object class="NSMutableDictionary" key="unlocalizedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
+ <reference key="dict.values" ref="0"/>
</object>
<nil key="activeLocalization"/>
<object class="NSMutableDictionary" key="localizations">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference key="dict.sortedKeys" ref="0"/>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- </object>
+ <reference key="dict.values" ref="0"/>
</object>
<nil key="sourceID"/>
- <int key="maxID">9</int>
- </object>
- <object class="IBClassDescriber" key="IBDocument.Classes">
- <object class="NSMutableArray" key="referencedPartialClassDescriptions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="IBPartialClassDescription">
- <string key="className">JTListViewAppDelegate</string>
- <string key="superclassName">NSObject</string>
- <object class="NSMutableDictionary" key="outlets">
- <string key="NS.key.0">window</string>
- <string key="NS.object.0">UIWindow</string>
- </object>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBProjectSource</string>
- <string key="minorKey">JTListViewAppDelegate.h</string>
- </object>
- </object>
- <object class="IBPartialClassDescription">
- <string key="className">JTListViewAppDelegate</string>
- <string key="superclassName">NSObject</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
- <string key="majorKey">IBUserSource</string>
- <string key="minorKey"/>
- </object>
- </object>
- </object>
+ <int key="maxID">31</int>
</object>
+ <object class="IBClassDescriber" key="IBDocument.Classes"/>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
@@ -191,8 +348,7 @@
<integer value="3100" key="NS.object.0"/>
</object>
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
- <string key="IBDocument.LastKnownRelativeProjectPath">JTListView.xcodeproj</string>
<int key="IBDocument.defaultPropertyAccessControl">3</int>
- <string key="IBCocoaTouchPluginVersion">81</string>
+ <string key="IBCocoaTouchPluginVersion">301</string>
</data>
</archive>
View
2  JTListView/main.m
@@ -3,7 +3,7 @@
// JTListView
//
// Created by Jun on 5/6/11.
-// Copyright 2011 東京工科大学. All rights reserved.
+// Copyright 2011 Jun Tanaka. All rights reserved.
//
#import <UIKit/UIKit.h>
Please sign in to comment.
Something went wrong with that request. Please try again.