Present a UIScrollView when opening an App for the first time - ios

I have an iPad App that I want to be compatible from iOS 5.0 to 6.0. My main view contains a scroll view z-indexed on the front, which is initially set to hidden. I also have a toolbar containing a button that cycle the scroll view hidden or not.
I would like to add a feature to present the scroll view as initially visible when the user opens the App for the first time to make the help visible by default to new users.
My code to cycle between visible and hidden is the following:
- (void)showHelpView:(id)sender {
BOOL hidden = [blackTranslucent isHidden];
[self.view bringSubviewToFront:scrollViewOutlet];
if (hidden) {
[scrollViewOutlet setHidden:FALSE animationStyle:KGAnimationFade duration:0.7];
[blackTranslucent setHidden:FALSE animationStyle:KGAnimationFade duration:0.5];
}
else {
[scrollViewOutlet setHidden:TRUE animationStyle:KGAnimationFade duration:0.5];
[blackTranslucent setHidden:TRUE animationStyle:KGAnimationFade duration:0.7];
}
}
where the sender is my toolbar button, blackTranslucent is a view on top of the main view and scrollViewOutlet is my scroll view IBOutlet.

Add a property "isNewUser" on NSUserDefaults in the application:willFinishLaunchingWithOptions: method which will only be written once by checking if the key exists.
In your main view in the viewDidLoad check this property if true make the view visible and update the key to false. if not just continue regularly.
Further information on NSUserDefaults
Hope that helps

Related

Subview keeps moving when I push and pop navigation controller

image before pushing
This is what it's supposed to look like originally. The slider's added as a subview of the main view from Xib file on viewWillLoad, and I don't add it again if the subview exists on viewDidLoad. When I push, I call hidesBottomBarWhenPushed on the other view controller.
This is what I happens when I pop back:
image after popping
I have no idea why the subview does that.
Whatever you have set for bottom slider in viewDidLoad is the first time setting when view comes appear on screen. After that you have hide slider on push action, and goes to second view….right?
But when you come back to your view with pop, then how view can identify that it have show or hide that slider…? So, when you come back-I mean pop that time viewWillAppear is called. Put you code there…
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// whatever you want to do, this is just for suggestion
if (bottomSlider.hidden == TRUE) {
bottomSlider.hidden = FALSE;
}
else {
bottomSlider.hidden = TRUE;
}
}

Keep button pressed down through view controller switch

I am currently creating a view which should appear when a user presses a button, and disappear as soon as they release a different button in the same place as the previous one. The only problem is that when the new view appears - when the view controller is switched - the new button appears deselected, despite it being set to selected and/or highlighted in its class's viewDidLoad method.
Code
override func viewDidLoad{
seeBillButton.selected = true
seeBillButton.highlighted = true
}
Thanks in advance!

View set as inputAccessoryView throws exception when added back into normal view

I have a text view, some decorations etc. in a view and I want that view to dock on keyboard, just like any other messaging app.
When I'm about to display my text view, here is how I attach my view to the keyboard:
-(BOOL)textViewShouldBeginEditing:(UITextView *)textView{
UIView *inputView = self.textInputView; //connected at IB outlet from storyboard, also contains the text view itself.
constraintsOfTextInputView = [self constraintsRelatedToView:inputView]; //to be able to add them again
[[UIApplication sharedApplication].keyWindow addSubview:self.textInputView];
textView.inputAccessoryView = inputView;
editingTextView = textView;
return YES;
}
And when dismissing:
//using notification hook for UIKeyboardWillHideNotification because
//textView[Will|Did]EndEditing is called too late
-(void)keyboardWillHide{
if(editingTextView && constraintsOfTextInputView){
editingTextView.inputAccessoryView = nil;
[self.textInputView removeFromSuperview];
[self.view addSubview:self.textInputView]; <--- EXCEPTION
[self.view addConstraints:constraintsOfTextInputView];
[self.view layoutIfNeeded];
editingTextView = nil;
constraintsOfTextInputView = nil;
}
}
Even though I'm doing exactly the opposite of what I do when adding, I'm getting this exception:
*** Terminating app due to uncaught exception
'UIViewControllerHierarchyInconsistency', reason: 'child view controller:
<UICompatibilityInputViewController: 0x13307ba20> should have parent view
controller:<ULPostViewController: 0x1307a7c00> but actual parent is:
<UIInputWindowController: 0x12f0be200>'
How can I get rid of this problem? I'm on iOS 8 (and don't support older versions).
UPDATE: I've created a git repository demonstrating the problem:
https://github.com/can16358p/CPInputAccessoryTest
You are abusing the inputView for something that it's not. The input view should be used for views the user an input data with, the input accessory view something you may want to extend that with. But its supposed be something like a keyboard.
Your text view is NOT part of that. It is the view the user is inputting data into. Decide if you want the view as an input view or in the main view hierarchy, but don't move it around before the two.
Your real problem is that you want to move the text view when the keyboard appears in order to keep it visible. To do so, observe the keyboard notifications
UIKeyboardWillShowNotification
UIKeyboardDidShowNotification
UIKeyboardWillHideNotification
UIKeyboardDidHideNotification
and move your views around accordingly. You can adjust the view controller's view's bounds origin for example, to move everything up.
You can use the text view as an input accessory view of the entire view controller. See my pull request.
Except for the growing text view part, this is pretty much the behavior of the Messages app.

How can I assign a pointer to the keyboard before I have assigned first responder

I am trying to create a user interface enabling users to switch between the keyboard and other menus when using a chat application.
On a click of the textField bar I want to raise either the keyboard or a collection view.
The problem occurs when I click the 'menu' button. I want the textField bar to raise revealing my menu view. Then, on a click on the keyboard button, instantly switch to the keyboard, rather than having it slide up from the bottom. This means I need to have the keyboard already loaded and hidden but in the background of the app.
Currently though the earliest I am managing to assign a variable to the keyboard is in the keyboardDidShow function.
-(void) keyboardDidShow: (NSNotification *) notification {
// Get the window the keyboard is a subview of
_window = [UIApplication sharedApplication].windows.lastObject;
_keyboard = _window.subviews[0];
}
This means that after it has been loaded once I can hide and reveal it, but I don't want it visible when it is loading this first time.
To achieve this using alternate means I have tried adding my extra views as subviews of the UIWindow the keyboard is created in:
[_window addSubview:_menuView];
[_window addSubview:_gamesView];
[_window addSubview:_stickerView];
[self hideSpecificView];
Unfortunately I keep coming across the same problem, until I have loaded the keyboard once it needs to fully load before I can get a pointer to it to hide it.
Here is a picture of my toolBar incase I am not being clear:
On clicking the menu icon or the stickers icon I want the bar to raise with a collection view. If I then click the textfield, with these views visible, I want to hide the visible view to immediately show the keyboard behind.
I have also tried experimenting with keyboardWillShow but as the window hasn't been loaded in front our screen I can't get a pointer to the keyboard to hide it before it loads.
An example of what I am after can be found many chat apps (facebook messenger, LINE, Kakao Talk)
Any help would be greatly appreciated
Although the way I came up with isn't perfect it works almost perfectly so hopefully this might help people in the future. If anyone else has solved it differently please post as it would be interesting to know how you did it.
I started by adding a class variable to a UIWindow in my header file and then setting off a timer to ping just after the keyboard will show method finishes. After this method has finished the keyboard has been created, just, and so I allocate it and hide it.
-(void) keyboardWillShow: (NSNotification *) notification {
// More keyboard code
_window = [UIApplication sharedApplication].windows.lastObject;
[NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:#selector(allocateKeyboard)
userInfo:nil
repeats:NO];
}
- (void)allocateKeyboard {
if (!_keyboard) {
_keyboard = _window.subviews[0];
}
_keyboard.hidden = YES;
[self setViewForButtonType];
}
I have already previously added my other views, hidden them and constrained them to the bottom of the main view, this means that when the keyboard rises they do too.
- (void)viewDidLoad {
[self.view addSubview:_menuView];
[self.view addSubview:_gamesView];
[self.view addSubview:_stickerView];
}
...
- (void)hideViews {
_keyboard.hidden = YES;
_menuView.hidden = YES;
_gamesView.hidden = YES;
_stickerView.hidden = YES;
}
When buttons get pressed I simple then unhide the view that I want to see and hide the rest of the views.
When I say that this method doesn't work perfectly it is because if you load view main view and then click a button before the keyboard has loaded for the first time then you get a quick glimpse of the keyboard before the view appears over the top. This though only happens the first time and only if they don't click in the text field first.
Anyway, I found this was the best way of making views look like they are in front of the keyboard. Obviously my code was a lot longer and more complex (too long for here) but this is the gist of the method I used to solve it. Comment if you have any queries and I hope this helps.

iOS Subviews added programmatically are lost when view is reloaded from the storyboard

I have an app with two view controllers. ViewControllerA is a blank view with a tap gesture assigned which allows the user to tab on the view and create a UITextView at the point of the tap. The user can create as many UITextViews as they wish and they are added then programmatically to the view (ViewControllerA) as sub views.
There is also a button which allows the user to change the text font and styling. This triggers a Segue to the second view controller ViewControllerB which then allows the user to set Font, Text Size, Color etc. Once completed the user clicks the DONE button on ViewControllerB and another Segue switches back to the initial view (ViewControllerA).
This all works fine. Except when the user switches back to the initial view (ViewControllerA) from ViewControllerB the view is reloaded from the storyboard and the sub views I have added programmatically are gone.
In view (ViewControllerA) ViewDidLoad and ViewWillAppear are firing just fine so the problem seems to be the initial view is released when the first Segue fires and then recreated from the storyboard on the transition back but the subviews are of course not included as they are not in the storyboard since I added them programmatically.
Any suggestions for a best practice on how to solve this so that the subviews are recreated also when the main view (ViewControllerA) reloads?
Many thanks for any suggestions!
From the question it sounds like you had a segue to the text styles view, then another segue "back to the original" - it doesn't work like that, segues always make new instances of the destination VC. You should have had a modal segue to the text styles view, then dismissed the modal view controller - this would return to your original instance.
Just for the record, I solved this as follows in case anyone else needs a solution.
I created a subview in ViewControllerA which is the size of the main view excluding the Toolbar. I call this canvasView. Then I add all of my ImageViews and TextViews to this canvas view.
Then in ViewControllerA viewWillDisappear I archive the canvasView and all of its subviews to a file like this.
NSString *archivePath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"Canvas.archive"];
BOOL result = [NSKeyedArchiver archiveRootObject:_canvasView
toFile:archivePath];
if (!result) {
NSLog(#"Archive failed to archivePath %#",archivePath);
}
Then in ViewControllerA viewWillAppear I check if there is an existing archive and if so reload it which loads the sub views in the correct order. Otherwise I create an empty canvasView like this.
// If the collageView already exists then restore it from the achive, otherwise initialize a new one.
NSString *archivePath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"Canvas.archive"];
_canvasView = [NSKeyedUnarchiver unarchiveObjectWithFile:archivePath];
if (_canvasView) {
// Restore existing canvasView
[_backgroundView addSubview:_canvasView];
} else {
// Initialize a new canvasView
_canvasView = [[UIScrollView alloc] initWithFrame:CGRectMake(_backgroundView.frame.origin.x,
_backgroundView.frame.origin.y,
_backgroundView.frame.size.width,
_backgroundView.frame.size.height)];
[_backgroundView addSubview:_canvasView];
}

Resources