I have a View that has a UIScrollView, with some text (loaded via JSON). I need to detect when the user has reached the end of the scroll (I have seen other questions about it here) but the problem is, i have done the .h implement UIScrollViewDelegate, I have
#property (retain, nonatomic) IBOutlet UIScrollView *scroll;
in my .h file, and synthezised it in the .m file. I have this in my viewDidLoad:
self.scroll=[[UIScrollView alloc]init];
self.scroll.delegate=self;
Connections are made in the Interface Builder (the IBOutlet "scroll" with the UIScrollView, and so on).
After that, i fulfill the UITextView with the call to the JSON, and do other stuff not related to the scrollView. I have, then, implemented the method scrollViewDidScroll. But, it is never called. The scroll works fine, lets me go up and down to see the whole text. But, any idea why the method of the protocol is not called?
Thank you.
You don't need to alloc and init a new UIScrollView instance. When you link it from the IB it is already done. That way you are breaking the link.
By the way, your scroll property is defined as retain, so
self.scroll = [[UIScrollView alloc]init];
is a memory leak.
Does your UIViewControllercomplies with the UISrollViewDelegate? The protocol here.
Keep in mind the following:
The methods declared by the UIScrollViewDelegate protocol allow the
adopting delegate to respond to messages from the UIScrollView class
and thus respond to, and in some affect, operations such as scrolling,
zooming, deceleration of scrolled content, and scrolling animations.
There are not mandatory methods, but you need to adopt the protocol in order to use the methods.
That is... I MUST set programatically the contentSize (despite the scroll is done nicely) if you want the method scrollViewDidScroll get called.
Fantastic... x(
Related
if scrollview inherits from UIView how come my code below doesn't work?
DOBMonthTextField us an an IBOutlet for a UITextField.
[DOBMonthTextField setHidden:YES];
It stopped working when I made my UIVIEW underneath the text field a scrollview. The text field use to hide when I executed the code above. Now it doesn't hide.
While changing the views in nib files via cut-paste, the IBoutlet connections of those views go missing (disconnected), so you always have to reconnect them after pasting.
Check your connections whenever some code for a view created in nib/storyboards used to work earlier but does not after some modifications.
Because hidden (or its setter, setHidden:) is a property of an instance of DOBMonthTextField, not the class itself. Classes don't have properties in Objective C. Here's an example of roughly what you should be doing instead:
DOBMonthTextField *someInstance = [[DOBMonthTextField alloc] init];
[someInstance setHidden:YES];
I have a UIScrollView full of tacos.
I attached a pull-to-refresh handler to it via: https://github.com/samvermette/SVPullToRefresh
It extends uiscrollview, and exposes this method:
[scrollview addInfiniteScrollingWithActionHandler:^{
// Get me more tacos
}];
When InfiniteScrolling is triggered, I clear the scrollview's subviews and data array(intentionally) and replace it with a new set.
It works great the first time. However, when I want to load more tacos it crashes.
I get:
-[SVInfiniteScrollingView retain]: message sent to deallocated instance 0x1e5db5d0
Not surprisingly, if I leave 1 subview left in my UIScrollview, everything works fine.
Question: How can I fix this?
I thought about declaring my properties with a strong pointer, like:
#property (strong, nonatomic) IBOutlet tacoScroller *tacoScroller;
But, I worry about a retain cycle & it also doesn't work.
Any help would be appreciated, perhaps I'm missing something fundamental.
Edit:
I'm using ARC
Use an UITableView to show your tacos, this way you will reuse views and avoid wasting memory. Also it is the easiest and most convenient way to show a list of things.
One simplest solution according to your description is simply add an empty & hidden subview inside the scrollview, i am sure it wont occupy much amount of memory.
I think you are invoking the wrong method. Infinite scrolling is for other purposes.
You probably want to use
[scrollView addPullToRefreshWithActionHandler:^{ ... }];
Also, as others pointed out, you definitely should consider to use a UITableView to present your data, which seems to be very suitable for the task.
I am sub-classing a UIScrollView element in response to a previous question suggestion.
In my subclass I have a few methods that are triggered by touch and keyboard events. Those events need to interact in various ways with variables that are in my superview.
I've tried accessing them via _myVar.text = #"smth" but that doesnt compile.
I know I could play back and forth with NSNotifications but is there a way to access the variables in my superview / class from my UISCrollView subclass?
I've tried self.myVar = #"" but it says that it is not recgonised. I am subclassing an UIScrollView element but then my view that hold all my variables is a UIViewController. just the UISCroll element was subclassed
Everything that is a #property in your superclass is accessible in your subclass, but not in the other way
It sounds like you're a little confused here. Are you sure you're talking about the superview? Or are you talking about the superclass from which you derived your subclass? If superview, and if you know the type of the superview, get a pointer to it, cast it to the appropriate class type, then call methods on it or access its visible properties.
UIButton* superButton = (UIButton*)[self superview];
superButton.visible = NO; // Assign to superview property
If you're talking about the superclass (in your case UIScrollView), then yes of course you can use any of its visible methods and properties.
self.bounces = YES; // Assign to superclass property
In case it's not clear what the difference is, you should really do some more reading about the basics of Objective-C and object oriented programming.
Superview: the view relative to which this view is laid out. This view is a subview of the superview. UIView and all derived classes have this hierarchical relationship.
Superclass: the class whose functionality you are extending to define your subclass. Your subclass inherits all visible properties and methods.
So much confusion, where to start? I really don't know. For what it's worth,
_myVar.text = "#"smth"
will obviously not compile, note the stray ".
_myVar.text = "#smth"
has a better chance of compiling.
I have a UITableView with static custom UITableViewCells, I need to scroll a text field into view as currently they are getting hidden behind the keyboard after the return key is pressed and the next responder is set. I know i need to use scrollToRowAtIndexPath:atScrollPosition:animated:. How would I go about scrolling to one of the text boxes?
I know this should scroll itself but if your UIViewController derives from UITableViewController (as Apple states it should be) then the UITableViewController class handles this behaviour for you by implementing UITextFieldDelegate, UIScrollViewDelegate etc. My application stopped doing this as I changed to derive from UIViewController and add the table view on top of the view controller's UIView. So basically I'm missing the features from UITableViewController because I (for other reasons) choose to derive from UIViewControler.
I do this all the time. The way that I do it is I have a method that is called in the UIControlEventEditingDidBegin for the textfield, and in that method, I do:
-(void)startEdit:(UITextField *)textField {
self.prevOffset = self.tableView.contentOffset.y; //I like storing the current offset so I can restore it when the text stops editing, you don't have to do this.
int offSet = [textField superview].frame.origin.y; //this gets the y coordinate of the cell the textField is in. If the table is not at 0,0, you also need to add [[textField superview] superview].frame.origin.y;
offSet-=(self.view.frame.size.height-KEYBOARD_HEIGHT)/2; //where KEYBOARD_HEIGHT is 216 in portrait and 160 in landscape;
if (offSet<0) offSet = 0;
[UIView animateWithDuration:0.3 animations:^{
[self.tableView setContentOffset:CGPointMake(0,offSet)];}];
}
I do a lot of other things as well, but I believe they are specific for my application.
First, if the offset is greater than 0, I set teh contentInset to UIEdgeInsetsMake(0,0,KEYBOARD_HEIGHT,0) because I was having some jumpy scrollViews before I did that.
Also, if the original offset (self.prevOffset) plus the frame's height is greater than the content size (which would also cause jumping as it sets the offset too low then jumps back), I set the prevOffset to MAX(0,contentSize.height-frame.size.height).
These things aren't neccessary, but you are getting Scroll/TableViews that are jumping around, try them out.
UITableViewController has the delegate protocols already in the header field. Since your class is no longer a UITableViewController, you need to manually add the delegate protocol headers for a UITableView to your .h file.
When I create a custom view controller that has a UITableView, I start off with a UITableViewController too, just to get the delegate methods, but then I change UITableViewController to UIViewController as you have done, and manually add the Delegate protocols to the header.
If you want, you can look at UITableViewController.h and copy over the delegate protocols.
For your reference they are:
<UITableViewDelegate, UITableViewDataSource>
So your .h file should look similar to this:
#interface MyTableViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
Also, don't forget to set the delegates of the controller to the file's owner in Interface builder, or to self in code.
You may also find it a lot easier to use a framework such as the freely available Sensible TableView framework. These frameworks usually provide all the data entry cells out of the box, and will take care of all scrolling/resizing chores on your behalf.
I'm working on an accessibility project for an iOS application. Because accessibility does not act quite as advertised, I have to override accessibilityFrame, accessibilityActivationPoint and pointInside:withEvent in a subclass in order to expand the region recognized by VoiceOver (for both drawing and touch recognition) beyond the "natural" bounds of the control view. So, in order to change the VoiceOver bounds of a UIButton I have to subclass that class and then add these three methods. In order to do this for a UILabel I have to add another subclass with the code, and so on.
I can refactor the code in these methods to a central location, but I was wondering if this can be done more elegantly with inheritance. I'd like to put this code into a subclass of UIView (maybe called UIViewAccessible) and then create a subclass of UIButton called UIButtonAccessible which inherits from UIButton which would in turn inherit from UIViewAccessible instead of UIView. Is this possible, or can something like this be done with a category?
Edit: According to the docs, you can't really achieve this with a category:
If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime.
Is there some other way to do this?
To answer your question, no, it can't, since your UIViewAccessible is a second degree sibling to UIButton in the inheritance chain (both inherit from UIView at some point). But I guess you already knew that. As for a solution, you could wrap around your UIView accessible classes a decorator and use protocols for strong typing. That way you'll keep the code in one place. I've described this technique here in more detail (although for a different purpose, it's the same situation).
For the views that would support accessibility you'll have to do this:
#property (nonatomic, strong) UIView<MyAccesibilityProtocol>* view;
//self.view can come from the nib or previously created in code
self.view = [[AccesibilityDecorator alloc] initWithDecoratedObject:self.view];
//you can then use self.view like any other UIView,
//and because it also implements an
//accessibility protocol, you can use the methods
//implemented in the wrapper as well.
//more than that, you can control which methods to override
//in the AccesibilityDecorator class
[self.view addSubview:otherView];//could be overridden or not
[self.view myAccesibilityMethod];//custom method declared in the protocol