I have a page-based application in Xcode and I am trying to set it up so that the left page and right page have different layouts in landscape mode.
Specifically, I want to set a different page bg image if the page is the on the left side, so that it looks more like a real book.
Is there a way to programmatically detect if a UIPageViewController is on the left or right side in landscape mode? How would you go about solving this problem?
If you have a property for the background image, you can change it on the viewControllerAtIndex
- (YourPageContentViewController *)viewControllerAtIndex:(NSUInteger)index {
// Return the data view controller for the given index.
if (([self.modelArray count] == 0) || (index >= [self.modelArray count])) {
return nil;
}
YourPageContentViewController *dataViewController [[YourPageContentViewController alloc]initWithNibName:#"YourPageContentViewController" bundle:nil];
if (index%2 ==0) {
//set a background
dataViewController.backgroundImage = imageForLeftSide;
} else {
//set the other background
dataViewController.backgroundImage = imageForRightSide;
}
dataViewController.dataObject = [self.modelArray objectAtIndex:index];
return dataViewController;
}
Related
I've got an NSSplitView with a table view in the left pane. I've noticed that when I have an item selected in the left pane and I change focus to the right pane, the left pane loses focus and the highlighted row's highlight color turns to gray and the text turns black.
I have overridden the highlight color by overriding drawSelectionInRect in NSTableRowView. By doing this, the highlight color remains the same custom color, but the text turns dark which looks wrong.
Can I either let the highlight color change when the table view is out of focus, or prevent the text from turning dark when it's out of focus?
It appears that OS X calls setBackgroundStyle on the row view and its subviews when you click on the other view in the split view. Interestingly it seems to only happen to NSOutlineView.
Since I have code in place already to handle changing my images to different images when rows are selected (for improved contrast), and I am explicitly setting the background style when I need to using outlineViewSelectionDidChange and outlineViewSelectionIsChanging I overrode setBackgroundStyle to be a no-op and I made my own custom setter which changed the _backgroundStyle ivar.
It looks like this:
#implementation TextFieldWithHighlighting
#synthesize backgroundStyle = _backgroundStyle;
- (NSBackgroundStyle) backgroundStyle {
return _backgroundStyle;
}
#synthesize secretBackgroundStyle = _secretBackgroundStyle;
- (NSBackgroundStyle) secretBackgroundStyle {
return _backgroundStyle;
}
- (void)setBackgroundStyle:(NSBackgroundStyle)backgroundStyle {
}
- (void) setSecretBackgroundStyle:(NSBackgroundStyle)secretBackgroundStyle {
_backgroundStyle = secretBackgroundStyle;
self.needsDisplay = YES;
}
- (void)drawRect:(NSRect)dirtyRect {
if(_backgroundStyle == NSBackgroundStyleDark) {
if(self.originalTextColor == nil) {
self.originalTextColor = self.textColor;
}
self.textColor = [NSColor whiteColor];
} else {
if(self.originalTextColor) {
self.textColor = self.originalTextColor;
} else {
self.textColor = [NSColor colorWithCalibratedRed:0x40/255.0 green:0x40/255.0 blue:0x41/255.0 alpha:0xFF/255.0];
}
}
[super drawRect:dirtyRect];
}
#end
It only works for me because I am explicitly handling rows changing their selection and AFAIK I am not relying anywhere on the OS changing it for me. If I could do it again I'd just push for using the system highlight color in which case I get this functionality for free.
Just as a small contribution to your answer. This works as well with the weird contrast generated with the drawSelectionInRect implementation. Here's a Swift solution that also works implemented in an NSTableCellView:
override var backgroundStyle: NSBackgroundStyle {
get {
return self.backgroundStyle
}
set {
}
}
new iOS developer here. I have multiple views that require different images to be displayed in portrait and landscape. I currently have implemented that successfully and the portrait image loads fine, and, upon rotation, the landscape image also loads fine. However, if the device is in landscape orientation then switches to another view, it loads improperly - wrong size, resolution, alignments, etc. My code for dealing with orientation changes is below:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if((self.interfaceOrientation == UIDeviceOrientationLandscapeLeft) || (self.interfaceOrientation == UIDeviceOrientationLandscapeRight))
{
_image1.image = [UIImage imageNamed:#"Landscape.png"];
}
else if((self.interfaceOrientation == UIDeviceOrientationPortrait) || (self.interfaceOrientation == UIDeviceOrientationPortraitUpsideDown))
{
_image1.image = [UIImage imageNamed:#"Portrait.png"];
}
}
I believe it is because the method is only called upon rotation. If I rotate the improper, initial landscape view, for instance, it displays the correct images once again. Is there a way to get the method to run and load the proper landscape view when the initial orientation is in landscape? Or a way to force the correct image to display? Thanks much.
I finally fixed this issue by adding an orientation checker. I added the following in my .h:
#property (nonatomic, readonly) UIDeviceOrientation *orientation;
Then I added this to my .m file in the viewDidLoad method:
if(([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft) || ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight)) {
_image1.image = [UIImage imageNamed:#"Landscape.png"];
}
This checks if the initial orientation is landscape. If it is, it loads my Landscape.png image. Otherwise, since the default image is my Portrait.png, as set in the Storyboard, that loads if the orientation is already in portrait. Cheers!
EDIT: The above code is not advised as you can run into issues when using it, such as with orientation-locked devices. I changed the it to check for the status bar's orientation, rather than the device's orientation, as below:
if(([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft) ||
([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeRight)) {
_image1.image = [UIImage imageNamed:#"Landscape.png"];
}
You do not need to declare any variables in the .h, and just add the above in the viewDidLoad method.
With Cocoa, how do I check if the mouse is inside a specified window of mine? I have the following code that detects if it's within the bounds of the window, but it incorrectly prints that it's inside if the window is closed/hidden but the mouse is still in that rectangle. It will also incorrectly say it's inside if another window is on top of it, but the mouse is within the region of the window I'm testing below it.
NSPoint mouse = [NSEvent mouseLocation];
BOOL mouseInside = NSPointInRect(mouse, self.window.frame);
if (!mouseInside) {
NSLog(#"mouse isn't inside");
} else {
NSLog(#"mouse is inside");
}
I've tried something like this:
while ((screen = [screenEnum nextObject]) && !NSMouseInRect(mouse, [screen frame], NO));
if (screen != self.window.screen && mouseInside) {
NSLog(#"mouse is inside.");
}
but it would always print "mouse is inside".
Any ideas? Or is setting up a tracking area the only way?
mikeash on Freenode pointed me to NSWindow's windowNumberAtPoint:
The following code appears to work as needed:
if ([NSWindow windowNumberAtPoint:mouse belowWindowWithWindowNumber:0] != self.window.windowNumber) {
NSLog(#"mouse outside");
}
UPDATE:Solved issue, see below!
The situation: I have several dynamically loaded UIViews on a UIScrollView in a nib.
Expected behavior: I want to single TAP any one of the UIViews and it will change background color to indicate it was tapped. If it was already tapped it should then change back to its initial look.
I have set up a UITapGesture recognizer on each of the UIViews and here is the selector method where I am doing the behavior. I have confused myself. I apologize for the sketchy logic here (it is a ruff draft). I have set up a isTapped BOOL set to "NO" initially in the init in the file.
- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer {
isTapped = !isTapped;
UIView *v = gestureRecognizer.view;
NSInteger currentIndex = [studentCellArray indexOfObjectIdenticalTo:v];
if (oldIndex != currentIndex) {
isTapped = YES;
}
//check to see if obj in array then switch on/off
if ([tappedViewArray indexOfObjectIdenticalTo:v] != NSNotFound) {
oldIndex = currentIndex;
}
if (currentIndex == v.tag) {
isTapped = !isTapped;
}
if (isTapped) {
[tappedViewArray addObject:v];
[super formatViewTouchedNiceGrey:v];
}else{
[tappedViewArray removeObject:v];
[super formatViewBorder:v];
}
if (currentIndex == oldIndex) {
isTapped = !isTapped;
}
}
Actual Behavior: After Tapping the First UIView it selects fine and changes, a second tap will change it back, however after successive taps it stays selected. Also, if you select a UIView and go to another view - you have to double tap the successive views.
I would like to just tap once to turn off or on any of the UIViews in the scrollview.
UPDATE: Well, after some Hand writing and other vain attempts at trying to focus on this issue ---- I have solved it this way and it BEHAVES properly!
here is my solution:
- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer {
isTapped = !isTapped;
UIView *v = gestureRecognizer.view;
NSInteger currentIndex = [studentCellArray indexOfObjectIdenticalTo:v];
if (((isTapped && currentIndex != oldIndex) || (!isTapped && currentIndex != oldIndex)) && [tappedViewArray indexOfObject:v] == NSNotFound) {
oldIndex = currentIndex;
[tappedViewArray addObject:v];
[super formatCornerRadiusWithGreyBackgrnd:v];
} else {
[super formatViewBorder:v];
[tappedViewArray removeObject:v];
}
}
So I hope this helps someone with this issue.
The key was to check for the isTapped and indexes being not equal AND the view object NOT being in the array I was assembling to indicate items touched/Tapped....
I have this iPad application with different NIBs and views.
Each view has two NIBs, one for potrait orientation and one for landscape, so i'm searching for a method to programmatically switch NIB for a given UIViewController .
Right now i have this function that i'm using in the willRotateToInterfaceOrientation method of each controller :
void UIHandleRotation( UIViewController *controller, NSString *nibName, UIInterfaceOrientation orientation, BOOL transform ){
double angle = 0.0;
if( orientation == UIInterfaceOrientationPortrait ) {
angle = PI * 2 /* 360° */;
}
else if( orientation == UIInterfaceOrientationLandscapeLeft ){
angle = PI + PI/2 /* 270 ° */;
// Each landscape nib is [nib-name]L
nibName = [NSString stringWithFormat:#"%#L", nibName];
}
[[NSBundle mainBundle] loadNibNamed:nibName owner:controller options:nil];
if( transform ) {
controller.view.transform = CGAffineTransformMakeRotation( angle );
}
}
But it's giving me strange behaviour (ui controls position messed, the outlets are not associated as in interface builder, and so forth).
Am i doing something wrong or there's just a better way to implement this ?
Thanks
NOTE: I'm not using a navigation controller, so i can't use this solution Easiest way to support multiple orientations? How do I load a custom NIB when the application is in Landscape?
You should use only one NIB with two views, one for portrait(potraitView) with frame(0,0,768, 1024)and
another for landscape(landScapeView) with frame(0,0,1024, 768).
And set your controls in both views (potraitView and landScapeView) according to your requirements.
and after this you can set your views according to device orientation as-
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if(interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
landScapeView.hidden = YES;
portraitView.hidden = NO;
}
else{
landScapeView.hidden = NO;
portraitView.hidden = YES;
}
return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation == UIInterfaceOrientationLandscapeRight || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
}
Hi,
As I think you want to know, when the view loads, what is the default orientation, and How I can load the view according to this orientation.
If this question is same as you are asking, then the answes is-
When you run your application and the same class view loads, then - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
method is called automatically. Then it returns your device orientation, and sets your view according to this orientation(using the same code as described above).
I think you need not to do more.
You shouldn't switch nibs, you should switch controllers.
See this answer for: Easiest Way to Support Multiple Orientations
you need to have one view per nib, so your UIViewController will have two UIViews. one for portrait, and one for landscape.
Why do you need to use 2 nibs for the same view.You should use one nib for different orientations.You can handle the required controls programatically in the same method
willRotateToInterfaceOrientation
Thanks.