My UIScrollView area is scrolling perfectly except when the user presses on one of the buttons:
var button:UIButton = UIButton.buttonWithType(UIButtonType.Custom) as UIButton
button.frame = CGRectMake(0,0,self.width, self.menuHeight)
button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
button.tag = Int(itemNo)
scrollView.addSubview(button)
and the buttonClicked code:
func buttonClicked(sender:UIButton)
{
var tag = sender.tag
println(tag)
}
It seems that the TouchUpInside method keeps control even when the user moves his finder away from the button. What is the best way of getting my UIScrollView area to scroll reliably?
This might work for swift. It worked for me in iOS 7.1. Xcode 5.1.1 without swift.
The answer has been taken from: ScrollView not scrolling when dragging on buttons
PREREQUSITS: UIScrollView subclass, Xcode 5.1.1, iOS 7.1., UIButtons stay in fixed positions while the UISV is scrolling, some buttons in your UISV added as subviews
THEORY:
-In your .m file of the UISCV subclass implement:
If you now scroll your SV outside the button frame (which you have added) you will see the layoutSubview method being called and changing the contentOffset position how you scroll. I used the .x coordinate since I have use horizontal scrolling (use .y if you have vertical scrolling). However if you click onto your button you will see touchesShouldBegin being called with the correct touch position which is you button being pressed. However, if you keep your finger on the button and try to drag no scrolling will occur and layoutSubviews will not be called. Here is the problem. Now you will have your touch but not your scrolling. The more buttons you have the less "scrolling chances" you will have since every touch stops scrolling.
SOLUTION 1 - PARTIALLY
If you return NO in touchesShouldBegin you will be able to scroll even the buttons are touched but the touch event will not be registered like written in the docs(CTRL + F "touchesShouldBegin")
Therefore no touch event will be registered by your scrollview. On this link someone proposed to make UIImageViews instead of buttons and use their frame sizes. With the frame sizes you could then check if the positionInScene (CGPoint) fits any frame and if it does call the method which does your buttons work.
SOLUTION 2 - FULLY
1.Add:
to your subclassed UISV .m file in the init method.
2.Add:
to your subclassed UISV .m file.
If you run your app now you will see that upon a button touch both layoutSubviews and touchesShouldBegin are being called. The scrolling works. It works but still doesn't call the method of your button. The reason for this is that the touchEvent is being cancelled and after the touch has been cancelled tracking is being allowed. Read the docs (CTRL + F "canCancelContentTouches") :
Since you set your button to :
myButtonPressed will not be called since UIControlEventTouchUpOutside occurred. If you change this to :
and run the code again you will have not only scrolling but button click with further scrolling since your button now calls the selector when and EventTouchCancel occurs which it will since you let you UISV transform a touchBegin into a touchCancelled with the :
Don't forget to overwrite (add) the :
It won't work without it. Please give any feedback, since I hope this will work in swift which I will begin using soon. Hope it helped. Gl & hf :)
Try setting the
delaysContentTouches
property of theUIScrollView
toNO
.Also, you can set
canCancelContentTouches
property toYES
. (It'sYES
by default, but just in case.)Reference (From docs) :
canCancelContentTouches : A Boolean value that controls whether touches in the content view always lead to tracking.
delaysContentTouches : A Boolean value that determines whether the scroll view delays the handling of touch-down gestures.