2014-02-15 45 views
1

我有一個簡單的情況。 UICollectionView和定製UICollectionViewCellUICollectionView有一個導航欄。自定義單元格有一個圖像。當圖像被點擊時,我想將第二個控制器推到導航堆棧。我將自來水手勢添加到自定義視圖內的圖像上。我如何從單元格訪問父控制器中的導航欄?或者我應該將點擊單擊手勢添加到UICollectionView而不是UICollectionViewCell單元?如何從視角向控制器講話輕拍手勢

self.templateImage.userInteractionEnabled = YES; 
self.userInteractionEnabled = YES; 
UITapGestureRecognizer *tapGestureRecog = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSelect:)]; 
[self.templateImage addGestureRecognizer:tapGestureRecog]; 
[self addGestureRecognizer:tapGestureRecog]; 

templateImage是單元格內的圖像。該代碼在UICollectionViewCellinitWithCoder方法中調用。所以我想我的問題是如何從視圖訪問控制器。通常這將通過IBAction完成。新手到iOS :)

+0

爲什麼要訪問單元格中的Nav BAr?訪問viewcontroller。 – preetam

+0

在選擇器中顯示代碼以便我們知道您的需求 – preetam

+3

一個手勢識別器應該只綁定到一個視圖。 – KudoCC

回答

1

正如其他答案中提到的,you can only attach a gesture recognizer to one view

你總是可以有UICollectionView手勢識別添加到集合觀察室中cellForItemAtIndexPath:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ 
    CustomCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCustomCollectionViewCellIdentifier forIndexPath:indexPath]; 
    if (cell.contentView.gestureRecognizers.count == 0) { 
     [cell.contentView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(myViewWasTapped:)]]; 
    } 

    return cell; 
} 

如果用這種方法去,你必須確保你不會持續手勢識別器添加到如果單元格被重用,則是同一個單元格。您可以檢查視圖的gestureRecognizers屬性以查看單元格的contentView是否已具有手勢識別器。

當點擊單元格時,您可以訪問通過傳遞到您的方法myViewWasTapped:(UIGestureRecognizer *)sender中的gestureRecognizer的view屬性點擊的視圖。

另一種方法是使用委託,這是一種在iOS中傳遞信息的流行方法。如果您繼承UICollectionViewCell,則可以爲單元的「委託」聲明一個協議。基本上,這只是一個對象應該實現的所有方法的列表,如果它想成爲單元的委託的話。在你的UICollectionViewCell h文件中,你可以用下面的方式聲明協議。

@class CustomCardCollectionViewCell; 

@protocol CustomCollectionViewCellDelegate <NSObject> 
@required 
- (void)customCollectionViewCellWasTapped:(CustomCollectionViewCell *)cell; 
@end 

然後在你的單元格的界面中,你會聲明一個名爲delegate的屬性(儘管你可以稱它爲任何你想要的)。代表的類型爲id,它符合協議CustomCollectionViewCellDelegate或您決定調用協議的任何內容。

@interface CustomCollectionViewCell : UICollectionViewCell 
    @property (weak, nonatomic) id<CustomCollectionViewCellDelegate> delegate; 

    //Other interface declaration stuffs. 
@end 

重要的是,UICollectionView則要設置單元格的委託財產是自己時,它會創建細胞。你可以把它看作是一個返回指針(這就是爲什麼委託屬性被聲明爲弱)到CustomCollectionViewCell的UICollectionView。

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ 
    CustomCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCustomCollectionViewCellIdentifier forIndexPath:indexPath]; 
    cell.delegate = self; 

    return cell; 
} 

委託的好處是委託不必是任何特定類型的對象,除非符合您定義的協議。因此,您不需要自定義單元來了解任何其他類。萬歲!

當單元格的手勢識別器檢測到敲擊時,您還需要記住讓單元調用它的委託方法。

[self.delegate customCollectionViewCellWasTapped:self]; 

跟進質詢,

如果需要檢測該小區的特定子視圖被竊聽,有解決該問題的一些方法。一種方法是將子視圖作爲UICollectionViewCell的子類中的公共屬性(可能只是readonly)公開,並將UIGestureRecognizer直接附加到該子視圖,以便僅在觸擊子視圖時觸發。假設該子視圖是指示最愛的星形按鈕。這可以通過以下方式完成。

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ 
    CustomCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCustomCollectionViewCellIdentifier forIndexPath:indexPath]; 
    if (cell.contentView.gestureRecognizers.count == 0) { 
     [cell.starView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(starWasTapped:)]]; 
    } 

    return cell; 
} 

或者,您可以將委託方法添加到委託協議中。像

- (void)customCollectionCell:(CustomCollectionViewCell *)cell starViewWasTapped:(UIView *)starView 

如果你使用這種方法的東西,你既可以有CustomCollectionViewCell重視它的手勢識別直接嚮明星視圖或手勢識別器連接到電池的內容查看並計算是否手勢識別的locationInView屬於starView的框架內。

您應該避免將手勢識別器添加到內容視圖,並讓UICollectionView計算單元格內的觸摸位置以確定是否輕敲了該星形。原因是這需要UICollectionView知道單元的contentView中的星的位置。每個視圖都應該負責其子視圖的位置。

如果明星是UIButton,則可以完全放棄UIGestureRecognizer,方法是在按鈕上設置標籤屬性,然後讓UICollectionView將它自己添加爲按鈕上的目標。然後,您可以通過檢查與該操作一起發送的按鈕的標籤屬性來確定在哪個單元中點擊了哪個按鈕。

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ 
    CustomCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCustomCollectionViewCellIdentifier forIndexPath:indexPath]; 
    [cell.starButton addTarget:self action:@selector(starButtonWasTapped:) forControlEvents:UIControlEventTouchUpInside]; 
    cell.starButton.tag = indexPath.row; 

    return cell; 
} 

- (void)starButtonWasTapped:(UIButton *)starButton { 
    //Do something based off of the tag of the button. 
} 
+1

好的答案!我會添加一個條件來查看是否存在實際的「委託」,並且是否實施了該方法,以避免崩潰。 – jbouaziz

+0

檢查是否有委託是沒有必要的,因爲向nil發送消息在Objective C中不做任何事情,所以它不會導致崩潰。檢查對象是否符合選擇器可能是好的,但是該方法聲明爲「@ required」,因此如果委託實際上未實現根據需要聲明的方法,則可能需要引發錯誤。 –

+0

謝謝@TylerCloutier。進一步的問題:如果用例是爲了識別單元格中特定的子視圖。例如,如果單元格中有一個星標按鈕將單元格標記爲最喜歡的單元格,則需要確定該單元格是否被按下或其他內容。一種解決方案是從識別器獲取水龍頭的位置,然後看它是否落在恆星的框架/邊界內。如果是的話,這個明星被挖掘出來。在我的情況下,圖像佔用了所有的單元格,所以你以前的答案是有效的。但我爲了學習而進行概括。謝謝 ! –