iOS - how to make subviews of a Navigation Bar transparent? - ios

I've been experiencing some troubles with animating the alpha of certaing subviews of my Navigation Bar. Here is the initial state of the bar:
Here is how far did I get by now:
The thing is that I need to make all this "star", "new" and other round buttons transparent when the search is active (I need to reduce their alpha to zero). I am trying to make them transparent in the following methods of the delegate:
- (void)searchBarCancelButtonClicked:(UISearchBar *)asearchBar
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
In all of them I do quite the same code:
//parent is just a pointer of a search delegate, which points to view controller
for (UIView * someViewToFade in parent.navigationController.navigationBar.subviews) {
if (someViewToFade.tag == 88 || someViewToFade.tag == 11) {
NSLog("someViewToFade.alpha before changes = %f", someViewToFade.alpha);
someViewToFade.alpha = 0.0; //or 1.0, depending on the method
}
}
However, I couldn't achieve the desired result this way, though I am getting right alpha values at that NSLog, buttons don't fade at all. Are there any suggestions on what can I possibly be doing wrong?
EDIT 1:
I think I should add some description of the view hierarchy in my case. Well, I have the UISegmentedConrol, which holds these round buttons and also two UIImageViews, the background for segmented control, and the triangle pointer. All of these views are added to the navigation bar as it's subviews. Also there is a rectangular view, which holds the searchbar, and is also added as a subview to the navigation bar later, so it's the top view in the hierarchy. Also, I am animating my searchBar by simply animating the frame of its superview (expanding or condensing it, when the events above occur in the delegate). I hope I've given all the necessary information.

Its been a while since I did ios programming. It is possible that even though you are setting the alpha, but not triggering a repaint. [UIView setNeedsDisplay] might help to refresh the drawing in the next drawing cycle.
For a reference: What is the most robust way to force a UIView to redraw?

1) This is UI update problem,write this statement after any UI update code.
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate date]];
this will update your GUI.
or
2) use perform selector on main thread and update your UI in selector method.
[self performSelectorOnMainThread:#selector(UpdateUIMethod) withObject:self waitUntilDone:NO];

Related

Picker View Background Color during Rotation

I am having an issue with my picker view rotating. I am using a normal UIPickerView and autorotation, all of which is done in code (but the autorotation isn't what I'm concerned about). The picker view does exactly what I want it to do after rotation. The issue is that my background is black, and during rotation the background of the picker view turns white in places. I am pretty sure that these are the deep subviews of the picker view simply because of debugging using Xcode's visual debugger and taking mid-rotation screen shots.
My question is, how do I get the background of the picker view to not appear momentarily white?
I have tried something along these lines:
-(void)setBackgroundBlackForSubviews:(NSArray *)subviews
{
if (subviews.count) {
for (UIView *view in subviews) {
[view setBackgroundColor:[UIColor blackColor]];
[self setBackgroundBlackForSubviews:view.subviews];
}
}
}
and pass in pickerView.subviews as the initial parameter, but this doesn't produce the desired result.
So, what solution should I try to get the background to appear black throughout the entire rotation process?

iOS UITextField Outside of SuperView not Responding to Touches

I'm building an iOS 8 app that makes use of the new hidesBarsOnSwipe property on UINavgitationController to hide the nav bar while scrolling. At the same time that the nav bar hides, I'm also programmatically hiding the tab bar. On top of the tab bar, there is a text field which lets users comment on a post (much like Facebook). When the tab bar is hidden (by moving it downward and off the screen), the text field is moved down as well, so that it now sits at the bottom of the screen and so that there's no gap between the bottom of the screen and the text field.
So, things look great. But, turns out that the text field doesn't respond to touch events when it moves to the bottom of the screen. I did some digging and it appears that the reason is because the text field is outside of its superview (the view controller's view), and so touch events will not be sent to the text field.
So I think I've figured out why the issue is occurring, but I haven't yet figured out how to fix it. I've tried messing with hitTest:withEvent: and pointInside:withEvent: but didn't have any luck. Anyone have any solutions?
EDIT: Here is some code to make the question clearer (hopefully). When the nav controller's barHideOnSwipeGestureRecognizer is called, I am running the following code:
- (void)barHideSwipeGestureActivated:(UIPanGestureRecognizer*)gesture
{
[self animateTabBarUpOrDown:self.navigationController.navigationBar.frame.origin.y >= 0 completion:nil];
}
The method above is the following:
- (void)animateTabBarUpOrDown:(BOOL)up completion:(void (^)(void))completionBlock
{
if(!self.animatingTabBar && self.tabbarIsUp != up)
{
self.animatingTabBar = YES;
//to animate the tabbar up, reset the comments bottom constraint to 0 and set the tab bar frame to it's original place
//to animate the tabbar down, move its frame down by its height. set comments bottom constraint to the negative value of that height.
[UIView animateWithDuration:kTabBarAnimationDuration animations:^{
UITabBar *tabBar = self.tabBarController.tabBar;
if(up)
{
tabBar.frame = CGRectMake(tabBar.frame.origin.x, tabBar.frame.origin.y - tabBar.frame.size.height, tabBar.frame.size.width, tabBar.frame.size.height);
self.addCommentViewToBottomConstraint.constant = 0.0f;
}
else
{
tabBar.frame = CGRectMake(tabBar.frame.origin.x, tabBar.frame.origin.y + tabBar.frame.size.height, tabBar.frame.size.width, tabBar.frame.size.height);
self.addCommentViewToBottomConstraint.constant = -tabBar.frame.size.height;
}
} completion:^(BOOL finished) {
self.tabbarIsUp = up;
self.animatingTabBar = NO;
if(completionBlock)
{
completionBlock();
}
}];
}
}
Ok, finally found a solution for this one. I haphazardly messed around with changing the bounds of my view controller's view, but that was too hacky and ultimately didn't accomplish what I wanted it to.
What I ended up doing was changing my view controller's edgesForExtendedLayout property to be equal to UIRectEdgeAll which basically says that the view should take up the entire screen, and extend above top bars / below bottom bars.
I had to hack around a little bit with changing auto layout constraints on my text field so that it appeared in the right place at the right time, but overall, the solution was changing edgesForExtendedLayout to be UIRectEdgeAll - this makes the view take up the entire screen, so the text field is now still in the super view even when it animates downward, thus, allowing it to still receive touch events.

fade in/fade out UISegmentedControl in XIB

I have a UISegmentedControl set up in my XIB. I want it to appear on viewDidLoad and if the user taps the area of the screen it's in, and then to disappear if the user taps it again or to fade out if the user leaves it alone.
In looking around for how to manage this I've found a lot of stuff about fading UIViews, but not as much on fading individual subviews, and little at all on fading elements in the XIB. I tried to adapt the UIView stuff but failed.
How can I make this work?
EDIT: Okay, I've got the appearance at viewDidLoad and the fade out working. But when the user taps the area where the UISegmentedControl is (now invisible because alpha=0), nothing happens. This is the code I'm using:
- (IBAction)tapInvisibleSegContr
//This is connected to the UISegmentedControl with the action Touch Up Inside. Until now, the segmented control has been at alpha=0 since fading after viewDidLoad.
{
self.segContrAsOutlet.alpha=1.0;
[self fadeMethodThatWorksInViewDidLoad];
NSLog(#"Yup, tapped.");
}
I'm not even getting the NSLog. I've got the action hooked up to the UISegmentedControl, with the action Touch Up Inside. What am I missing?
If it is resident in a xib, just put his alpha to 0, do the properly connections: an Outlet and an IBAction for value changed
Then in the viwDidLoad right after [super viewDidLoad] write:
[UIView animateWithDuration:1 animations:^{self.mySegOutlet.alpha = 1;}];
Inside the IBAction right after you code the answer before the last } write:
[UIView animateWithDuration:1 animations:^{self.mySegOutlet.alpha = 0;}];
This is the easiest method.
Bye
In the xib set your control's alpha to 0.0, then use UIView animation methods to animate its alpha to 1.0. For example:
[UIView animateWithDuration:1.0 animations:^{
self.segmentedControl.alpha = 1.0f;
}];
EDIT: To your problem with not getting the action called, try attaching it for the value changed control event - I don't think UISegmentedControl sends for touch up inside.

UISearchDisplayController change dimmed view frame

In my iPad app I have an UITableView. Table's frame size is less than screen size, so to make search functionality look nice I have to adjust searchResultTableView's frame to fit my TableView. I'm doing it in my UISearchDisplayDelegate's -searchDisplayController:willShowSearchResultsTableView: method.
Everything works fine except dimming view. When I'm starting search dimming view's width is equal to screen width:
When I start entering search string or clear textfield my searchResultsTableView resizes properly and everything works as it should:
I tried to change searchResultsTableView frame inside -searchDisplayControllerWillBeginSearch: method using this line
controller.searchResultsTableView.frame = myFrame;
but it doesn't work as well. Any suggestions besides implementing my own search display controller?
I also needed to change the frame of the dimming view but for a different reason. In my case I created a UISearchDisplayController and UISearchBar programmatically in a regular UIViewController not a UITableViewController. I was also using MFSideMenu which added to the complexity of the problem. What ended up happening was the dimming view was in the correct position initially but the next time the search was cleared the dimming view shifted leftwards and upwards by exactly half of it's size. Given the UISearchDisplayController you can find the dimming view like so.
for(UIView * v in controller.searchContentsController.view.subviews)
{
if([v isMemberOfClass:[UIControl class]])
{
v.frame = newFrame; //This frame should account for the UISearchBar
}
}
To handle for the initial incorrect frame you should change it in this delegate method:
- (void) searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView;
To handle for an incorrect frame on any subsequent clears you should change it in this delegate method:
- (void) searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView;
Note: this solution runs through the subviews of the searchContentsController which is one of the reasons I used isMemberOfClass instead of isKindOfClass (UIButton is a subclass of UIControl). Further discrimination would be required if you added a UIControl instance into your view (you could use tags to help determine which ones are yours).

dismissModalViewControllerAnimated resets contentOffset

I have a problem with my table view. When dismissing a modal view controller presented on top of it, it always scrolling to the top . I have tried observing the changes to contentOffset using KVO, but the one that messes my view goes behind it.
From the UITableViewController, when user finishes his task in the modal dialog, self.tableView.contentOffset is , I call:
[self dismissModalViewControllerAnimated:YES]
Subsequently, when the viewWillAppear:(BOOL)animated is called, the self.tableView.contentOffset is already set to 0,0.
Is this supposed to be happening? I am able to work around the issue by remembering the scroll position before presenting the modal view and restore it back in viewWillAppear after dismissing the modal view. But it seems wrong. Am I missing something?
I have found similar problem described in Dismiss modal view changes underlying UIScrollView.
It looks like this is default behavior of UITableViewController. I tested it in very simple app and It worked exactly as you said. If you don't like it, use UIViewController instead.
Here is how I work around this problem, so that the table view maintains the original scroll position. In my subclass of UITableViewController I have added:
#property (assign) CGPoint lastScrollPosition;
Then in the implementation, I have overridden the following:
- (void)viewWillAppear:(BOOL)animated
{
self.tableView.contentOffset = self.lastScrollPosition;
}
- (void)dismissModalViewControllerAnimated:(BOOL)animated
{
self.lastScrollPosition = self.tableView.contentOffset;
[super dismissModalViewControllerAnimated:animated];
}
If you want your table to initially appear scrolled to non-zero position, as I did, don't forget to initialize the lastScrollPosition in your viewDidLoad.

Resources