So in my app I have a popover control with an embedded navigation control. In different parts of the navigation stack, I want the popover to be different colors depending on where the user is. The weird thing is sometimes setting the popover background color makes this terrible looking box around it, sometimes it doesn't. It looks like this:
This is the look I am trying to get:
It seems if I change the background color before displaying the popover it seems to work and transition correctly, but if I don't set the popover color before showing it, then change it after it has been shown it has the box effect. I've also noticed other cases where it seems to happen randomly, but I can't really explain what is causing it (my real app is much more complex than this demo). Here is the relevant code:
- (IBAction)buttonPressed:(id)sender {
UIViewController *vc = [[UIViewController alloc] init];
UIButton *b = [[UIButton alloc] init];
[b addTarget:self action:#selector(innerButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[b setTitle:#"Button" forState:UIControlStateNormal];
[b setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[b setFrame:CGRectMake(0,0,100,100)];
[vc.view addSubview:b];
_innerNav = [[UINavigationController alloc] initWithRootViewController:vc];
_popOver = [[UIPopoverController alloc] initWithContentViewController:_innerNav];
//If this line is here, everything works fine
_popOver.backgroundColor = [UIColor yellowColor];
[_popOver presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
//If this line is here (and the above line is commented out), the transition will look wrong
//_popOver.backgroundColor = [UIColor yellowColor];
}
-(void)innerButtonPressed {
_controller = [[UIViewController alloc] init];
UIButton *b = [[UIButton alloc] init];
[b addTarget:self action:#selector(test) forControlEvents:UIControlEventTouchUpInside];
[b setTitle:#"Make Purple" forState:UIControlStateNormal];
[b setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[b setFrame:CGRectMake(0,0,200,200)];
[_controller.view addSubview:b];
[_popOver setBackgroundColor:[UIColor orangeColor]];
[_innerNav pushViewController:_controller animated:YES];
}
-(void)test{
_popOver.backgroundColor = [UIColor purpleColor];
}
Any idea what is causing this issue? And what steps to safely update the background color of a popover without ever getting into this state? I have a full project demonstrating the problem, I thought you could attach projects to questions but apparently you cannot. If someone wants it I can probably host it somewhere.
After looking at your sample project, Apple's "Popover Controllers in iOS" sample project, perusing Apple's Documentation, and trying a few different things I have come to the following observations:
The UIPopoverController only exhibits this odd behavior when it is presented without a valid value for the backgroundColor property. From this I am guessing that since UIPopoverController's backgroundColor property is nil by default it must use different drawing code than when the backgroundColor property is valid.
Triggering some sort of redraw (e.x. Setting popoverContentSize) will get the colored box overlay to go away (it looks like it clips a color layer).
Conclusion: For the time being I would set a backgroundColor prior to the UIPopoverController being presented and then update it as needed. If this is not an option try updating the UIPopoverController such that it redraws (As a note: I was not able to get this to look good and it seems hacky). Lastly, I would report it as a bug to apple.
I hope this helps.
UIPopoverController is now deprecated. I found a similar issue when updating it to use the new popoverPresentationController. In the past I was able to set the backgroundColor of UIPopoverController before presenting. The popover presentation controller also has a backgroundColor property but didn't work like it did before where I could assign it before presentation. To get it to work I had to assign it after it starts presenting for some reason:
contentViewController.modalPresentationStyle = UIModalPresentationPopover;
[[self presentViewController:contentViewController animated:YES completion:^{
// completion code
}];
contentViewController.popoverPresentationController.backgroundColor = [UIColor orangeColor];
For your particular scenario where you are changing the background color after presentation is finished I don't think you'd be able to do that by just changing the popoverPresentationController's backgroundColor. The only solution I can think of is to dismiss and re-present the popover without animating:
[self dismissViewControllerAnimated:NO completion:^{
contentViewController.modalPresentationStyle = UIModalPresentationPopover;
[[self presentViewController:contentViewController animated:NO completion:^{
// completion code
}];
contentViewController.popoverPresentationController.backgroundColor = [UIColor purpleColor];
}];
Related
I am using a UIRefreshControl in my UITableViewController to refresh the content. I use the following code in my -viewDidLoad method to add it to my table.
UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
//[refresh setAttributedTitle:[[NSAttributedString alloc] initWithString:#"Reloading" attributes:#{NSForegroundColorAttributeName : [UIColor lightGrayColor]}]];
[refresh setTintAdjustmentMode:UIViewTintAdjustmentModeNormal];
[refresh setTintColor:[UIColor colorFromHex:0xff8900]];
[refresh addTarget:self action:#selector(refresh) forControlEvents:UIControlEventValueChanged];
[[refresh layer] setZPosition:-1.0f];
//if (iOS_AT_LEAST(10)) {
// [self setRefreshControl:refresh];
//} else {
[self setRefresher:refresh];
[[self tableView] insertSubview:[self refresher] atIndex:0];
//}
I created a category for UIColor so it can accept hex values. I use this in the complete application and on another location I get #ff8900 back which is correct. But setting the tint color on the UIRefreshControl gives me #fb6a2e which is odd. The same happens when I try a default color, for example [UIColor lightGrayColor] gives me another tint than giving the same color to another view.
I have found the following post: UIRefreshControl tint color doesn't match given color. I tried to put it into an animation block and the hack given in the answer, but with no luck.
What do I do wrong here?
Another side question. When setting the attributed title, the spinner has a greater space from the top. If this happens, the title will be below the cell if only one is available. Is there a way to move the string up?
After rotation of iPad in my simulator i found a strange bug - my UIButton have visible title, it property enables is YES, but, its not work. I tried to set background colour of button to black, and found that after rotation it vanish. Please take a look at portrait mode (all work):
And landscape mode (not work):
This is how i create button (i doubt that it help though, because its pretty mundane):
self.readNextButton = [UIButton new];
self.readNextButton.backgroundColor = [UIColor blackColor];
// self.readNextButton.titleLabel.adjustsFontSizeToFitWidth = YES;
[self.readNextButton setTitleColor:[UIColor colorWithHexString:#"#60aabf"] forState:UIControlStateNormal];
self.readNextButton.titleLabel.lineBreakMode = NSLineBreakByClipping;
self.readNextButton.titleLabel.font = [UIFont fontWithName:#"Times New Roman" size:14];
[self.readNextButton setTitle:#"Читать дальше" forState:UIControlStateNormal];
[self.view addSubview:self.readNextButton];
Also, i want to notice that this bug appears even when i'm not rotating anything, but simply load app in landscape mode. And also, ENABLED property of button is 1 (mean YES), when i log it..
Button frame:
[self.readNextButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.containerForNewsText.mas_right).with.offset(-10.834);
make.bottom.equalTo(self.containerForNewsText.mas_bottom).with.offset(-10.834);
make.top.equalTo(self.truncatedNewsText.mas_bottom).with.offset(20);
}];
It is in a method 'createLandscapeConstraints', that called in end of viewDidLoad.
Image 1
Image 2
Image 3
1st image is the settings screen and everything behaves normally
upon the first loading of this screen.
2nd image is the policy
screen which is pushed from the settings screen.
3rd image upon returning from the policy screen back to the settings screen shows the UI Slider now doesn't show the track image. The behavior still works normally, but the track is just gone. It's a very mysterious bug to me. If I go to another screen in the app and then hit settings it works fine again, but when I come from the policy screen the track image is gone.
I am using the default UISlider. I am using xib files for the different screens.
When the Policy Button is clicked...
EditorialPolicyViewController *policyView;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
{
policyView = [[EditorialPolicyViewController alloc]initWithNibName:#"EditorialPolicyViewController_iPad" bundle:nil];
}
else
{
policyView = [[EditorialPolicyViewController alloc]initWithNibName:#"EditorialPolicyViewController_iPhone" bundle:nil];
}
[self.navigationController pushViewController:policyView animated:YES];
ViewDidLoad - setting up the uislider
NSString *textSize = [[NSUserDefaults standardUserDefaults] valueForKey:#"Text Size"];
float textSizeFloat = [textSize floatValue];
self.textSizeSlider.value = textSizeFloat;
[self.textSizeSlider setMaximumValue:16.0];
[self.textSizeSlider setMinimumValue:11.0];
Let me know if you have any other questions. I am out of ideas on how to solve this bug.
UPDATE
Found that the code below was "theming" the slider but when I removed it, it worked fine. What is a way i can keep the theme color and not get it to disappear?
[[UISlider appearance] setThumbTintColor:[UIColor colorWithRed:0/255.0f green:75/255.0f blue:152/255.0f alpha:1.0f]];
[[UISlider appearance] setMinimumTrackTintColor:[UIColor colorWithRed:164/255.0f green:75.0f blue:25/255.0f alpha:1.0f]];
[[UISlider appearance] setMaximumTrackTintColor:[UIColor colorWithRed:204/255.0f green:204/255.0f blue:204/255.0f alpha:1.0f]];
This is the well known bug in SetMaximumTrackTintColor.
Remove this line:
[[UISlider appearance] setMaximumTrackTintColor:[UIColor colorWithRed:204/255.0f green:204/255.0f blue:204/255.0f alpha:1.0f]];
and your app will work fine.
It is correct that this is a known bug. But have found a way to work around it so that you can still keep your theming:
[[UISlider appearance] setMaximumTrackTintColor:[UIColor colorWithRed:204/255.0f green:204/255.0f blue:204/255.0f alpha:1.0f]];
In UIViewController's where I use a slider, I set the maximumTrackTintColor in the viewDidLoad: method
- (void)viewDidLoad
{
[super viewDidLoad];
_slider.maximumTrackTintColor = [UISlider appearance].maximumTrackTintColor;
}
This works for me, so I wanted to share!
you can move the appearance changes into the viewDidLoad: function.
this way the appearance changes will only happened once.
- (void)viewDidLoad
{
// Appearance changes here
}
it works for me
I have a UIPickerView which works correctly, now I want to add a button above it so that I can dismiss it.
and here is my code where I initiate a UIPickerView as well as its dismiss button:
- (UIPickerView *)creatPickerView {
UIPickerView *tempPickerView = [[[UIPickerView alloc]
initWithFrame:CGRectMake(kPickerViewX, kPickerViewY, kPickerViewWidth, kPickerViewHeight)] autorelease];
tempPickerView.showsSelectionIndicator = YES;
tempPickerView.delegate = self;
tempPickerView.dataSource = self;
UIButton *pickerButton = [[UIButton alloc] initWithFrame:CGRectMake(270, -32, 50, 32)];
[pickerButton setBackgroundImage:[UIImage imageNamed:#"hidePicker.png"]
forState:UIControlStateNormal];
[pickerButton addTarget:self action:#selector(hidePicker)
forControlEvents:UIControlEventTouchUpInside];
[tempPickerView addSubview:pickerButton];
[pickerButton release];
[self.view addSubview:tempPickerView];
return tempPickerView;
}
and it works well on my iPhone 4.3 Simulator, like this:
apparently there is a button on the upper right of the pickerView,
problem is, when I run the app in my device - a 5.0.1 iPhone4 and a 4.2.1 iTouch, the button is missed like it has never been added to the pickerView.
Can anyone help me with this?
Thanks a lot and a lot!
I found the reason, it seems the png has some problem,
after I change another png, it comes up in the screen!
but the real problem is that I place the button outside of the pickerView which results in the button's untouchableness.
But anyway the pickure is only a small problem.
Basically what I am trying to figure out to do is, say I have one View Controller, called V1, that has a regular view inside it and a button. Now, when you tap that button, I want that button to create an action that pop-ups another View Controller, called V2, within the same view controller, V1.
V2 will be reduced in size some so that it does not fill the entire screen, but you can still see the first layer which is V1 behind V2. So basically, you never really leave V1. I hope this makes sense for what I'm trying to do. I know the MTV app has this functionity. An image of what I'm talking about is here: https://docs.google.com/leaf?id=0BzlCAVXRsIPcNWUxODM2MDAtNDE3OS00ZTc4LTk5N2MtZDA3NjFlM2IzNmZk&hl=en_US
Sample code or an example is what I'm looking for as well.
Thanks
You can create such view by setting appropriate property type of modalPresentationStyle. See my example below:
UIViewController *V2 = [[UIViewController alloc] init];
V2.modalPresentationStyle = UIModalPresentationFormSheet;
V2.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[V1 presentViewController:V2 animated:YES completion:nil];
V2.view.superview.frame = CGRectMake(0, 0, 540, 620); //it's important to do this after presentModalViewController
V2.view.superview.center = V1.view.center;
[V1 release];
Try this:
V2 *d = [[V2 alloc]initWithNibName:#"V2" bundle:nil];//assuming V2 is name of your nib as well
d.delegate = self; //Optional:you only need this if you want to delegate
//create popover and put V2 in the popover view
UIPopoverController *popoverController = [[UIPopoverController alloc] initWithContentViewController:d];
popoverController.delegate = self; //optional
CGSize size = CGSizeMake(325, 75); // size of view in popover…V2
popoverController.popoverContentSize = size;
[d release];
[popoverController presentPopoverFromRect:yourButton.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
If you want to present this as a modal popup in iOS 8 with a similar style to the OP's screenshot here's what I did:
UIViewController *V2 = [[UIViewController alloc] init]; // V2 is the popup
V2.modalPresentationStyle = UIModalPresentationFormSheet;
V2.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
V2.preferredContentSize = CGSizeMake(325, 75); // size of popup view
[V1 presentModalViewController:V2 animated:YES]; // V1 is the current topmost view controller
I like this better than using a UIPopover because you don't need to mess with arrow directions and the user cannot close it by tapping outside of the popup.
These properties can also be set in a storyboard/nib via the designer. To set preferredContentSize check "Use Preferred Explicit Size" and set the values.
This only works on the iPad.
There is a very good library to display a view controller as Popup on iPhone
see here https://github.com/martinjuhasz/MJPopupViewController
If you're using Storyboard, you can follow this step:
Add a view controller (V2), setup the UI the way you want it
*based on the image you attached
add an UIView - set background to black and opacity to 0.5
add an UIImageView - that will serve as your popup (Pls take note that the image and the view must not have the same level/hierarchy. Dont make the imageview the child of the view otherwise the opacity of the uiview will affect the uiImageView)
Present V2 Modally
Click the segue. In the Attributes inspector, Set Presentation as Over Full Screen. Remove animation if you like
Select V2. In the Attributes inspector, Set Presentation as Over Full Screen. Check Defines Context and Provides Context
Select the MainView of your V2 (Pls. Check image). Set backgroundColor to Clear Color
file .m ---> this is the implementation file
-(IBAction)anyAlert:(id)sender{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"A Message" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK!", #"Other Title", nil];
[alert show];
[alert release];
}
remember declare
-(IBAction)anyAlert:(id)sender;
in the file .h ---> header file
It works for me, hopefully for you...
Create UIView for v2 and add in v1.
- (void)viewDidLoad
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(aMethod:)
forControlEvents:UIControlEventTouchDown];
[button setTitle:#"Show View" forState:UIControlStateNormal];
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[self.view addSubview:button];
}
- (void)aMethod:(id)sender
{
CGRect * imageFrame = CGRectMake(10, 90, 300, 300);
V2 *v2 = [[V2 alloc] initWithFrame:imageFrame];
[self.view addSubview:v2];
}