开发者

is there a uipickerview delegate method like scrollviewDidScroll?

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开发者_如何学Python didSelectRow is called. Is there a way to do this?

Thanks


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.


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


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


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.


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜