开发者

UIPickerView is not scrolling when added to UIScrollView!

I have added UIPickerView to the UIScrollView but now UPickerView is not scrolling. When I add it to the self.view it scrolls smoothly. Here i my code

monthsArray = [[NSArray alloc] initWithObjects:@"Jan",@"Feb",@"Mar开发者_如何学C",@"Apr",@"May",@"Jun",@"Jul",@"Aug",@"Sep",@"Oct",@"Nov",@"Dec",nil];

UIPickerView *objPickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(185,350,100,100)];
    objPickerView.userInteractionEnabled=YES;
    objPickerView.delegate = self;
    objPickerView.showsSelectionIndicator = YES; 
    [objScrollView addSubView:objPickerView];

I have included the delegete and its methods. have a look on this issue. Thanks in advance.

If I am not clear please tell me.


I am using a subclass of UIPickerView for the same purpose, but mine is much simpler:

@implementation ScrollablePickerView

- (UIScrollView *)findScrollableSuperview {

    UIView *parent = self.superview;
    while ((nil != parent) && (![parent isKindOfClass:[UIScrollView class]])) {
        parent = parent.superview;
    }
    UIScrollView* scrollView = (UIScrollView *)parent;

    return scrollView;
}

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event {
    UIScrollView* scrollView = [self findScrollableSuperview];

    if (CGRectContainsPoint(self.bounds, point)) {
        scrollView.canCancelContentTouches = NO;
        scrollView.delaysContentTouches = NO;
    } else {
        scrollView.canCancelContentTouches = YES;
        scrollView.delaysContentTouches = YES;
    }

    return [super hitTest:point withEvent:event];
}

@end

Works like a charm - at least for me.


From the UIScrollView class documentation:

Important: You should not embed UIWebView or UITableView objects in UIScrollView objects. If you do so, unexpected behavior can result because touch events for the two objects can be mixed up and wrongly handled.

They don't mention UIPickerView there, but I wonder if it should have been added to that list. It shares in common with the others the characteristic of using touches to scroll things.


I guess this might solve your problem (be sure to check the comments too):

http://www.alexc.me/uiscrollview-and-uidatepicker/153/

Basically you have to set DelaysContentTouches and CanCancelContentTouches to NO on the scroll view, as it steals the touch events from the picker.


UIPickerView is not designed to be scrolled or moved at all. You should place some text field instead and show UIPickerView when user taps on it.


I had a similar issue with a UIPickerView nested within a UIScrollView and solved it by subclassing UIPickerView. Changes to DelaysContentTouches/CanCancelContentTouches didn't help, and the other "answers" here that basically say "don't do it" -- well, that's no answer at all! It can be done and you can get a picker to behave within a scrollView.

I answered the following question on subclassing UIPickerView, including some code at the end which may help you:

Responding to touchesBegan in UIPickerView instead of UIView


I've been running into a similar problem. I've got a UIPickerView that I turned horizontal by applying a transform ( which works pretty well), however inside of a scrollview, scrolling only works at the left hand side.

What I think is happening is that the UIPicker looks up it's parent chain to see if there are any gesture recognisers, and sets itself as a delegate, so it can disable gesture recognition further up the chain for touches within it's boundaries, and while the transform changes the visual boundaries, it doesn't change the frame, is it is looking for touches within it's original bounds.

If this isn't what is happening, you could use this to prevent the scroll view stealing your touches.

I'm think I'm going to switch to a custom UISCrollView instead of my transformed UIPickerView.


On iOS 11 and iOS 12 changing canCancelContentTouches and delaysContentTouches when UIScrollView is already been dragging doesn't help. So I did the hack by intercepting some touches before scrollView.panGestureRecognizer receives them.

Here is Swift 4 code. Maybe we can check if touch is inside picker more elegantly. But it works good.

public class TableView: UITableView {

    /// Check if view is a picker's subview
    private func isInPickerView(_ view: UIView) -> Bool {
        var prev: UIView? = view
        while prev != nil {
            if prev is UIPickerView ||  prev is UIDatePicker {
                return true
            }
            prev = prev?.superview
        }
        return false
    }

    // UITableView is already UIGestureRecognizerDelegate internally, 
    // so we just need to overwrite 1 method here
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, 
                                  shouldReceive touch: UITouch) -> Bool {
        // we don't care about any recognizers except self.panGestureRecognizer
        guard gestureRecognizer == panGestureRecognizer else {
            return true
        }
        // if touch is inside picker - we don't pass this touch 
        // to panGestureRecognizer
        let location = touch.location(in: self)
        if let view = self.hitTest(location, with: nil), isInPickerView(view) {
            return false
        }
        return true
    }
}
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜