Отвечая на touchesBegan в UIPickerView вместо UIView - PullRequest
6 голосов
/ 20 февраля 2009

У меня есть UIPickerView, который исчезает до 20% альфа, когда он не используется. Я хочу, чтобы пользователь мог прикоснуться к средству выбора и вернуть его обратно.

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

Я предполагаю, что это как-то связано с цепочкой респондентов, но, похоже, это не сработает.

Ответы [ 4 ]

10 голосов
/ 15 июля 2010

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

Извините, если мой язык не очень технический, но я довольно новичок в разработке Objective-C и iPhone.

Создание подклассов UIpickerView - верный способ сделать это. Но вы должны переопределить метод - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event. Этот метод вызывается всякий раз, когда вы касаетесь экрана, и он возвращает вид, который будет реагировать на касание. Другими словами, представление, для которого будет вызван метод touchesBegan:withEvent:.

UIPickerView имеет 9 подпредставлений! В реализации класса UIPickerView - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event не вернет self (это означает, что touchesBegan:withEvent:, который вы пишете в подклассе, не будет вызван), но вернет подпредставление, в точности представление по индексу 4 (недокументированный подкласс называется UIPickerTable).

Хитрость в том, чтобы заставить метод - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event возвращать self, чтобы у вас был контроль над методами touchesBegan:withEvent:, touchesMoved:withEvent: и touchesEnded:withEvent:.

В этих методах, чтобы сохранить стандартные функциональные возможности UIPickerView, вы ДОЛЖНЫ не забывать вызывать их снова, но в подпредставлении UIPickerTable.

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

8 голосов
/ 07 мая 2011

Вот код, который делает то, что вы хотите:

@interface TouchDetectionView : UIPickerView {

}
- (UIView *)getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event;
@end
@implementation TouchDetectionView

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
    [hitTestView touchesBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
    [hitTestView touchesMoved:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
    [hitTestView touchesEnded:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
    [hitTestView touchesCancelled:touches withEvent:event];
}

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    return self;
}

- (UIView *)getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch * touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];
    UIView * hitTestView = [super hitTest:point withEvent:event];

    return ( hitTestView == self ) ? nil : hitTestView;
}
1 голос
/ 06 июля 2011

Оба приведенных выше ответа были очень полезны, но у меня есть UIPickerView, вложенный в UIScrollView. Я также делаю непрерывный рендеринг в другом месте на экране, пока присутствует графический интерфейс. Проблема в том, что UIPickerView не обновляется полностью, когда: не выбранная строка нажата, средство выбора перемещено так, что два ряда колеблются в области выбора, или строка перетаскивается, но палец скользит за пределы UIPickerView. Тогда только когда UIScrollView не будет перемещен, средство выбора мгновенно обновляется. Этот результат ужасен.

Причина проблемы: мой постоянный рендеринг не давал анимации UIPickerView получать циклы ЦП, необходимые для завершения, и, следовательно, отображать правильный текущий выбор. Мое решение - которое работает - заключалось в следующем: в UIPickerView touchesEnded:withEvent: выполните что-то, чтобы ненадолго приостановить рендеринг. Вот код:

#import "SubUIPickerView.h"

@implementation SubUIPickerView

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

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

- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
    [singleton set_secondsPauseRendering:0.5f];  // <-- my code to pause rendering

    [pickerTable touchesEnded:touches withEvent:event];
}

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

- (UIView*) hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
    if (CGRectContainsPoint(self.bounds, point))
    {
        if (pickerTable == nil)
        {
            int nSubviews = self.subviews.count;
            for (int i = 0; i < nSubviews; ++i)
            {
                UIView* view = (UIView*) [self.subviews objectAtIndex:i];
                if ([view isKindOfClass:NSClassFromString(@"UIPickerTable")])
                {
                    pickerTable = (UIPickerTable*) view;
                    break;
                }
            }
        }
        return self;    // i.e., *WE* will respond to the hit and pass it to UIPickerTable, above.
    }
    return [super hitTest:point withEvent:event];
}

@end

, а затем заголовок SubUIPickerView.h:

@class UIPickerTable;

@interface SubUIPickerView : UIPickerView
{
    UIPickerTable*  pickerTable;
}

@end

Как я уже сказал, это работает. Рендеринг приостанавливается на дополнительные 1/2 секунды (он уже останавливается при перемещении UIScrollView), позволяя завершить анимацию UIPickerView. Использование NSClassFromString () означает, что вы не используете никаких недокументированных API. Связываться с цепочкой респондента не было необходимости. Спасибо Checcco и Tylerc230 за помощь в разработке собственного решения!

0 голосов
/ 04 января 2013

Установите для canCancelContentTouches и delaysContentTouches родительского представления значение NO, которое работало для меня

...