customize uipopovercontroller in ipad - ipad

i want to change the image of popover. it is having blue tint at the top so i want it to be of different color. how can i do it...
- (void)presentPopoverFromRect:(CGRect)rect inView:(UIView *)view permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections animated:(BOOL)animated
can i do it with this method.. make my own view and place a image in that view.
i read in some posts that it is not possible to change color and also i didnt fine any instance method of UIPopOverController class to do this..
thanks in advance.

You cannot customize a popover the way you want. The view you see is the popover's content. Popovers are always the way it is, black.

Maybe I am misunderstanding the question but it seems like it is possible to designate custom UIPopoverView backgrounds:
UIPopoverBackgroundView. Haven't got around to trying this myself.
The UIPopoverBackgroundView class provides the background appearance for a popover. This class is abstract and must be subclassed before it can be used. The implementation of your subclass is responsible for providing the border decoration and arrow for the popover. Subclasses must also override all declared properties and methods to provide information about where to lay out the corresponding popover content and arrow.

Related

UIAppearance tintColor takes priority over Storyboard tintColor

I created a simple view controller using Interface Builder that contains an UIImageView and UIButton. On both of them, I set tintColor to be Magenta.
On the AppDelegate, I set UIView.appearance.tintColor to be Cyan.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIView.appearance.tintColor = UIColor.cyanColor;
return YES;
}
When running the app I get this:
This doesn't make sense to me. I expect the Magenta tintColor specified directly on the imageView and button to override the Cyan tintColor.
Why is this happening?
For reference, I'm using Xcode Version 11.2 (11B52).
It turns the tintColor property is not decorated with UI_APPEARANCE_SELECTOR, so it shouldn't be used in UIAppearance proxies.
Even if it seems to work, setting UIView.appearance.tintColor has side effects. One instance is this issue with storyboards. Another case I've noticed is that, in iOS 13, UITableView section headers would become filled with the set color.
Given it's not a supported scenario, it's hard to tell exactly why attempting to override tintColor for a component on a storyboard doesn't work. Checking again the documentation, I found a note which might explain it though:
iOS applies appearance changes when a view enters a window, it doesn’t change the appearance of a view that’s already in a window. To change the appearance of a view that’s currently in a window, remove the view from the view hierarchy and then put it back.
I assume that the "storyboard" tintColor will be set while loading the storyboard object, and then UIKit will overwrite it with the "UIAppearance" tintColor once the view is inserted in the view hierarchy.
The solution
The correct way to set a global tintColor seems to set it on the main UIWindow. According to the comments in UIView.h, tintColor is inherited by the superview. This allows to use a global tintColor for all views and override it locally where needed. It works as expected when setting the property from a storyboard.
Programmatically set tintColor in your ViewController class .
UIImageView is also inherited from UIView, changing the appearance of UIView (parent of UIImageView) will affect in the entire application. If you want to override the appearance of any particular UI element, create an IBOutlet and change it programatically to only that UI element.

How can I edit a manually added UINavigationBar sub view in interface builder using storyboards?

I've added a UIView as a sub view of a navigation bar and resized it to look like a tool bar.
It will house 3 buttons:
One for changing the style of how clothing items in a collection view
One for filtering results e.g. favourites, recommended etc
One for refining results
I'd prefer to create these buttons and doing all the editing in interface builder. Is this possible?
Here is my current code I use to create the view:
#interface MyCollectionViewController () <UIScrollViewDelegate>
#property (nonatomic, weak) UIView *filterBar;
#end
#implementation MyCollectionViewController
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIView *filterBar = [[UIView alloc] initWithFrame:CGRectMake(0, 42, self.view.frame.size.width, self.navigationController.navigationBar.frame.size.height)];
[[[self navigationController] navigationBar] addSubview:filterBar];
[filterBar setBackgroundColor:[[UIColor whiteColor] colorWithAlphaComponent:0.9f]];
[filterBar setTag:1];
}
My buttons will be like select buttons that trigger UIActionSheet instances or push other controllers onto the top of the stack where I can provide an interface for carrying out an action e.g. refining types of clothes then searching.
Here is a photo of the an app with the bar I'm talking about:
Anyway the is this possible, can I link the view I created in code above up in interface builder and work on it visually rather than in code?
Thanks for your time.
Kind regards
Short answer: you can't really...
Storyboards/IB don't allow much customization of UINavigationBar aside from setting title and left/right barButtonItems. Most of what (it seems like) you want to do has to be done in code using a custom UIView subclass.
Longer answer:
To use the standard UINavigationBar, your menu, search, star & suitcase(?) icons at the top would need to be added as arrays of barButtonItems set to the left & right sides. This can only be done in code (you could use a segmented control but need to customize appearance in code anyway).
See 2nd response here for an example: How to add multiple buttons to a NavigationBar?
For the 2nd "filter" row, looks like it would have to be a separate view created & added separately as you've already done, but ideally an instance of a custom UIView subclass. You can't expand/add that many things to the navigation bar in IB.
Create a new UIView subclass. Then in IB drag out/resize a UIview and set it to be your custom class. You could then drag out items to sort of approximate your design.
The issue is that IB only has stock UIKit items and options for customizing them can be limited.
The collection view toggle could be a segmented control, but you
can only change/remove the default blue-rounded border in code, so
you're not saving any work.
Your middle "filter" dropdown would have to be a UIPickerView
(spinner), or perhaps a UITableView subclass. Either of these you'd
have to code a bunch of separately anyway.
The right-side "refine" button could be just a simple UIButton w/a
label. You'd have to change the default color & add a border in code or w/a custom image anyway (since iOS7 removed button borders).
You really might as well code it. IB isn't going to save much time or energy for this many custom elements...
In Interface Builder, you can drag a UIView to a UINavigationItem in a UINavigationBar:
This view you just dragged is accessible as:
self.navigationItem.titleView
You can also link the buttons or whatever you put in that view to your .m file

MVC with view built in code

I've been trying to interpret the lessons from CS193P, and have a few questions.
I'm building views in code, the way I do it is I have a UIView subclass where I put all the views in place in the init method. This class is initialized by the ViewController.
The question is then, what is the right approach from here - say i want to animate a button I placed at 0,0 to 100,100. I'd like to animate it from the ViewController, but i don't like the fact that i set the 0,0 position in the UIView class (in the initializer) and now i am setting a new position in the ViewController. I'd prefer there would be just one place knowing about the actual (x,y) positions of my views.
How am i supposed to go about this?
Move the positions in the initializer to the ViewController
Put a method in my UIView "-(void)AnimateToSecondPosition" where the actual "second position" is then up to the view?
Just let it go. It seems like this would be the right approach if i had placed the button in interface builder - i consider interface builder to be the view then...
Or maybe even a fourth option?
Please help me understand it better and not just give me the right answer ;)
I'd like to be able to compare my approach in some way to how you would do it using interface builder, so each of my views are public and accessable from the controller - this way i believe i could easily start using interface builder instead if i wanted, without changing the controller code, just hooking up the outlets.
I'm guessing the case would be the same for disabling, hiding and doing other things with the views.
Thanks in advance.
If you want to create a new View programmatically you should generally instantiate it in your View Controller using its designated initialiser:
UIView *testView = [[UIView alloc]initWithFrame:myFrame];
If you create a custom view it's totally fine and correct to put some configuration code in the init method, but it's your ViewController that should be in charge of deciding what to do with this view - it is his job! Using the MVC the View and the Model should never communicate directly (as you definitely learned in the first lesson of CS193P).
Therefore the same apply to the animations. You should animate the Views within your ViewController and not implement the animation in the View itself.
Therefore in my opinion you "second position" should be setup by the VC - if this has to be done when something happens to the view (e.g. someone pressing a UIButton) you should set a target/action to your VC and handle this within your VC.
ADDED:
Regarding building UIViews in the Interface Builder I don't know what you mean by "and let them go". Interface builder will create the views and add them to the specific superviews at runtime - as you can see in the example below you control the view hierarchy graphically on the left. For instance in this case there is a UIView (which I coloured green for clarity) and two buttons. One is a subview of the main view while the other is a subview of the green UIView.
Once your ViewController is loaded the view hierarchy is automatically loaded to self.view - in fact if you run the following code in your VC when it is loaded you will see the list of self.views subviews in your console.
for (UIView *view in self.view.subviews){
NSLog("%#", [view description]);
}
If you know already that you need to change some attributes of a specific UIView you setup via Interface Builder (e.g. we know we want to change programmatically the color of the green UIView in the example above) you should create an outlet which allows you to have a reference to that view in your code. You do it by crtl-drag from the storyboard to your ViewController code - see the example below.
When you have done that you can refer in code to this as any other property, with the difference that it has been created by Interface Builder.
Hope this helps.
You can add an -setButtonFrameToSecondPosition to the view subclass, which simply updates the frame of the button, and then call that from the view controller via one of the +[UIView animate:...] methods.

Top level view in a UIView hierarchy

I have a singleton instance of a custom UIView with a method -(void)display whose job is to animate the custom view in and out on whatever screen is currently being displayed. (kind of like the -show method in UIAlertView).
My question is how do I determine which view is at the top of the UIView hierarchy and currently displayed?
The "top" of the view hierarchy is a UIWindow. And there can be (and usually is) more than one UIWindow in the application. If you want to have something shown over everything else on the screen, I suggest you implement a custom UIWindow. E.g. UIAlertView is also implemented this way.

iPad UIPopOverController - is it possible to have transparent background?

Does anyone know if it possible to have a transparent background for a UIPopOverController on the iPad?
I'd like to put a semi-transparent view inside the popover (hence the desire for the popover itself to have a transparent background).
I think it can't be done ... but I'd love to know if I am wrong!
I think that setting the transparency of the view in the popover won't work, but I've never tried it and it might.
Anyways, another cool way would be to take a UIImage rendering of the main UIView inside the popover controller.
Once you have this image, you can follow this process, assuming that you also know where the popover is positioned (its CGRect) relative to the view controller that opened it.
Hide popover.
Show rendered UIImage in a transparent UIImageView at the same position. (You can add a little border yourself so that it looks like the popover too.)
Reshow the popover.
The effect would be that the UIPopoverController "faded".
I know its a hard way to do it if the first solution also works, but this might be cool project to take on.
Why not add a View whose alpha is setted to 0.5 before showing popover view
then use
presentPopoverFromRect:(CGRect)rect inView:(UIView *)view permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections animated:(BOOL)animated;
method of popover passing the created view's reference.
It is possible to have UIPopOverController to have semi-transparent background. Check the following example.
[[[myPopOverController contentViewController] view] setAlpha:0.25f];
Usually popover control wil be transparent,we cant change the popover control to semi-transparent view

Resources