I have a Cordova app that is since recently using WKWebViewEngine and I noticed horizontal and vertical scrollbars appearing since switching.
I researched and the issue is documented at:
https://issues.apache.org/jira/browse/CB-10123
A CSS fix does not work but there is apparently a fix with using:
self.wkWebView.scrollView.showsVerticalScrollIndicator = NO;
self.wkWebView.scrollView.showsHorizontalScrollIndicator = NO;
The question is where do I add this fix? I checked in CDVWKWebViewEngine.m but am not sure where to add it.
In case it helps, in a pure iOS app those 2 lines of code :
self.wkWebView.scrollView.showsVerticalScrollIndicator = NO;
self.wkWebView.scrollView.showsHorizontalScrollIndicator = NO;
would typically be placed within the view controller viewDidLoad function.
I don't know the details of Cordova, but you should find your view's view controller (could be CDVViewcontroller in CDVViewcontroller.m (?)) and add those lines at the end of the viewDidLoad method.
Alternatively (and certainly cleaner), you could subclass CDVViewcontroller into your own ViewController class and override viewDidLoad like this
- (void)viewDidLoad {
[super viewDidLoad];
self.wkWebView.scrollView.showsVerticalScrollIndicator = NO;
self.wkWebView.scrollView.showsHorizontalScrollIndicator = NO
}
then find a way to force Cordova to use your view controller class instead of its own.
Take care, in the codes I've read, the web view property is called webView and not wkWebView, so you might need to change that in your two lines.
Related
I need to update a constraint programmatically in my project to adjust a view's height accordingly (based on different subviews). I've made outlet of the constraint in my controller but facing an issue.
when I try to update this for the first time (in viewDidLoad or viewWillAppear method), it's not updated. and if i update it afterwards (because of some rotation etc), then it is done correctly. Kindly tell me why this is happening and what is the right way/place to do this? (As i feel that the constraint is updated somewhere again after my updation in viewWillAppear/DidLoad).
I tried view.layoutIfNeeded as well but it didn't help. I guess it has something to do with viewDidLoad and other viewController delegate methods
P.S. I'm also using size classes in my project but I think it has nothing to do with that as it's working in some cases.
Updating constraints may not work in viewWillAppear.
It will, however, work in viewDidAppear.
There are other places you may overwrite, such as: (using static BOOL shouldRefreshView = NO; for the first time)
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if(shouldRefreshView) {
shouldRefreshView = NO;
[self.view layoutIfNeeded];
}
}
Using Storyboards in XCode5 for iOS7, I unchecked the "Clear on Appearance" checkbox for a UITableViewController. Using the version editor, I could see that the actual text in the file reacted accordingly (btw, is there a better way to see "source" of the storyboard?). But when I added
-(void) viewDidLoad {
[super viewDidLoad];
NSLog(#"clear on appear %d", self.clearsSelectionOnViewWillAppear);
}
It always showed as 1 (YES). Regardless of on or off in the storyboard. To get the desired affect, I had to add:
self.clearsSelectionOnViewWillAppear= NO;
to that method. Did I misunderstand the way this was supposed to work? Or is it broken?
Yes, seems like it is broken.
This works on viewDidLoad:
self.clearsSelectionOnViewWillAppear = NO;
Yes, looks like a bug, at least as of iOS 9.3. You can use IB's User Defined Runtime Attributes if you don't want to fix it in code:
I am trying to execute following code in viewDidLoad method of my single view controller project:
self.view.layer.frame = CGRectInset(self.view.layer.frame, 20, 20);
But it does not give the desired inset. However other UI changes i make in the same method do work e.g
self.view.layer.backgroundColor = [UIColor orangeColor].CGColor;
Above line of code does work and background is change to orange but the frame does not.
The inset works only if I place the line of code in viewDidAppear. I would like to understand the key reason for this behavior if anyone can explain. Thank you in advance.
I think the issue you are running into with this line:
self.view.layer.frame = CGRectInset(self.view.layer.frame, 20, 20);
can be explained like so :
in viewDidLoad, the properties are set, but the frame of the views are not yet defined.
by the time viewWillAppear is triggered, they will be set. That explains why that line of code works there.
But since iOS 5, there is another method called after viewDidLoad and before viewWillAppear in which the view frames are set : viewDidLayoutSubviews.
You can find the complete explanation of this in this season's Stanford CS193P course about iOS programming (very cool by the way).
So if you want it to work just once, use :
- (void)viewDidLayoutSubviews
{
self.view.layer.frame = CGRectInset(self.view.layer.frame, 20, 20);
}
PS : I posted this answer on Ray's forum too.
Regards,
Fred
The viewDidLoad method is too early to set your view's frame because something else is changing the frame later.
For example, if this is your root view controller, then the UIWindow object will set the view's frame when it adds the view to itself as a subview. The viewDidLoad method runs as soon as loadView returns, before any outside object (like the UIWindow) can get its hands on the view.
You can test this by using a custom view (if you're not already) and overriding setFrame: in the custom view class:
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
}
Put a breakpoint in that method and you'll see that the view's frame gets set some time after viewDidLoad returns.
Rob Mayoff's answer is correct and excellent, but putting it a slightly different way: viewDidLoad only means the view has loaded, i.e. that the view controller has obtained its view. It doesn't mean that the view has been placed in the interface. That, indeed, is one of the things that viewDidAppear: does mean — and that's why it worked when you ran your code there.
The trick in this sort of situation, where you want to initialize something about the view, is to do it late enough but do it only once. viewDidAppear: could easily be called again later, but you don't want to initialize the view again (unless it has been unloaded). In iOS 5, isMovingToParentViewController allows you to distinguish the particular circumstances you're looking for. Before that, it might be necessary to set up a BOOL flag so that you perform final initializations only once.
A related trap is what happens when the app launches into landscape orientation. Here, too, viewDidLoad is too soon because the interface has not yet rotated into landscape.
However, this issue should not be arising at all. It should be none of your business to inset a view controller's view. Either the view is the root view controller, in which case its size is correctly taken care of automatically, or it is the child of a parent view controller, in which case it is the parent view controller's job to size the view (as UINavigationController, for example, already does), or the view is to be presented modally, in which case its size will be set automatically to match the view it replaces. So I would suggest that you very question suggests you're doing something wrong.
Create your project with an older version of Xcode (for instance I'm using Xcode 4.3.3 for this) . Then you can use setFrame: method with viewDidLoad in any version of Xcode .
I also experienced this issue on Ray Wenderlich's tutorial 'Introduction to CALayers'.
http://www.raywenderlich.com/2502/introduction-to-calayers-tutorial
It seems shrinking the entire view controllers view is not the best thing to do. Instead create a sub view and call CGRectInset on that e.g in your view controllers viewDidLoad
UIView *viewToManipulate = [[UIView alloc] initWithFrame:CGRectMake(0.0,0.0, self.view.bounds.size.width, self.view.bounds.size.height)];
[self.view addSubview:viewToManipulate];
viewToManipulate.backgroundColor = [UIColor redColor];
viewToManipulate.layer.cornerRadius = 20.0;
viewToManipulate.layer.frame = CGRectInset(self.view.layer.frame, 20, 20);
I am working on an iOS SDK 4 project with ARC enabled.
My class MyTextView (derived from UITextView with UITextViewDelegate protocol) implements the following static method:
+ (void)showInViewController:(UIViewController*)viewController
{
MyTextView *textEdit = [[MyTextView alloc] init];
textEdit.delegate = textEdit;
[viewController.view addSubview:textEdit];
// Show the keyboard
[textEdit becomeFirstResponder];
}
In one of my view controllers I call the following:
[MyTextView showInViewController:self]
This crashes with warning: Unable to restore previously selected frame. on becomeFirstResponder. Looks like some stack related crash because of some cycle. I am fairly new to ARC. The delegate property of UITextView is defined as assign (shouldn't ARC interpret that as weak?). I know this approach is rather strange memory-wise. However, I wanted to know if ARC can handle things like that. Obviously it can't. Any idea what might be the problem and how to solve it?
I don't think it has anything to do with the ARC and memory management, but just a more fundamental problem that a UITextView cannot be a delegate of itself. It gets locked in a loop. Put a logging message in textViewDidChangeSelection and you'll see it gets repeatedly invoked. Not a memory issue, methinks, but rather just a logic issue with UITextView delegates. Even if you don't do your problematic showInViewController but just create a standard UITextView subclass and try to set its delegate to itself, you'll see the same curious behavior.
old post, but here is the answer:
http://www.cocoabuilder.com/archive/cocoa/282093-uitextview-as-its-own-delegate-infinite-loop-on-keyboard-select.html
or here aswell
self.delegate = self; what's wrong in doing that?
When using the the Three20 framework I have a problem with the way how TTNavigator seems to work. If in applicationDidFinishLaunching I restore the previous state of the app with:
TTNavigator* navigator = [TTNavigator navigator];
navigator.persistenceMode = TTNavigatorPersistenceModeAll;
navigator.window = self.window;
[navigator restoreViewControllers];
The methods loadView and viewDidLoad of the ViewController that was just restored never get called. How can that be so?
Is that a bug or by design?
If it's by design, what would be a good fix. My problem is that I want the ViewController to load its nib. I've seen other workarounds, but they are ugly and have outside component (like the app delegate instead of the view controller itself) load the nib, which I would like to avoid. An example of those ugly workarounds is given in the TTNibDemo example that ships with the Three20 source code.
It depends in what way you are calling viewController, try in viewWillAppear, should work.
Are you testing on device?
navigator.window = self.window;
_ [navigator restoreViewControllers];
On the device the first screen is always the first screen, whereas on the simulator that is not the case, and you should always check before with the condition
if(![navigator restoreViewControllers])
// do this
else
TTNavigationController* navi = [[((MyViewController1*)[navigator topViewController]) viewControllers] objectAtIndex:0];