2015-03-29 2 views
1

В моем приложении у меня есть UICollectionView, который действует как прокручивающийся набор цветов в моем приложении. У меня очень редкая ошибка, когда однажды в синей луне цвет будет установлен на первое значение в скроллере при нажатии кнопки, а не на том, что связано с кнопкой, которую пользователь действительно коснулся.indexPathForItemAtPoint Время от времени возвращающееся nil

Я выделил это для indexPathForItemAtPoint, возвращая nil для нажатия кнопки.

На данный момент я взломал проблему, просто вернувшись, когда возвращаемый путь указателя равен nil, однако я обеспокоен тем, что это поведение по-прежнему не подходит по нескольким причинам;

  1. Прежде всего, я посмотрел на позицию касания в отладчике, и он действителен в пределах вида коллекции.
  2. Во-вторых, триггер, чтобы получить цвет, связанный с кнопкой, возникает, когда событие UIControlEventTouchUpInside происходит для одной из кнопок в коллекции. Поэтому для меня не имеет смысла, что код будет вызван для касания не внутри кнопки. В этом случае я поменял свою текущую ошибку, получив неправильный цвет для ошибки, когда кнопка редко не реагирует.

Я сделал немного поиска, и если я не пропустил это, все, что я не видел на этом сайте, являются случаи, когда код была ошибка реализации и всегда получать ноль, но ничего подобного в этом.

Я надеялся, что кто-то сможет помочь мне определить причину, чтобы я мог ее исправить или, по крайней мере, понять, почему проблема возникает.

соответствующие функции приведены ниже:

- (IBAction)myClickEvent:(id)sender event:(id)event 
{ 
    NSSet *touches = [event allTouches]; 

    UITouch *touch = [touches anyObject]; 

    CGPoint currentTouchPosition = [touch locationInView: self.collectionViewColors]; 

    NSIndexPath *indexPath = [self.collectionViewColors indexPathForItemAtPoint: currentTouchPosition]; 

    if(!indexPath)return; 

    appState.currentColor = appState.colors[indexPath.row]; 

    const CGFloat *components = CGColorGetComponents(appState.currentColor.CGColor); 

    self.redSlider.value = components[0]; 
    self.greenSlider.value = components[1]; 
    self.blueSlider.value = components[2]; 

    appState.setBackgroundImagePreview(nil); 
} 

И функция инициализации, которая устанавливает событие кнопки:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *identifier = @"Cell"; 

    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath]; 

    UIButton *myButton = (UIButton *)[cell viewWithTag:100]; 

    [myButton addTarget:self action:@selector(myClickEvent:event:) forControlEvents:UIControlEventTouchUpInside]; 

    /// abridged 

    [myButton setBackgroundImage:colorSquare forState:UIControlStateNormal]; 

    return cell; 
} 

Спасибо!

Редактировать: Я попробовал следующее, чтобы получить штрихи, полагая, что Apple может по какой-то причине отправлять мультитач/касания за пределы кнопки. Нет кубиков. Он по-прежнему возвращает индексный путь nil.

NSSet *touches = [event touchesForView:sender]; 
+0

Вы пробовали другой общий способ получить точку с помощью 'CGPoint p = [sender convertPoint: CGPointZero toView: self.collectionView]; NSIndexPath * indexPath = [self.collectionView indexPathForItemAtPoint: p]; 'чтобы убедиться, что это работает лучше? – rdelmar

+0

Я просто попробовал это; Трудно сказать наверняка, так как это сложная ошибка для воспроизведения, но, похоже, это уже не так! Хотелось бы, чтобы я знал, почему другой метод не был таким же надежным, но я включу этот патч и опубликую его снова, если найду какую-либо проблему. – VirtuosoChris

ответ

3

indexPathForItemAtPoint: возвращает nil, если «no item was found at the specified point», который является наиболее часто тот случай, когда точка попадает в интервал между ячейками. Есть 3 свойства макета потока, которые обычно используются для влияния на клетки разнесены:

  • minimumLineSpacing
  • minimumInteritemSpacing
  • sectionInset

Когда вы получите путь к nil индекса, а затем попросить его строка всегда будет 0, и поэтому appState.colors[indexPath.row] дает вам первый цвет в вашем массиве.


Один из способов исправить это было бы в цикле по всем клеткам в indexPathsForVisibleItems и определить, какой из них содержит центральную точку (если таковая имеется) или ближе к нему. Самый простой способ сделать это - - layoutAttributesForItemAtIndexPath:, CGRectContainsPoint() и несколько простых математических вычислений.

Это может также иметь смысл для вашего приложения просто return, если вы получите путь nil и не предпринимайте никаких действий.

+0

Этот ответ исправил мою проблему, которая была именно тем, что я просил указательный путь в точке между двумя ячейками. Я применил категорию в UICollectionView под названием indexPathForCellNearestPoint: используя приведенные выше советы, и он работает. –

+0

@jszumski Не могли бы вы рассказать о точном использовании layoutAttributesForItemAtIndexPath: и CGRectContainsPoint()? Когда вы пытаетесь найти ближайший центр ячейки, можем ли мы просто вычислить минимальное расстояние? для (NSIndexPath * путь в [self indexPathsForVisibleItems]) { cell = [self cellForItemAtIndexPath: path]; distance = powf (cell.center.x - point.x, 2) + powf (cell.center.y - point.y, 2); если (дистанция <ближайшийDistance) { ближайшийDistance = дистанция; ближайшийPath = путь; } } – Cindeselia

+0

@Cindeselia Это действительно зависит от того, что имеет смысл для вашего приложения. Можете ли вы создать новый вопрос с большей спецификой и связать его здесь? – jszumski

Смежные вопросы