is there a uipickerview delegate method like scrollviewDidScroll?
Asked Answered
S

5

7

I have a customized UIPickerview and I do not want to use a datepicker. I want to implement the feature where when a user scrolls down/up the hours, the AM/PM component switches while the hour is scrolling. This means that I need to switch it before pickerView didSelectRow is called. Is there a way to do this?

Thanks

Stoddart answered 2/10, 2011 at 9:40 Comment(0)
H
14

Use following method,

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
     // put your logic here.
}

Above method is from UIPickerViewDelegate, If user selects any element using pickerview, this method is automatically triggered.

Hope it helps to you.

Edit :

I think you should use following method for detecting - in which direction user is scrolling ?

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    NSLog(@"scrolling to row is %@",[NSString stringWithFormat:@"index_%i",row]);
    return [NSString stringWithFormat:@"index_%i",row];
}

whenever user is scrolling up/down above method is triggered automatically which is similar to UITableView. Remember UIPickerView is using UIPickerTableView which is private, so we can not detect the scrolling the way you want to have.

Let me explain the detecting the direction in pickerview.

Example. Visible rows are index_4,index_5,index_6,index_7. Now if user is scrolling down index_8 will be called. Similarly if user is scrolling to up index_3 will be called.

I hope this trick will solve your problem. Even-though let me know your feedback on this.

Headless answered 2/10, 2011 at 11:47 Comment(3)
I already know of this method. the problem is that it triggers when the picker has stopped scrolling, I need a callback while it is still scrolling.Stoddart
thanks! i had no idea titleForRow was called while it scrolled.Stoddart
when i am using viewForRow - titleForRow is not being called, so i am using viewForRow instead to detect scrolling. Works!Raskin
C
6

There is a trick to detect this but there is no delegate method/ property to detect if its scrolling or not

  1. take a property as isScrolling
  2. set isScrolling to true in func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? or equivalent method
  3. set isScrolling to false in func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)

hope this helps, BTW this is what is explained in all the above mentioned answers

Comfort answered 22/5, 2017 at 16:34 Comment(1)
Fix "Set isScrolling to true" in number (3) to "Set isScrolling to false".Spirketing
F
3

have to use this two UIPickerView delegate method for event:

DID END SCROLL:

- (void)pickerView:(UIPickerView *)pV didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    NSLog(@"pickerView didSelectRow %zd",row);
    // DID END SCROLL: CALL YOUR HEANDLER METHOD!!
}

WILL START SCROLLING:

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
    // WILL START SCROLLING: CALL YOUR HEANDLER METHOD!!
    UILabel* label = (UILabel*)view;
    if (!label){
        label = [UILabel new];
        [label setFrame:frame];
        [label setBackgroundColor:[UIColor clearColor]];
        [label setFont:[UIFont fontWithName:FONT_QUICKSAND_BOLD size:12]];
        [label setTextAlignment:NSTextAlignmentRight];
        [label setLineBreakMode:NSLineBreakByTruncatingMiddle];
        [label setTextColor:UIColorFromRGB(0X2692ff)];
        }
    //Update labeltext here
    [label setText:[NSString stringWithFormat:@"row %zd",row]];
    return label;
}

obviosly except for the building of UIPickerview (firstTIME!); so u have to implement a fake didendscroll event when you finish to build you piker or ignore first willstart scroll for the visible piker row

Folkway answered 30/6, 2014 at 17:46 Comment(0)
S
3

Unfortunately, the above solutions (setting a flag when data source methods such as titleForRow are called and resetting it when didSelectRow is called) are sketchy and won't work in many cases. The data source methods may be called in many cases where there is no scrolling by the user - such as UI changes resulting in changing view layouts, and also may be called immediately after didSelectRow - you have no control over when these methods are called.

In relation to this particular question, these solutions may work, since these methods are always called when scrolling - just not ONLY when scrolling. However, care needs to be taken not to assume that the user MUST be scrolling in these cases. Also, if you manage a state machine with this flag (like disabling some button when scrolling and enabling it after), you'll get in trouble.

Finally, this only allows detecting a scroll (with the above caveats), but it won't tell you the speed or current values - so it would be difficult to tell when to switch the AM/PM label.

The only way I was able to reliably detect a scroll was through a mess of flags that I set when UI changes are made and other ugly hacks (like waiting 100 ms after a didSelectRow before trying to detect scrolls again, because I noticed calls to the data source immediately after didSelectRow). Adding willScroll/didScroll methods to the delegate seems like an obvious thing Apple neglected to add.

Spirketing answered 9/5, 2018 at 7:30 Comment(0)
F
0

I just found a way to achieve "pickerDidScroll",it work fine. The key point is add KVO to the row view. Here is my code:

//picker view delegate

- (UIView*)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {

    if (!view) {
        view = [[RatchetScrollUnit alloc] initWithFrame:CGRectZero];
        //
        [((RatchetScrollUnit*)view) addRatchetObserver:self];
    }
    return view;
}

//KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {

    if (self.ratchet) {
        NSInteger row = [self.ratchet selectedRowInComponent:0];

        if (row != _lastRow) {
            _lastRow = row;

            if (self.delegate && [self.delegate respondsToSelector:@selector(ratchetScrollerDidRatchetedToTooth:)]) {

                [self.delegate ratchetScrollerDidRatchetedToTooth:row];
            }
        }
    }
}

The "RatchetScrollUnit" class :

@interface RatchetScrollUnit ()
@property (nonatomic,assign) BOOL observed;
@property (nonatomic,weak) NSObject *myObserver;
@end

@implementation RatchetScrollUnit

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];

    if (self) {
        _observed = NO;
        self.backgroundColor = [UIColor clearColor];
    }
    return self;
}

- (void)dealloc {
    if (self.observed) {
        [self removeObserver:self.myObserver forKeyPath:@"frame" context:nil];
    }
}

- (void)addRatchetObserver:(NSObject*)observer {
    if (self.observed) {
        return;
    }
    self.observed = YES;
    self.myObserver = observer;
    //
    [self addObserver:observer
           forKeyPath:@"frame"
              options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew
              context:nil];
}

Have a try

Froth answered 12/11, 2019 at 11:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.