UIScrollView inside UITableViewCell touch detect

后端 未结 5 1474
清歌不尽
清歌不尽 2020-12-04 20:16

I have a tableview with 8 custom cells. in the 8th cell I added a scrollView with paging enabled so I can show page 1 and page 2 (or 3, 4... 10) without have a very high cel

相关标签:
5条回答
  • 2020-12-04 20:24

    I found the simplest solution for my needs:

    subclass UIScrollView touchesEnded method and post a notification.

    In the UITableview add an observer in viewdidAppear (remove it in viewdiddisappear) to call a function that call tableview didSelectRowForIndexPath.

    Something like this (swift version)

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

    In your 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
        */
    
    0 讨论(0)
  • 2020-12-04 20:26

    There is a trick Apple recommends to use in this case, in theirs WWDC 2014 session "Advanced scrollviews" (See Demo starting from 8:10):

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

    That's all what needs to be done, no need to override touchesBegan:, touchesMoved: and others.


    I used solution based on overriding of touchesBegan:, touchesMoved:, touchesEnded: and touchesCancelled: previously, but sometimes it caused a weird behaviour: when select a certain cell, method -tableView:didSelectRowAtIndexPath: was called for cell with different indexPath.

    Solution from Apple has no side effects so far and looks more elegant.

    0 讨论(0)
  • 2020-12-04 20:26

    There is also an elegant resolution:

    Create a SubClass from UIScrollView and override the following methods

    - (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];
    }
    

    Passing every touch to the superview of the scroll view and then the didSelectRowAtIndexPath will be called.

    0 讨论(0)
  • 2020-12-04 20:35

    The selected answer is correct, but I updated the code based on a bug I was getting.

    In the subclassed scroll view add the following code.

    - (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];
        }
    }
    

    If your self.delegate is not the UITableViewCell, than replace that property with a property to your cell.

    The cell needs to retrieve the cancel touch event during movement to prevent the undesired results. It can be easily reproducible as follows.

    • Highlight the cell (assuming the scroll view is over the whole cell, if not highlight the scroll view)
    • While the cell is highlighted, drag the table view
    • Select any other cell and now the previously highlighted cell will retrieve the didSelectCell state

    Another point to mention is that order matters! If the self.delegate is not called before the self.superview then the highlighted state wont happen.

    0 讨论(0)
  • 2020-12-04 20:42

    Solved subclassing both uitableviewcell and uiscrollview.

    It worked for my needs. Hope it can help.

    Max


    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;
    }
    
    0 讨论(0)
提交回复
热议问题