2013-08-07 84 views
0

我正在使用一個插件爲可滾動圖層。它有兩個文件,如下所示。[__NSCFString setPosition:]:無法識別的選擇器發送到實例

FGScrollLayer.h

#import <Foundation/Foundation.h> 
#import "cocos2d.h" 

@class FGScrollLayer; 
@protocol FGScrollLayerDelegate 

@optional 

/** Called when scroll layer begins scrolling. 
* Usefull to cancel CCTouchDispatcher standardDelegates. 
*/ 
- (void) scrollLayerScrollingStarted:(FGScrollLayer *) sender; 

/** Called at the end of moveToPage: 
*/ 
- (void) scrollLayer: (FGScrollLayer *) sender scrolledToPageNumber: (int) page; 

@end 

/** Vertical scrolling layer for items. 
* 
* It is a very clean and elegant subclass of CCLayer that lets you pass-in an array 
* of layers and it will then create a smooth scroller. 
* Every sub-layer should have the same size in current version. 
* 
* @version 0.1.01 
*/ 
@interface FGScrollLayer : CCLayer 
{ 
    NSObject <FGScrollLayerDelegate> *delegate_; 

    // The screen coord of initial point the user starts their swipe. 
    CGFloat startSwipe_; 

    // The coord of initial position the user starts their swipe. 
    CGFloat startSwipeLayerPos_; 

    // For what distance user must slide finger to start scrolling menu. 
    CGFloat minimumTouchLengthToSlide_; 

    // Internal state of scrollLayer (scrolling or idle). 
    int state_; 

    BOOL stealTouches_; 

#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED 
    // Holds the touch that started the scroll 
    UITouch *scrollTouch_; 
#endif 

    // Holds pages. 
    NSMutableArray *layers_; 

    // Holds current pages width offset. 
    CGFloat pagesOffset_; 

    // Holds the height of every page 
    CGFloat pageHeight_; 

    // Holds the width of every page 
    CGFloat pageWidth_; 

    // Holds the maximum upper position 
    CGFloat maxVerticalPos_; 

    // Holds the real responsible rect in the screen 
    CGRect realBound; 

    /*Decoration and slide bars*/ 
    // Scroll bars on the right 
    CCSprite* scrollBar; 
    CGFloat scrollBarPosY; 

    // Scroll block that indicates the current position in whole scorll view content 
    CCSprite* scrollBlock; 
    CGFloat scrollBlockUpperBound; 
    CGFloat scrollBlockLowerBound; 

    // Decoration 
    // Holds position to maintain their position fixed even in setPosition 
    CCSprite* upperBound; 
    CGFloat upperBoundPosY; 
    CCSprite* lowerBound; 
    CGFloat lowerBoundPosY; 
} 

@property (readwrite, assign) NSObject <FGScrollLayerDelegate> *delegate; 

#pragma mark Scroll Config Properties 

/** Calibration property. Minimum moving touch length that is enough 
* to cancel menu items and start scrolling a layer. 
*/ 
@property(readwrite, assign) CGFloat minimumTouchLengthToSlide; 

/** If YES - when starting scrolling FGScrollLayer will claim touches, that are 
* already claimed by others targetedTouchDelegates by calling CCTouchDispatcher#touchesCancelled 
* Usefull to have ability to scroll with touch above menus in pages. 
* If NO - scrolling will start, but no touches will be cancelled. 
* Default is YES. 
*/ 
@property(readwrite) BOOL stealTouches; 

#pragma mark Pages Control Properties 

/** Offset, that can be used to let user see next/previous page. */ 
@property(readwrite) CGFloat pagesOffset; 

/** Page height, this version requires that each page shares the same height and width */ 
@property(readonly) CGFloat pageHeight; 
@property(readonly) CGFloat pageWidth; 

/** Returns array of pages CCLayer's */ 
@property(readonly) NSArray *pages; 
- (void) updatePages; 
-(void)updatePagesAvailability; 
#pragma mark Init/Creation 

/** Creates new scrollLayer with given pages & width offset. 
* @param layers NSArray of CCLayers, that will be used as pages. 
* @param pageSize indicates the size of every page, now this version requires each page 
* share the same page size 
* @param widthOffset Length in X-coord, that describes length of possible pages 
* @param visibleRect indicates the real position and size on the screen 
* intersection. */ 
+(id) nodeWithLayers:(NSArray *)layers pageSize:(CGSize)pageSize pagesOffset: (int) pOffset visibleRect: (CGRect)rect; 

/** Inits scrollLayer with given pages & width offset. 
* @param layers NSArray of CCLayers, that will be used as pages. 
* @param pageSize indicates the size of every page, now this version requires each page 
* share the same page size 
* @param pagesOffset Length in X-coord, that describes length of possible pages 
* @param visibleRect indicates the real position and size on the screen 
* intersection. */ 
-(id) initWithLayers:(NSArray *)layers pageSize:(CGSize)pageSize pagesOffset: (int) pOffset visibleRect: (CGRect)rect; 

#pragma mark Misc 
/** 
* Return the number of pages 
*/ 
-(int) totalPagesCount; 

#pragma mark Moving/Selecting Pages 

/* Moves scrollLayer to page with given number. 
* Does nothing if number >= totalScreens or < 0. 
*/ 
-(void) moveToPage:(int)page; 

@end 

FGScrollLayer.m

// 
// FGScrollLayer.m 
// Fall G 
// 
// Created by Dai Xuefeng on 23/9/12. 
// Copyright 2012 Nofootbird. 
// 

#import "FGScrollLayer.h" 


enum 
{ 
    kFGScrollLayerStateIdle, 
    kFGScrollLayerStateSliding, 
}; 

#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED 
@interface CCTouchDispatcher (targetedHandlersGetter) 

- (id<NSFastEnumeration>) targetedHandlers; 

@end 

@implementation CCTouchDispatcher (targetedHandlersGetter) 

- (id<NSFastEnumeration>) targetedHandlers 
{ 
    return targetedHandlers; 
} 

@end 
#endif 

@implementation FGScrollLayer 

@synthesize delegate = delegate_; 
@synthesize minimumTouchLengthToSlide = minimumTouchLengthToSlide_; 
@synthesize pagesOffset = pagesOffset_; 
@synthesize pages = layers_; 
@synthesize stealTouches = stealTouches_; 
@synthesize pageHeight = pageHeight_; 
@synthesize pageWidth = pageWidth_; 

- (int) totalPagesCount 
{ 
    return [layers_ count]; 
} 

+(id) nodeWithLayers:(NSArray *)layers pageSize:(CGSize)pageSize pagesOffset:(int)pOffset visibleRect:(CGRect)rect{ 
    return [[[self alloc] initWithLayers: layers pageSize:pageSize pagesOffset:pOffset visibleRect:rect] autorelease]; 
} 

-(id) initWithLayers:(NSArray *)layers pageSize:(CGSize)pageSize pagesOffset:(int)pOffset visibleRect:(CGRect)rect{ 
    if ((self = [super init])) 
    { 
     NSAssert([layers count], @"FGScrollLayer#initWithLayers:widthOffset: you must provide at least one layer!"); 

     // Enable Touches/Mouse. 
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED 
     self.isTouchEnabled = YES; 
#endif 

     self.stealTouches = YES; 

     // Set default minimum touch length to scroll. 
     self.minimumTouchLengthToSlide = 30.0f; 

     // Save offset. 
     self.pagesOffset = pOffset; 

     // Save array of layers. 
     layers_ = [[NSMutableArray alloc] initWithArray:layers copyItems:NO]; 

     // Save pages size for later calculation 
     pageHeight_ = pageSize.height; 
     pageWidth_ = pageSize.width; 
     maxVerticalPos_ = pageHeight_ * [layers_ count] - rect.size.height + 5; 

     realBound = rect; 

     [self updatePages]; 
    } 
    return self; 
} 

- (void) dealloc 
{ 
    self.delegate = nil; 

    [layers_ release]; 
    layers_ = nil; 

    [super dealloc]; 
} 

- (void) updatePages 
{ 
    // Loop through the array and add the screens if needed. 
    int i = 0; 
    for (CCLayer *l in layers_) 
    { 
     l.position = ccp(realBound.origin.x, realBound.origin.y + (realBound.size.height - i * (pageHeight_ - self.pagesOffset))); 
     if (!l.parent){ 
      [self addChild:l]; 
     } 

     i++; 
    } 
    [self updatePagesAvailability]; 
} 

/** 
* According to current position, decide which pages are visible 
*/ 
-(void)updatePagesAvailability{ 
    CGPoint currentPos = [self position]; 
    if (currentPos.y > 0) { 
     int visibleBoundUp = currentPos.y/pageHeight_; 
     visibleBoundUp = MIN([layers_ count], visibleBoundUp); 
     for (int i = 0; i < visibleBoundUp; i++) { 
      [[layers_ objectAtIndex:i] setVisible:NO]; 
     } 
     if (visibleBoundUp < [layers_ count]) { 
      int visibleBoundDown = (currentPos.y + realBound.size.height)/pageHeight_; 
      visibleBoundDown = MIN([layers_ count] - 1, visibleBoundDown); 
      for (int i = visibleBoundUp; i <= visibleBoundDown; i++) { 
       [[layers_ objectAtIndex:i] setVisible:YES]; 
      } 
      if (visibleBoundDown < [layers_ count] - 1) { 
       for (int i = visibleBoundDown + 1; i <= [layers_ count] - 1; i++) { 
        [[layers_ objectAtIndex:i] setVisible:NO]; 
       } 
      } 
     } 
    } 
    else if (currentPos.y <= 0){ 
     CGFloat gapY = -currentPos.y; 
     int visibleBound = (realBound.size.height - gapY)/pageHeight_; 
     // index visibleBound itself should be invisible 
     if (visibleBound < 0) { 
      for (int i = 0; i < [layers_ count]; i++) { 
       [[layers_ objectAtIndex:i] setVisible:NO]; 
      } 
      return; 
     } 
     visibleBound = MIN([layers_ count] - 1, visibleBound); 
     for (int i = 0; i <= visibleBound; i++) { 
      [[layers_ objectAtIndex:i] setVisible:YES]; 
     } 
     for (int i = visibleBound + 1; i < [layers_ count]; i++) { 
      [[layers_ objectAtIndex:i] setVisible:NO]; 
     } 
    } 
} 

-(void)setRealBound:(CGPoint)position size:(CGPoint)size{ 
    realBound = CGRectMake(position.x, position.y, size.x, size.y); 
} 

-(void)setPosition:(CGPoint)position{ 
    [super setPosition:position]; 
    [self updatePagesAvailability]; 
    CGFloat scrollBlockDesiredY = scrollBlockUpperBound - (scrollBlockUpperBound - scrollBlockLowerBound) * position.y/maxVerticalPos_; 
    if (scrollBlockDesiredY > scrollBlockUpperBound) { 
     scrollBlockDesiredY = scrollBlockUpperBound; 
    }else if (scrollBlockDesiredY < scrollBlockLowerBound){ 
     scrollBlockDesiredY = scrollBlockLowerBound; 
    } 
    [scrollBlock setPosition:ccp([scrollBlock position].x, scrollBlockDesiredY - position.y)]; 
    [lowerBound setPosition:ccp([lowerBound position].x, lowerBoundPosY - position.y)]; 
    [upperBound setPosition:ccp([upperBound position].x, upperBoundPosY - position.y)]; 
    [scrollBar setPosition:ccp([scrollBar position].x, scrollBarPosY - position.y)]; 
} 

#pragma mark Moving To/Selecting Pages 

-(void) moveToPage:(int)page 
{ 
    if (page < 0 || page >= [layers_ count]) { 
     CCLOGERROR(@"FGScrollLayer#moveToPage: %d - wrong page number, out of bounds. ", page); 
     return; 
    } 

    CGFloat desiredPos = page * pageHeight_; 
    if (desiredPos > maxVerticalPos_) { 
     desiredPos = maxVerticalPos_; 
    } 

    [self runAction:[CCMoveTo actionWithDuration:0.3 position:ccp([self position].x, desiredPos)]]; 

} 

#pragma mark Touches 
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED 

/** Register with more priority than CCMenu's but don't swallow touches. */ 
-(void) registerWithTouchDispatcher 
{ 
#if COCOS2D_VERSION >= 0x00020000 
    CCTouchDispatcher *dispatcher = [[CCDirector sharedDirector] touchDispatcher]; 
    int priority = kCCMenuHandlerPriority - 1; 
#else 
    CCTouchDispatcher *dispatcher = [CCTouchDispatcher sharedDispatcher]; 
    int priority = kCCMenuTouchPriority - 1; 
#endif 

    [dispatcher addTargetedDelegate:self priority: priority swallowsTouches:NO]; 
} 

/** Hackish stuff - stole touches from other CCTouchDispatcher targeted delegates. 
Used to claim touch without receiving ccTouchBegan. */ 
- (void) claimTouch: (UITouch *) aTouch 
{ 
#if COCOS2D_VERSION >= 0x00020000 
    CCTouchDispatcher *dispatcher = [[CCDirector sharedDirector] touchDispatcher]; 
#else 
    CCTouchDispatcher *dispatcher = [CCTouchDispatcher sharedDispatcher]; 
#endif 

    // Enumerate through all targeted handlers. 
    for (CCTargetedTouchHandler *handler in [dispatcher targetedHandlers]) 
    { 
     // Only our handler should claim the touch. 
     if (handler.delegate == self) 
     { 
      if (![handler.claimedTouches containsObject: aTouch]) 
      { 
       [handler.claimedTouches addObject: aTouch]; 
      } 
     } 
     else 
     { 
      // Steal touch from other targeted delegates, if they claimed it. 
      if ([handler.claimedTouches containsObject: aTouch]) 
      { 
       if ([handler.delegate respondsToSelector:@selector(ccTouchCancelled:withEvent:)]) 
       { 
        [handler.delegate ccTouchCancelled: aTouch withEvent: nil]; 
       } 
       [handler.claimedTouches removeObject: aTouch]; 
      } 
     } 
    } 
} 

-(void)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event 
{ 
    [scrollBar setVisible:NO]; 
    [scrollBlock setVisible:NO]; 

    if(scrollTouch_ == touch) { 
     scrollTouch_ = nil; 
    } 
} 

// these two variables are to make a sliding effect on scroll view 
static CGFloat previousTouchPointY = -1; 
static CGFloat moveSpeed = 0; 
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event 
{ 
    if(scrollTouch_ == nil) { 
     scrollTouch_ = touch; 
    } else { 
     return NO; 
    } 

    CGPoint touchPoint = [touch locationInView:[touch view]]; 
    touchPoint = [[CCDirector sharedDirector] convertToGL:touchPoint]; 

    startSwipe_ = touchPoint.y; 
    startSwipeLayerPos_ = [self position].y; 
    state_ = kFGScrollLayerStateIdle; 
    return YES; 
} 

- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event 
{ 
    if(scrollTouch_ != touch) { 
     return; 
    } 

    CGPoint touchPoint = [touch locationInView:[touch view]]; 
    touchPoint = [[CCDirector sharedDirector] convertToGL:touchPoint]; 


    // If finger is dragged for more distance then minimum - start sliding and cancel pressed buttons. 
    // Of course only if we not already in sliding mode 
    if ((state_ != kFGScrollLayerStateSliding) 
     && (fabsf(touchPoint.y-startSwipe_) >= self.minimumTouchLengthToSlide)) 
    { 
     state_ = kFGScrollLayerStateSliding; 

     // Avoid jerk after state change. 
     startSwipe_ = touchPoint.y; 
     startSwipeLayerPos_ = [self position].y; 
     previousTouchPointY = touchPoint.y; 

     if (self.stealTouches) 
     { 
      [self claimTouch: touch]; 
     } 

     if ([self.delegate respondsToSelector:@selector(scrollLayerScrollingStarted:)]) 
     { 
      [self.delegate scrollLayerScrollingStarted: self]; 
     } 
    } 

    if (state_ == kFGScrollLayerStateSliding) 
    { 
     CGFloat desiredY = startSwipeLayerPos_ + touchPoint.y - startSwipe_; 
     [self setPosition:ccp(0, desiredY)]; 

     // enable scroll bar to be visible 
     [scrollBar setVisible:YES]; 
     [scrollBlock setVisible:YES]; 

     // update scrolling effect variables 
     moveSpeed = touchPoint.y - previousTouchPointY; 
     previousTouchPointY = touchPoint.y; 
    } 
} 

/** 
* After touching, generate an inertia effect. 
*/ 
- (void)moveToDesiredPos:(CGFloat)desiredY{ 
    CCAction* slidingAction = nil; 
    if (desiredY > maxVerticalPos_) { 
     slidingAction = [CCSequence actions:[CCMoveTo actionWithDuration:0.10 position:ccp([self position].x, desiredY)], [CCMoveTo actionWithDuration:0.15 position:ccp([self position].x, maxVerticalPos_)], nil]; 
    } 
    else if (desiredY < 0){ 
     slidingAction = [CCSequence actions:[CCMoveTo actionWithDuration:0.10 position:ccp([self position].x, desiredY)],[CCMoveTo actionWithDuration:0.15 position:ccp([self position].x, 0)], nil]; 
    } 
    else{ 
     CGFloat interPosY = (desiredY - [self position].y) * 0.7 + [self position].y; 
     slidingAction = [CCSequence actions:[CCMoveTo actionWithDuration:0.15 position:ccp([self position].x, interPosY)],[CCMoveTo actionWithDuration:0.3 position:ccp([self position].x, desiredY)], nil]; 
    } 
    [self runAction:slidingAction]; 
} 

- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event 
{ 
    [scrollBar setVisible:NO]; 
    [scrollBlock setVisible:NO]; 

    if(scrollTouch_ != touch) 
     return; 
    scrollTouch_ = nil; 

    if (ABS(moveSpeed) > 10) { 
     CGFloat desiredDesY = [self position].y + moveSpeed * 5; 
     [self moveToDesiredPos:desiredDesY]; 
    } 
    else{ 
     if ([self position].y > maxVerticalPos_) { 
      [self runAction:[CCMoveTo actionWithDuration:0.3 position:ccp([self position].x, maxVerticalPos_)]]; 
     }else if ([self position].y < 0){ 
      [self runAction:[CCMoveTo actionWithDuration:0.3 position:ccp([self position].x, 0)]]; 
     } 
    } 

    // restore scrolling effect variables to default value 
    moveSpeed = 0; 
    previousTouchPointY = -1; 
} 

#endif 

@end 

現在在我的HelloWorldLayer.m初始化我喜歡下面:

-(id) init 
{ 
    if((self=[super init])) { 
     NSMutableArray *persons = [NSMutableArray array]; 
     for (int i = 0; i < 10; i++) { 
      [persons addObject:[NSString stringWithFormat:@"%d",i]]; 
     } 

     NSArray *arrayOfPersons = [NSArray arrayWithArray:persons]; 

     //scrollNode.position = ccp(0, 0); 


     scrollNode = [FGScrollLayer nodeWithLayers:arrayOfPersons pageSize:CGSizeMake(100, 20) pagesOffset:1 visibleRect:CGRectMake(30, 30, 500, 900)]; 




    } 
    return self; 
} 

但它給錯誤:- [__ NSCFString setPosition兩種:]:無法識別的選擇發送到實例0x960e170

我搜索了這個錯誤,我才知道,這是基本子類的錯誤。, 任何人都可以指導我解決這個問題嗎?

回答

3

您創建了一組人員。他們都是NSString對象。您將該數組(在不必要地複製之後)傳遞給需要一組CCLayer對象的滾動層類。

相關問題