I do understand how to go about making the UIKeyboard push up the UIView if the active UITextView is blocked by the UIKeyboard as per this question: How to make a UITextField move up when keyboard is present?.
What I'm wondering is, from a design perspective, how do you go about implementing the keyboardDidShow and keyboardDidHide methods so that all of the views in your app, whether they be a UIView, UITableView, or UIScrollView all have this functionality and so you need to implement these methods only once?
The only way I could think of would be to have the view property of the UIViewController always set to a UIView, and if you have a UIViewController that needs a UIScrollView or UITableView, just attach it as a subview to this. Then if the UITextView is being blocked, just move the parent UIView up so it will move all of the views that are attached to it.
Does this sound like a good plan, or is it even worth it? Anyone else have any other ideas?
This is a little old, but it's a great article about using firstResponder methods to tell views to slide up. I, personally, like to put my UITextField in a parent container and move it all up. However, I do NOT suggest putting everything in there and moving it all up, because the UITextField "feels" better just above the keyboard. But I do like the background or certain items to move up with the UITextField.
See below: http://cocoawithlove.com/2008/10/sliding-uitextfields-around-to-avoid.html
This is a nice implementation that moves the field up based on the section of the screen it's in (upper, middle, lower). Works very well. May need to be updated for newest SDK, but should be pretty easy.
In experimenting with this, I noticed that if you want to make a BaseViewController that implements this functionality to work for everything that inherits from it, you have to attach another view on top of the UIViewController's view property in order to get it to work. Reason is, if you push the UIViewController's view property up when the keyboard appears, then it resets itself if the app comes back from being active and it's messy.
The problem with this however, is now in all of your child classes you have to attach your subviews to this new view property instead of the regular view property. Also, you probably have to make a custom UITableViewController which will inherit from your BaseViewController class so it can inherit the keyboard notification methods.
Ultimately, I've found it's not the worst idea to have another view on top of the UIViewController's property for a bunch of different scenarios. Making a custom UITableViewController isn't that big of a deal either. So if you have a lot of text fields in your app, this might not be the worst way to go.
Related
I was googling for a while and I found similar problems but when the custom View is inside a ScrollView, but that is not my case.
I have a custom view that consists of a UILabel behind a UITextField, so I can animate that label later.
The problem is that when I add a View in my ViewController and in the Identity Inspector I set the Class as my custom class, when I use the application the UITextField within my custom view does not receive the touches well and it takes time to gain focus and therefore to open the keyboard. The strange thing is that if I move that same arrangement of views to my main ViewController in Storyboard everything works fine. Why doesn't it do it when I place it using the described method?
I plans to reuse this custom view a lot, so putting logic and views in each ViewController is not an option.
Thanks in advance
Well, the problem was in the constraints of the container UIView. That means, the UIView in my main ViewController. The Height of the UIView was a little bit smaller than the space required for my custom view, so although my custom view seemed to draw correctly, it was not receiving the gestures correctly. The solution was simply increase the height to the correct value occupied by my custom View. Thanks a lot!
I want to make the horizontal swipeable page like YouTube. Is there an object in XCode for this? How do I have to do it? I did not find a tutorial about it. Sorry for my English.
Like this
There are tons of components already made for this in the internet, you can try looking at the cocoacontrols site.
If you still want to write your own code for this, one way is writing a custom UIView subclass. The YouTube feature looks very simple and as far as I can guess, they can use two separate UIView subclasses: one for the menu and one for the pages, just as a container.
For the menu you can use UIStackViews or a single UIViews with UIButtons for the page's titles and another view for the selection effect that moves with the UIButton's touch event. This view should provide a delegate or any notification system that fits better to you in order to notify the container that needs to load the right UIViewController's view inside the container.
The container can be a UIView that loads the view property from the UIViewController subclass on demand. Make sure to add the loaded view controller as a child of the parent view controller, otherwise you will loose some important features.
I hope it can help you to start.
I'm trying to make a custom table view. I have a UIScrollView loaded up with UIViews. I would like to recreate the reusable cell functionality that a tableview has. And I'm wondering what might be a good way to do this.
I was thinking that when the UIViews are scrolled off screen I'll remove them from the Subview, and when I need another I'll just add it. However I'm not sure what method might be the best to do this in.
I could check to see the views location in scrollViewDidScroll: but I'm not sure if this would be the best thing to check over and over again. If anyone has any suggestions or helpful tips that would be really awesome.
Thanks!
One reason why scrollViewDidScroll is less than ideal choice is that your scroll view subclass will then need to be its own delegate. That will deny the users of that class the chance to be the delegate (easily, at least).
The better place to check this is in overriding layoutSubviews. And yes, like scrollViewDidScroll, it gets called a lot! But if you think about it, the only way to detect with certainty if any subview has been scrolled off, is to check when any scrolling occurs.
So the key is to be as efficient as you can checking. The first thing I'd try is fast enumeration of the subviews, asking if each frame transformed by contentOffset falls within the parent's bounds (using CGRectIntersectsRect). If not, add it to your reuse pool and remove it from superview.
Subclass UIScrollView and override setContentOffset. That's where the scrollViewDidScroll message comes from in the original UITableView, and that's where you can implement your own logic.
Edit: you might want to study the source code for PSTCollectionView, which is not a custom UITableView but a custom UICollectionView.
I'm writing a simple iPhone app which lets a user access a series of calculators. It consists of the following:
UITableViewController (RootViewController), with the list of calculators.
UIViewController + UIScrollView (UniversalScroller), which represents an empty scroll view - and has a 'displayedViewController' property.
UIViewController (Calculators 1-9), each of which contains a view with controls that represents a particular calculator. Each calculator takes 3-5 values via UITextFields and UISliders, and has a 'calculate' button. They can potentially be taller than 460px(iPhone screen height).
The idea is:
User taps on a particular menu item in the RootViewController. This loads and inits UniversalScroller, ALSO loads and inits the UIViewcontroller for the particular calculator that was selected, sets the displayedViewController property of UniversalScroller to the newly loaded calculator UIViewcontroller, and pushes the UniversalScroller to the front.
When the UniversalScroller hits its 'viewDidLoad' event, it sets its contentSize to the view frame size of its 'displayedViewController' object. It then adds the displayedViewController's view as a subview to itself, and sets its own title to equal that of the displayedViewController. It now displays the calculator, along with the correct title, in a scrollable form.
Conceptually (and currently; this stuff has all been implemented already), this works great - I can design the calculators how I see fit, as tall as they end up being, and they will automatically be accommodated and displayed in an appropriately configured UIScrollView. However, there is one problem:
The main reason I wanted to display things in a UIScrollView was so that, when the on-screen-keyboard appeared, I could shift the view up to focus on the control that is currently being edited. To do this, I need access to the UniversalScroller object that is holding the current calculator's view. On the beganEditing: event of each control, I intended to use the [UniversalScroller.view scrollRectToVisible: animated:] method to move focus to the correct control. However, I am having trouble accessing the UniversalScroller. I tried assigning a reference to it as a property of each calculator UIViewController, but did't seem to have much luck. I've read about using Delegates but have had trouble working out exactly how they work.
I'm looking for one of three things:
Some explanation of how I can access the methods of a UIScrollView from a UIViewController whose view is contained within it.
or
Confirmation of my suspicions that making users scroll on a data entry form is bad, and I should just abandon scrollviews altogether and move the view up and down to the relevant position when the keyboard appears, then back when it disappears.
or
Some pointers on how I could go about redesigning the calculators (which are basically simple data entry forms using labels, sliders and textfields) to be contained within UITableViewCells (presumably in a UITableView, which I understand is a scrollview deep down) - I read a post on SO saying that that's a more pleasing way to make a data entry form, but I couldn't find any examples of that online. Screenshots would be nice. Anything to make my app more usable and naturally 'iPhone-like', since shuffling labels and textboxes around makes me feel like I am building a winforms app!
I've only recently started with this platform and language, and despite being largely an Apple skeptic I definitely see the beauty in the way that it works. Help me solve this problem and I might fall in love completely.
Dan
If you have the particular calculator view, you should be able to get to the scroll view via the superview property (though there might be more than one intermediate view, so you might need the superview of the superview).
I'm having a fundamental problem with getting scrolling to work normally on my iPhone app. I have two views, each created in IB (although I've tried this programmatically and it makes no difference) which scroll very sloppily. Instead of the scrolling that we're used to (which is smooth and continues to scroll and eventually dampen and rubber band at the top/bottom), my scrolling only scrolls as long as my finger is in contact with the view. Swiping down quickly on a view has no more effect than swiping slowly. And when you scroll beyond the top or bottom, the view just stays there scrolled with empty area above/below.
One of my views is a UITableView and the other is a UIScrollView. Both have exactly the same problem and are in different XIBs, coupled to different classes, so this is why I think I'm missing a key concept in general.
My UITableView is a child to a UIView (since there is also a nav bar at the top) with my UIViewController's view connected to the UIView. The referencing outlets datasource and delegate are both hooked to the UITableView. Nothing is subclassed here aside from the ViewController of course which has overrides to populate the table.
In the second instance, I again have a non-subclassed UIView which my UIViewController's view is connected to. I have a subclassed UIScrollView as a child to the UIView and then a have a subclassed UIView (with larger size than the scroll view) as a child to the subclassed UIScrollView. This in itself seems ridiculously complicated to me, but I was not able to get scrolling working at all with fewer than 3 views (again there is a nav bar at the top of the non-subclassed UI-View). I am overriding drawRect: in my UIScrollView, which is putting the content up fine except for this scrolling issue.
Is there something I'm doing wrong organizationally? I've come across many suggestions on stackoverflow and other sites for UIScrollView and none make a difference. And I don't see anyone having scrolling issues with UITableView. I'm not pasting in any code because I would have to post full classes at this point (making the post ridiculously long) and I believe the problems to really lie with the way I'm using IB.
Thanks!!
OK, it turns out that this has nothing to do with UIKit. This code is part of a game I'm developing using cocos2d and that framework is what is causing the problem. For those who are developing on cocos2d, you cannot use FastDirector and expect scrolling to work in UIViews. Just remove any code like [[Director sharedDirector] useFastDirector] and everything will be fine.
Some code might help narrow down your problem.
In the mean time, try creating a new project in Xcode using the 'Navigation-based Application' template and take a look at how the navigation controller is being created in MainWindow.xib. Take a look at how the UITableViewController subclass called 'RootViewController' is defined and how the corresponding xib is setup too. You'll notice there is no UIScrollView explicitly defined anywhere but you get scrolling functionality from the tableview controller 'for free'.
This should give you a pretty good starting point down the right path. I question the need for overriding drawRect: without seeing some code or fully understanding your goal.
Take a look at:
http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIScrollView_Class/Reference/UIScrollView.html
http://developer.apple.com/iPhone/library/featuredarticles/ViewControllerPGforiPhoneOS/UsingNavigationControllers/UsingNavigationControllers.html