UIScrollView subclass trigger event - ios

I've tried for some days understand Xcode Subclasses and Categories - and after all I found one event that are fired.
- (void)setContentOffset:(CGPoint)contentOffset {
NSLog(#"foo");
}
And for more confusion, after read Apple iOS Documentation I get this stuff:
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated {
NSLog(#"bar");
}
First event are fired, but from Apple documentation are not. Why?!
But in the first case, although he was fired the UIScrollView loses their scroll/drag'n' bounce behavior. I think it's because after overrride setContentOffset I would need to call the parent method to keep the default behavior of the UIScrollView. But I'm already exhausted from test obsolete Xcode approaches.
Than why second code are not fired and how call parent overridden method?
Thanks in advance.

To call the super (:parent) here
- (void)setContentOffset:(CGPoint)contentOffset {
NSLog(#"foo New Offset x: %.0f y: %.0f", contentOffset.x, contentOffset.y);
[super setContentOffset:contentOffset];
}
And, for the second one; That is not a delegate method (:event), this is a method provided to developer actually, to initiate scrolling to a specific offset with/without animation. You probably do not need to override this.
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;
Even more; even the first one is not an event, that's a message sent to scrollview to change the offset, but you can get in between and do your thing using that as an event trigger, and call super again to let it do it's work.
If you want to get real events on scrollView, you need to set up a delegate as documented here;
https://developer.apple.com/library/ios/documentation/uikit/reference/UIScrollViewDelegate_Protocol/Reference/UIScrollViewDelegate.html#//apple_ref/occ/intf/UIScrollViewDelegate
And I also agree with Wain on sharing this link,
https://developer.apple.com/library/ios/documentation/general/conceptual/DevPedia-CocoaCore/Delegation.html

Related

Call method once after viewDidLayoutSubviews

I need a little help to understand the viewDidLAyoutSubviewsmethod and how to safely use it.
I need to edit some of my subviews programmatically before the viewDidAppear method. And in order for it to work properly I of course need to wait until the targeted subviews are layed out before I edit them.
Now I thought this was what the viewDidLayoutSubviewsmethod was for, but when I tested it I found out that it was actually called two times before my viewDidAppear method. I tried to edit my subviews only the first time viewDidLayoutSubviews was called, because I just want to run [self editMySubviews] once, but then the targeted subview wasn't ready and it got messed up. This is how I tried:
- (void)viewDidLayoutSubviews {
if (!myBoolean) {
[self editMySubviews];
myBoolean = YES;
}
}
Of course if I remove the if-statement it fixes itself next time the method is called, but I only want [self editMySubviews]to be called once.
So my question is, when I can call the [self editMySubviews] method before the viewDidAppear method, and be 100% sure that all subviews are ready to be edited? Now in my case the viewDidLayoutSubviews gets called two times before viewDidAppear, but will that be the case every time? Is it safe to just call [self editMySubviews] after the second time viewDidLayputSubviews is called?
According to your comment you said
Editing some button constraints according to its superView.frame.size.width which is different on different devices
After viewdidload you will get the proper size from view.bounds
so you can easily set/update constraint and add at the end of this
setNeedsUpdateConstraints and layoutIfNeeded method call

iOS8 custom keyboard issues

I'm working on iOS 8 custom keyboard extension right now, and there are some issues that I cannot figure out.
First, I think the UITextInputDelegate Methods are not working as I expected.
Does this sound right: selectionWillChange: and selectionDidChange: methods should be called when user long-presses typing area? And textWillChange: and textDidChange: methods should be called whenever the text is literally changing?
Actually, what I observed is that, when I changed selection in text input area, textWillChange: and textDidChange: are called, and I cannot get a clue that the other two methods are called in what condition. If anyone knows about the usage of these delegate methods, please let me know.
Second, I know the playInputClick: method can be used to virtualize keyboard click sound in custom keyboard. As this is applicable in a normal situation, I found it impossible to apply in iOS 8 custom keyboard extension. My app consists of one keyboard view controller, and custom view that subclasses UIView is added to this view controller. My approach is that UIInputViewAudioFeedback delegate is declared in this custom view, enableInputClicksWhenVisible method is returning YES, class method that calls [[UIDevice currentDevice] playInputClick] is set, then this method is called wherever the keyboard sound is needed: which is not working at all.
Is my approach is wrong in any way? If anyone has succeeded in using playInputClick method, please share your wisdom.
Thank you
It is best to play the Audio on a queue rather than in the UI key handler
func playPressKeySound() {
let PRESS_KEY_DEFAULT_SOUND_ID: SystemSoundID = 1104
dispatch_async(dispatch_get_main_queue()) {
AudioServicesPlaySystemSound(PRESS_KEY_DEFAULT_SOUND_ID)
}
}
NOTE: this only works if the keyboard has Full Access switched on, so best test there is full access before calling, otherwise the keyboard can suffer long pauses.
For the second question, try AudioServicesPlaySystemSound
#define PRESS_KEY_DEFAULT_SOUND_ID 1104
- (void)playPressKeySound {
if (self.openPressSound) {
AudioServicesPlaySystemSound(PRESS_KEY_DEFAULT_SOUND_ID);
}
}

Does willMoveToSuperview will also deallocate the UIView on which its got called?

I was wondering if I can call willMoveToSuperview on UIView and after that retain that view to reuse later for one ? something like following
if (!CGRectIntersectsRect(cell.frame, visibleRegion)) {
[cell willMoveToSuperview:nil];
[self.resuableCells addObject:cell];
}
I am not sure about your intent here...
But WillMoveToSuperview - According to doc:
The default implementation of this method does nothing. Subclasses can override it to perform additional actions whenever the superview changes.
So your code,
[cell willMoveToSuperview:nil];
Has no effect unless you override this method in a cell subclass and implement your own logic there.
Coming to your question -
Does willMoveToSuperview will also deallocate the UIView on which its got called?
Answer is obvious - NO.
willMoveToSuperview is an observer method that the system calls as a courtesy to you in order to give you a chance to handle special cases before it completes some other hidden tasks.
It's default behavior is to do nothing, but you might want to tidy up something in your code prior to a move by overriding this method.
A proper use case might be if you had a view playing a video clip or an animation, and something else in your code is about to rip the view out of it's current hierarchy and place it in some other un-related view hierarchy. You might want the chance to pause the clip or suspend the animation before the move took place.
I doubt it's the right method to handle what you are attempting, and I definitely know you should not be calling it directly.
Feel free to post some more code to show us what you're trying to accomplish and where it's going wrong.

Prevent delegate method from being called too often

How would you add a delay between certain method being called?
This is my code that I want to only trigger 30 times per second:
- (void) scrollViewDidScroll: (UIScrollView*)scrollView {
[self performSelector:#selector(needsDisplay) withObject:nil afterDelay:0.033];
}
- (void) needsDisplay {
[captureView setNeedsDisplay];
}
If I leave it like this, it only gets called after the user stopped scrolling.
What I want to do is call the method when the user is scrolling, but with a delay of 33 milliseconds between each call.
There are different delegate methods which will call on different occausion. This method will only call when user finish scrolling. So you can perform some task if you want to. If you want to do some thing while scrolling or before scrolling you can use different delegate method. Select one of the below depending on your functionality.
– scrollViewDidScroll:
– scrollViewWillBeginDragging:
– scrollViewWillEndDragging:withVelocity:targetContentOffset:
– scrollViewDidEndDragging:willDecelerate:
– scrollViewShouldScrollToTop:
– scrollViewDidScrollToTop:
– scrollViewWillBeginDecelerating:
– scrollViewDidEndDecelerating:
For detail description upon these delegates please follow this link.
https://developer.apple.com/library/ios/documentation/uikit/reference/uiscrollviewdelegate_protocol/Reference/UIScrollViewDelegate.html
Delegate should call when it should be... other wise you gonna cause some glitch.
Since I couldn't find a solution, and other scroll view delegate methods weren't good, I did it by limiting based on scroll view's content offset, as suggested in a comment. (Ex: only calling it if the user scrolled more then 3 pixels).
This is a decent solution, since I doubt someone can scroll more then 90 pixels per second and STILL read the text in between those 90 pixels.
if (ABS(self.oldOffset.y - webView.scrollView.contentOffset.y) > 3) {
[captureView setNeedsDisplay];
}
The delegate method will get called, you can't setup a limit in that. I think a good option for you is to add the operations in NSOperationQueue, and since you are calling the same selector again and again, make sure you only keep a maximum of 30 operations in the queue at the same time. NSOperationQueue Class Reference.
One cannot have the control over the calling of the delegate methods, and also there is no parameter to set how often delegate method should call or to set the sensitivity of the scrollview,
U cannot control it.
Only thing remaining is to ignoring the call (return at the beginning of the function call if you do not need that) or else process the call..

Ideal place to put a method after orientation has changed

I have an issue and here how it goes,
I have a view with a subview, the subview is loaded conditionally, only if the parent view is setHidden property is set to YES;
something like [parentView setHidden:YES] and if([parentView isHidden]),
I want to call a method when the orientation changes and that is the cited snippet above, but I have observed that the method shouldAutorotateToInterfaceOrientation is called 4 times during loading and 2 times during runtime, since the method is called more than once, how can I possibly implement a method call ideally since apple's existing method doesn't seem to give me the intuitiveness to put my custom method call with the existing method.
If I would hack this thing, it is possible, but somebody might have a better idea before resorting to things that in the future would just cause me more trouble than benefit.
TIA
Have you tried with
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration {
// check here for your desired rotation
}

Resources