【问题标题】:UIScrollView inside UITableViewCell touch detectUITableViewCell 内的 UIScrollView 触摸检测
【发布时间】:2011-10-01 23:38:32
【问题描述】:

我有一个包含 8 个自定义单元格的表格视图。在第 8 个单元格中,我添加了一个启用分页的滚动视图,这样我就可以显示第 1 页和第 2 页(或 3、4...10),而无需非常高的单元格。

问题在于滚动视图,我无法使用 didSelectRowAtIndexPath,因为单元格位于滚动视图后面,所以我试图检测滚动视图的点击(不是滑动)。

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

非常感谢任何帮助。

谢谢, 最大

【问题讨论】:

    标签: iphone uitableview uiscrollview


    【解决方案1】:

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

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

    这就是所有需要做的,不需要覆盖touchesBegan:touchesMoved:和其他。


    我使用的解决方案基于touchesBegan:touchesMoved:touchesEnded:touchesCancelled:以前,但有时它引起了一个奇怪的行为:选择某个单元格时,-tableView:didSelectRowAtIndexPath:呼叫小区@ 987654329不同的 indexPath。

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

    【讨论】:

    • 此解决方案的唯一缺点是它禁用了滚动视图内任何UIButtons 的交互。我自己又使用了touchesBegan:touchesEnded:
    • 此解决方案提供与普通 tableview 单元格相同的选择特性,因此只要滚动视图中的任何内容都不需要启用用户交互,它就是最好的。
    • 这绝对是一种更好的方式。
    • 效果很好!覆盖 touchesBegan 会导致长按时出现奇怪的选择故障。
    • 你拯救了我的一天
    【解决方案2】:

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

    从 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。

    【讨论】:

    • 这是迄今为止解决这个问题最好和最优雅的解决方案。谢谢!
    • 我想知道如果单元格中也有按钮,这将如何工作?
    • 问题是ScrollView的touch不会传递给它的父view,所以解决方法是把所有touch阶段的每一个touch都传递给它的父view。你不需要担心按钮,它首先接收到触摸事件。
    • 我在滚动视图后面有一个按钮,但它没有收到触摸... Ofc 的解决方案是将按钮放在滚动视图内
    • 如果你不想把按钮放在滚动视图里面,解决方法会比较复杂,你可以检测触摸是否在按钮区域内,如果是,将触摸传递给按钮而不是超级视图
    【解决方案3】:

    解决了 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;
    }
    

    【讨论】:

      【解决方案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 之前被调用,那么高亮状态就不会发生。

      【讨论】:

      • 谢谢。我从未遇到过该错误,因为无法选择我的单元格。我点击它并呈现一个新视图,因此在选择/突出显示单元格时我无法移动表格。谢谢,马克斯
      【解决方案5】:

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

      继承 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
          */
      

      【讨论】:

        猜你喜欢
        • 2013-04-12
        • 1970-01-01
        • 2016-02-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-25
        相关资源
        最近更新 更多