UITcrollView里面的UITableViewCell触摸检测

时间:2011-07-09 19:04:01

标签: iphone uitableview uiscrollview

我有8个自定义单元格的tableview。在第8个单元格中,我添加了一个启用了分页的scrollView,这样我就可以显示第1页和第2页(或3,4 ... 10)而不会有非常高的单元格。

问题在于scrollView我不能使用didSelectRowAtIndexPath,因为单元格在scrollView后面,所以我试图检测scrollView点击(不刷卡)。

我玩touchesBegan和touchesEnded,但他们从未被调用过(我知道触摸仅适用于UIView,但也许.....)

非常感谢任何帮助。

谢谢, 最大

5 个答案:

答案 0 :(得分:77)

Apple建议在这种情况下使用技巧,在他们的WWDC 2014 session"高级滚动视图" (参见从8:10开始的演示):

[cell.contentView addSubview:_scrollView];
[_scrollView setUserInteractionEnabled:NO];
[cell.contentView addGestureRecognizer:_scrollView.panGestureRecognizer];

所有需要做的事情,无需覆盖touchesBegan:touchesMoved:和其他人。


我之前使用基于覆盖touchesBegan:touchesMoved:touchesEnded:touchesCancelled:的解决方案,但有时它会导致一种奇怪的行为:当选择某个单元格时,方法{/ 1}}被调用了具有不同indexPath的单元格。

Apple的解决方案到目前为止没有任何副作用,看起来更优雅。

答案 1 :(得分:14)

还有一个优雅的解决方案:

从UIScrollView创建一个SubClass并覆盖以下方法

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [[self superview]touchesBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [[self superview]touchesMoved:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [[self superview]touchesCancelled:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [[self superview]touchesEnded:touches withEvent:event];
}

将每次触摸传递到滚动视图的超级视图,然后调用didSelectRowAtIndexPath。

答案 2 :(得分:5)

解决了子类化uitableviewcell和uiscrollview的问题。

它符合我的需要。希望它可以提供帮助。

最高


myScrollView.h


#import <UIKit/UIKit.h>
@interface myScrollView : UIScrollView {
}

@end

myScrollView.m


#import "myScrollView.h"
@implementation myScrollView


- (id)initWithFrame:(CGRect)frame {

    return [super initWithFrame:frame];
}

- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event 
{   
    NSLog(@"touch scroll");
    // If not dragging, send event to next responder
    if (!self.dragging) 
        [self.nextResponder touchesEnded: touches withEvent:event]; 
    else
        [super touchesEnded: touches withEvent: event];
}

myCell.h


#import <UIKit/UIKit.h>


@interface myCell : UITableViewCell {

}

@end

myCell.m



#import "myCell.h"


@implementation myCell


- (id)initWithFrame:(CGRect)frame {

    return [super initWithFrame:frame];
}

- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event 
{   
    NSLog(@"touch cell");
    // If not dragging, send event to next responder
    [super touchesEnded: touches withEvent: event];
}

RootViewController.h



#import <UIKit/UIKit.h>

@class myCell;
@class myScrollView;

@interface RootViewController : UITableViewController {

    myCell *cell;
    myScrollView *scrollView;
}

@end

RootViewController.m



#pragma mark -
#pragma mark Table view data source

// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}


// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 3;
}


// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";

    // my custom cell
    cell = [[myCell alloc] init];
    if (cell == nil) {
        cell = [[[myCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }


    // the custom scroll view
    scrollView = [[myScrollView alloc] initWithFrame:cell.frame];
    scrollView.contentSize = CGSizeMake(640, 40);
    [cell.contentView addSubview:scrollView];

    //something to add in scrollView
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 150, 20)];
    label.text = @"some text";
    [scrollView addSubview:label];

    // Configure the cell.

    return cell;
}

答案 3 :(得分:4)

所选答案是正确的,但我根据我遇到的错误更新了代码。

在子类滚动视图中添加以下代码。

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    if (self.dragging) {
        [super touchesMoved:touches withEvent:event];
    } else {
        if ([self.delegate isKindOfClass:[UITableViewCell class]]) {
            [(UITableViewCell *)self.delegate touchesCancelled:touches withEvent:event];
        }

        [self.superview touchesMoved:touches withEvent:event];
    }
}

如果您的self.delegate不是UITableViewCell,请将该属性替换为您的单元格。

单元需要在移动期间检索取消触摸事件以防止不期望的结果。它可以很容易地重现如下。

  • 突出显示单元格(假设滚动视图位于整个单元格上,如果不突出显示滚动视图)
  • 单元格突出显示时,拖动表格视图
  • 选择任何其他单元格,现在之前突出显示的单元格将检索didSelectCell

另一点需要提及的是订单很重要!如果在self.delegate之前未调用self.superview,则突出显示的状态不会发生。

答案 4 :(得分:0)

我找到了满足我需求的最简单的解决方案:

子类UIScrollView touchesEnded方法并发布通知。

在UITableview中,在viewdidAppear中添加一个观察者(在viewdiddisappear中删除它)以调用一个调用tableview didSelectRowForIndexPath的函数。

像这样的东西(快速版)

// myScrollView.swift

import UIKit

class myScrollView: UIScrollView {
    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
            NSNotificationCenter.defaultCenter().postNotificationName("selectTVRow", object: nil)
    }
}

在你的tableView中:

// ItemsList.swift

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "selectFourthRow", name: "selectTVRow", object: nil)
    }

    override func viewDidDisappear(animated: Bool) {
        super.viewDidDisappear(animated)
        NSNotificationCenter.defaultCenter().removeObserver(self, name: "selectfourthrow", object: nil)
    }

    func selectFourthRow() {
        let rowToSelect:NSIndexPath = NSIndexPath(forRow: 4, inSection: 0);
        self.tableView(self.tableView, didSelectRowAtIndexPath: rowToSelect);
    }

    /*
    .... rest of your tableview Datasource and Delegate methods...
    numberOfSectionsInTableView, numberOfRowsInSection, cellForRowAtIndexPath
    */