5

When finger is on usercard or on "edited" link - scrolling via swipe is not possible.

scrollno

  • App Version: 1.6.2.5
  • Device: iPad Air 2 (Wi-Fi)
  • OS Version: Version 10.2 (Build 14C92)

2 Answers 2

4

This will be fixed in 1.6.3.3, shipping this month.

The easy part

When you start dragging your finger, UIScrollView calls it's own touchesShouldCancelInContentView: method to decide whether or not to scroll.

The default implementation of this method returns NO (cancels scrolling) if your finger is touching an enabled UIControl. That's what buttons subclass from.

The reason you can scroll the "Add an answer" button, toolbar buttons (actually buttons inside cells), etc. is that we've subclassed UITableView and overridden this method:

@implementation SEPostTableView

- (BOOL)touchesShouldCancelInContentView:(UIView *)view
{
    if ([view isKindOfClass:[UIButton class]]) {
        //cancel UIButton touches, especially for the action toolbar
        return YES;
    }

    return [super touchesShouldCancelInContentView:view];
}

@end

The problem was that the new attribution views aren't buttons but generic UIControls. This was done because there's a lot of complex stuff in them. I just needed to above method to capture the specific view.

The hard part

"Edited on ..." is a horse of a different color though. It's a link in a UITextView. This link is driven off a UITapGestureRecognizer that cancels the scroll view's pan gesture recognizer before it can even get going. To make this work, I would need to get both gesture recognizers to fire simultaneously and manually kill the tap gesture when the pan gesture accepts. (I do something similar for UIWebView.)

I'm able to get the gesture recognizers to work in parallel because UIScrollView.panGestureRecognizer.delegate is the scroll view. It's a little tricky though, because both the tap and a long press are required for the link to work. ¯\_(ツ)_/¯

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if (gestureRecognizer == self.panGestureRecognizer && [otherGestureRecognizer.view isKindOfClass:[UITextView class]] && ([otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]])) {
        return YES;
    }

    return NO;
}

In addition to disabling and reenabling gesture recognizers on scroll though, I also needed to guard the text view delegate with a timestamp because the event was firing anyway in some cases.

1
  • This answer deserves to be on the SO! Commented Jan 20, 2017 at 4:54
2

If I had to guess, this is due to the iOS runtime and the way UIKit works.

The way UI elements work on iOS is through the UIResponder chain. With normal scrolling, the responder to the touch events is the UIScrollView (usually part of a UITableView or UICollectionView). When you touch a UIButton such as the edited button or the usercard (which is actually a custom button), that button becomes the responder to the touch events, not the scroll view. Thus, you can't scroll the view while touching any buttons. This is to give the user the opportunity to cancel the touch (which in technical terms are the UIControlEvents: touchUp, touchDown, touchUpInside, touchUpOutside).

The view hierarchy of the view controller (SETableRootViewController) is quite complex:

View Hierarchy

The user cards are rows in the table view:

User card cell

While the share, safari, flag, etc. buttons are part of a collection view with a horizontal view layout:

Collection View

These images were taken with Flex on a jailbroken iPad Air running iOS 9.0. I don't have access to the source code, so I went digging into the app with a view debugger.

The "buttons" mentioned in Cai's comment are actually UICollectionViewCell instances and not UIButton instances, hence the behavior of touching those is different than the other buttons.

10
  • I'm not sure, but seems that older version of the app did not have same behavior. So if you are right, I would like that usercard does work as another buttons (fav, edit, share etc). Commented Jan 4, 2017 at 3:14
  • @alexolut Brian might be able to chime in, but I believe those user cards were changed in a newer version of the app. If they were just regular views in an older version, they wouldn't have the same behavior.
    – JAL
    Commented Jan 4, 2017 at 5:19
  • This isn't the case for other button though (and it's easy enough to get around by returning YES for touchesShouldCancelInContentView)
    – Cai
    Commented Jan 4, 2017 at 9:36
  • @Cai which other button?
    – JAL
    Commented Jan 4, 2017 at 13:56
  • I actually meant buttons, it's all other buttons from what I can see... "edit", "share" etc. "add comment" and "add answer" too.
    – Cai
    Commented Jan 4, 2017 at 13:59
  • @Cai Ah I see what you mean, the buttons below the usercard. I have an idea about those, but I need to do a little more testing first.
    – JAL
    Commented Jan 4, 2017 at 14:00
  • My point is there's no problem cancelling the touch and it's already done for all other buttons (not just the ones under the user card).
    – Cai
    Commented Jan 4, 2017 at 14:12
  • @Cai See my edit, they're not actually buttons, but UICollectionViewCells. Hence the different behavior than the other UIButtons.
    – JAL
    Commented Jan 4, 2017 at 14:15
  • Ok, but I'm guessing the "add comment", "add answer" and tags aren't, and if they are then why not use a collectionView for the usercards too? Or simply cancel touches on the button?
    – Cai
    Commented Jan 4, 2017 at 14:21
  • @Cai Can't explain those. ¯\_(ツ)_/¯ They could be in table view reusable views (headers, footers, etc). Will have to wait for Brian to answer any architecture questions.
    – JAL
    Commented Jan 4, 2017 at 14:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .