I have a Monotouch 6.0.10 iPhone app using the 6.1 SDK, but targeted to iOS 4.0 and up, where I am trying unsuccessfully to force just one of the views to portrait orientation, using ShouldAutorotateToInterfaceOrientation. It's now deprecated I realize, but nevertheless necessary to support iOS4/iOS5 devices.
To try to isolate the problem I wrote a minimal test app. It is XIB-less and has a UITabBarController with one tab. The tab has a UINavigationController and the UINavigationController has a UIViewController (with a hello world button to click).
In AppDelegate I have:
tabController = new TabController();
window.RootViewController = tabController;
In the UITabBarController and in the UINavigationController I have:
public override bool ShouldAutorotateToInterfaceOrientation(UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
In the UIViewController I have:
public override bool ShouldAutorotateToInterfaceOrientation(UIInterfaceOrientation toInterfaceOrientation)
{
if ( toInterfaceOrientation == UIInterfaceOrientation.Portrait )
{
return true;
}
else
{
return false;
}
}
Well, on an iOS 6.1 device at least, those ShouldAutorotateToInterfaceOrientation's seem to be completely ignored. Breakpoints there don't get reached, and if I force them to return false in every case, rotations still happen.
My understanding is that ShouldAutomaticallyForwardRotationMethods defaults to true so that would not seem to offer a solution. Have combed the forums with no luck, except a suggestion from Glen Schmidt here: iOS 6 rotations: supportedInterfaceOrientations doesn´t work? but unfortunately I'm lost on how to translate that to MonoTouch:
QUOTE
If you want to replicate the pre-iOS 6 behaviour where all the views in the navigation stack / tab bar have to agree on an allowable set of orientations, put this in your subclass of UITabBarController or UINavigationController:
- (NSUInteger)supportedInterfaceOrientations
{
NSUInteger orientations = [super supportedInterfaceOrientations];
for (UIViewController *controller in self.viewControllers)
orientations = orientations & [controller supportedInterfaceOrientations];
return orientations;
}
UNQUOTE
I understand also that I can't even hope to solve it just for my iOS6 users via ShouldAutoRotate/SupportedInterfaceOrientations because this would cause iOS4/IOS5 rotations to fail.
Any suggestion much appreciated!
Bill.
Found a solution that works, after quite a bit of thrashing about. Somebody might be able to improve on this.
PROBLEM
My app, based on SDK 6.1, targets iOS4, iOS5 and iOS6 devices. It needs to allow all screens to rotate, except for one which must be fixed in portrait orientation. The app has a UITabBarController, most tabs have a UINavigationController with stacked views beneath.
SOLUTION
For iOS4/iOS5 users, the key is the deprecated ShouldAutorotateToInterfaceOrientation() method in the app's root view controller (tab bar controller in my case). This method is not called automatically in any other view controller, but of course the root view controller can invoke a method of the same name in the current view controller.
For iOS6 users, the key is ShouldAutorotate() / GetSupportedInterfaceOrientations() in the app's root view controller. Again, these methods are not called automatically in any other view controller but the root view controller can invoke methods of the same name in the current view controller.
For my simple test app described in the original post:
In AppDelegate/FinishedLaunching:
window.RootViewController = tabController;
In AppDelegate:
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations (UIApplication application, UIWindow forWindow)
{
return UIInterfaceOrientationMask.All;
}
In TabController:
public override bool ShouldAutorotateToInterfaceOrientation(UIInterfaceOrientation toInterfaceOrientation) // iOS4/iOS5 only
{
try
{
UINavigationController navController = (UINavigationController)SelectedViewController;
UIViewController targetController = navController.ViewControllers[0];
if ( targetController.Title == "Greetings")
{
if ( toInterfaceOrientation == UIInterfaceOrientation.Portrait )
{
return true;
}
else
{
return false;
}
}
}
catch
{
return true;
}
return true;
}
public override bool ShouldAutorotate() // iOS6+ only
{
return true;
}
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations() // iOS6+ only
{
try
{
UINavigationController navController = (UINavigationController)SelectedViewController;
UIViewController targetController = navController.ViewControllers[0];
return targetController.GetSupportedInterfaceOrientations();
}
catch
{
return UIInterfaceOrientationMask.All;
}
return UIInterfaceOrientationMask.All;
}
In the view controller that needs to be portrait:
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations() // iOS6+ only
{
return UIInterfaceOrientationMask.Portrait;
}
My actual app needs something slightly more elaborate but along the same lines. For example in the tabbarcontroller:
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations()
{
try
{
UINavigationController navController = (UINavigationController)SelectedViewController;
if ( navController.Title == "Tracking" ) // Are we on the Tracking tab?
{
// Yes. Looking for RedLaser's BarcodePickerController
UIViewController targetController = navController.ViewControllers[1]; // BarcodePicker would be second on nav stack
string controllerType = targetController.GetType().Name;
if ( controllerType == "BarcodePickerController" ) // Is this BarcodePicker?
{
return UIInterfaceOrientationMask.Portrait; // Yes, force portrait orientation
}
}
else
{
return UIInterfaceOrientationMask.All; // No, allow any orientation
}
}
catch
{
return UIInterfaceOrientationMask.All; // Not BarcodePicker, allow any orientation
}
return UIInterfaceOrientationMask.All;
}
Related
The project (WPF) has these folders:
Views
ViewModels
SubViews
SubViewModels
How to get the Prism's ViewModelLocator working with them (Views> ViewModels & SubViews> SubViewModels), the solution I found only works with one convention:
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
{
var viewName = viewType.FullName.Replace(".ViewModels.", ".CustomNamespace.");
var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
var viewModelName = $"{viewName}ViewModel, {viewAssemblyName}";
return Type.GetType(viewModelName);
});
}
You could opt for registration of the pairs (not as bad as it sounds because you have to register for navigation anyway).
Alternatively, you implement both conventions one after the other - take the view's name, subtract "Views" and add "ViewModels" and try to get the view model's type. If that fails, subtract "SubViews" and add "SubViewModels" and try again. You could even check for cross combinations (e.g. "SubViews.ViewA" and "ViewModels.ViewAViewModel")...
I solved it by checking the viewType and based on it, I return the appropriate ViewModel type:
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
{
string prefix;
if (viewType.FullName.Contains(".SubViews."))
{
prefix = viewType.FullName.Replace(".SubViews.", ".SubViewModels.");
}
else
{
prefix = viewType.FullName.Replace(".Views.", ".ViewModels.");
}
var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
var viewModelName = $"{prefix}ViewModel, {viewAssemblyName}";
return Type.GetType(viewModelName);
});
}
So I have an application with navigation controller, the last one viewcontoller can be rotated to any orientation. And the others must be in portrait only. So I have troubles when we rotate the last viewController in landscape and then pressing back button on navigation controller. We go to previous one and see that layout are broken.
I thought the only way is to use something like this:
[[UIDevice currentDevice] performSelector:NSSelectorFromString(#"setOrientation:") withObject:(id)UIInterfaceOrientationPortrait]
(I know it's a hack and it would be preferred to avoid such things)
But wherever I tried it - it caused me with different layout problems. The usual methods like:
- (NSUInteger)supportedInterfaceOrientations
- (BOOL)shouldAutorotate
and so on for handle orientation are useless in this situation.
Thanks in advance.
I solved this problem for parent of those viewControllers who must be in portrait:
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationPortrait;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:YES];
}
For rotation viewController:
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskAll;
}
For Navigation Controller:
- (BOOL)shouldAutorotate {
BOOL result = self.topViewController.shouldAutorotate;
return result;
}
- (NSUInteger)supportedInterfaceOrientations {
NSUInteger result = self.topViewController.supportedInterfaceOrientations;
return result;
}
And added this to AppDelegate:
- (NSUInteger) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
if ([navigationController.topViewController isKindOfClass:[RotationViewController class]])
return UIInterfaceOrientationMaskAll;
else
return UIInterfaceOrientationMaskPortrait;
}
I am converting my app to ios6 but i am getting rotation problems.
Can some one help me which methods will be called when we rotate device
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation) toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self doLayoutForOrientation:toInterfaceOrientation];
}
- (void)doLayoutForOrientation:(UIInterfaceOrientation)orientation {
if (UIInterfaceOrientationIsPortrait(orientation))
{
//set the frames here
}
else
{
//set the frames here
}
}
These are the new methods in ios 6 where you can set the frames as per the orientation. Hope it will useful to you.
- (BOOL) shouldAutorotate
-(NSUInteger)supportedInterfaceOrientations
These are the new functions added to iOS 6.
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
-(void)viewWillLayoutSubviews
{
if([self interfaceOrientation] == UIInterfaceOrientationPortrait||[self interfaceOrientation] ==UIInterfaceOrientationPortraitUpsideDown)
{
//set the frames here
}
else if ([self interfaceOrientation] == UIInterfaceOrientationLandscapeLeft||[self interfaceOrientation] == UIInterfaceOrientationLandscapeRight)
{
//set the frames here
}
}
better go with this , the above method will call every time when you change the orientation of the device.
Handle the rotation with these methods
-(BOOL) shouldAutorotate
{
return NO;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
If some-view in rotating and you don't want such as UIImagePickerController just make a child class and override first method.
I am using a UIPageViewController with transitionStyle UIPageViewControllerTransitionStyleScroll and navigationOrientation UIPageViewControllerNavigationOrientationVertical
I also have a UIPanGestureRecognizer on the view and I want to disable page scrolling when the pan gesture is active.
I am trying to set the following when the gesture begins:
pageViewController.view.userInteractionEnabled = NO;
This seems to have no effect, or it appears to work sporadically.
The only other way I have found to do it (which works) is to set the UIPageViewController dataSource to nil while the pan gesture is running, however this causes a huge delay when resetting the dataSource.
UIPageViewController uses some UIScrollView object to handle scrolling (at least for transitionStyle UIPageViewControllerTransitionStyleScroll). You can iterate by controller's subviews pageViewController.view.subviews to get it. Now, you can easly enable/disable scrolling:
- (void)setScrollEnabled:(BOOL)enabled forPageViewController:(UIPageViewController*)pageViewController
{
for (UIView *view in pageViewController.view.subviews) {
if ([view isKindOfClass:UIScrollView.class]) {
UIScrollView *scrollView = (UIScrollView *)view;
[scrollView setScrollEnabled:enabled];
return;
}
}
}
For those who are using swift instead of objective-c, here is Squikend's solution transposed.
func findScrollView(#enabled : Bool) {
for view in self.view.subviews {
if view is UIScrollView {
let scrollView = view as UIScrollView
scrollView.scrollEnabled = enabled;
} else {
println("UIScrollView does not exist on this View")
}
}
}
Everyone is complicating this very very much.
This is the whole function you need to disable or enable the scroll.
func enableScroll(_ enable: Bool) {
dataSource = enable ? self : nil
}
Swift 4.2 Version of the answer
func findScrollView(enabled: Bool) {
for view in self.view.subviews {
if view is UIScrollView {
let scrollView = view as! UIScrollView
scrollView.isScrollEnabled = enabled
} else {
print("UIScrollView does not exist on this View")
}
}
}
then yourpagecontorller.findScrollView(enabled: false)
You may also disable gesture recognizers.
for (UIGestureRecognizer *recognizer in pageViewController.gestureRecognizers)
{
recognizer.enabled = NO;
}
Unlike the popular answer, which relies on existing of the inner UIScrollView, this one uses public gestureRecognizers array. The underlying scroll view may not exist if you use book-style paging.
I am using the WPF webbrowser and basically when I load an external url, i want to filter any pages that are loaded to make sure the url doesnt contain a swear or porn type word.
This is easy to do on page load, as I check the URL against my List badwords; I have also set up a Load Completed method which gets me the url of clicked words, however this isnt working properly :-
void webBrowser1_LoadCompleted(object sender, NavigationEventArgs e)
{
mshtml.IHTMLDocument2 doc = (mshtml.IHTMLDocument2)this.webBrowser1.Document;
foreach (IHTMLElement link in doc.links)
{
HTMLAnchorElement anchor = link as HTMLAnchorElement;
if (anchor != null)
{
HTMLAnchorEvents_Event handler = anchor as HTMLAnchorEvents_Event;
if (handler != null)
{
handler.onclick += new HTMLAnchorEvents_onclickEventHandler(delegate()
{
uxURLText.Text = anchor.href;
//if (HelperClass.isNotFile(anchor.href))
// {
if (basepage.nonSafeWords.WordsContainSwearWord(anchor.href))
{
System.Windows.MessageBox.Show(basepage.INTERNET_RESTRICTION_NOTICE);
}
else
{
System.Windows.MessageBox.Show("Word Ok");
}
return true;
});
}
}
}
}
I need to basically stop any bad content from loading in the window, either from link, button, or ajax if a bad link is clicked a popup needs to notify us. I also need to show the current url in the address bar
Please help many thanks
:)
Listen to the WebBrowser.Navigating Event (docs) and check the Uri in NavigatingCancelEventArgs. Then set e.Cancel = true if you to not want to allow the navigation.
But your valid Uri check is the more complex problem.
private void webBrowser1_Navigating(object sender, NavigatingCancelEventArgs e)
{
string currentURl= e.Uri.ToString();
_addrBox.Text = currentURl;
}
this was the solution in my case.
maybe itll help somebody