UIScrollView внутри сенсорного обнаружения UITableViewCell
У меня есть таблица с 8 пользовательскими ячейками. в 8-й ячейке я добавил scrollView с пейджингом, поэтому я могу показать страницы 1 и 2 (или 3, 4... 10) без очень высокой ячейки.
Проблема с scrollView я не могу использовать didSelectRowAtIndexPath, потому что ячейка находится за scrollView, поэтому я пытаюсь обнаружить scrollView (не прокручивать).
Я играл с touchBegan и касалсяEnded, но они никогда не называются (я знаю, что касается работы только с UIView, но может быть.....)
Любая помощь очень ценится.
Спасибо,
Макс
Ответы
Ответ 1
Я нашел самое простое решение для своих нужд:
Подкласс UIScrollView коснулся метода и отправил уведомление.
В 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
*/
Ответ 2
Существует трюк, который Apple рекомендует использовать в этом случае в своем сеансе WWDC 2014 "Расширенные просмотры прокрутки" (см. демонстрацию, начинающуюся с 8:10):
[cell.contentView addSubview:_scrollView];
[_scrollView setUserInteractionEnabled:NO];
[cell.contentView addGestureRecognizer:_scrollView.panGestureRecognizer];
Чтобы все, что нужно сделать, не нужно переопределять touchesBegan:
, touchesMoved:
и другие.
Я использовал решение, основанное на переопределении touchesBegan:
, touchesMoved:
, touchesEnded:
и touchesCancelled:
ранее, но иногда это вызывало странное поведение: при выборе определенной ячейки метод -tableView:didSelectRowAtIndexPath:
вызывался для ячейки с другой indexPath.
Решение от Apple пока не имеет побочных эффектов и выглядит более элегантно.
Ответ 3
Существует также элегантное разрешение:
Создайте SubClass из UIScrollView и переопределите следующие методы.
- (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.
Ответ 4
Решено подклассификация как uitableviewcell, так и uiscrollview.
Он работал для моих нужд. Надеюсь, это поможет.
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;
}
Ответ 5
Выбранный ответ правильный, но я обновил код на основе ошибки, которую я получал.
В подклассовом просмотре прокрутки добавьте следующий код.
- (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
, тогда выделенное состояние не будет.