iOS7: UISearchBar scope buttons misaligned - ios7

Ok, I bumped into another iOS7 weirdness:
I am adding a UISearchdisplayController + UISearchBar with some scope buttons programmatically to a table view.
Now, if I select the search field, the scope buttons are too large. If I switch to landscape, things get even worse, the buttons are badly misaligned.
Here is my code (just a few lines added to the standard 'Master Detail Application"-template):
- (void)viewDidLoad
{
// ...
UISearchBar *searchBar = [[UISearchBar alloc] init];
searchBar.showsScopeBar = YES;
searchBar.scopeButtonTitles = #[#"one", #"two"];
self.tableView.tableHeaderView = searchBar;
self.mySearchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
// ... add delegate, datasource, irrelevant for this example
}
This is what it looks like:
Addition:
By the way, the misalignment also appears if I hook things up with IB instead. The button width is correct though.
Does anyone have an idea for a workaround?

Change the initializer you have used to instantiate the search bar with something like this UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];. Seems to be a problem related with the designated initializer for the search bar.

Related

Which one of the two NSTextViews has been edited? doCommandBySelector is always returns the first one

I'm desperate to find the answer, so I opened TextLayoutDemo sample project from Apple. The point is that: I have two NSTextViews for column view. Everything works fine, text I enter is successfully laying out in those two text views via single layout manager:
NSLayoutManager *twoColumnLayoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *firstColumnTextContainer = [[NSTextContainer alloc] init];
NSTextContainer *secondColumnTextContainer = [[NSTextContainer alloc] init];
NSTextView *firstColumnTextView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, 240, 360) textContainer:firstColumnTextContainer];
firstColumnTextView.delegate = self;
NSTextView *secondColumnTextView = [[NSTextView alloc] initWithFrame:NSMakeRect(240, 0, 240, 360) textContainer:secondColumnTextContainer];
secondColumnTextView.delegate = self;
[firstColumnTextContainer setContainerSize:NSMakeSize(240, 360)];
[secondColumnTextContainer setContainerSize:NSMakeSize(240, 360)];
[twoColumnLayoutManager addTextContainer:firstColumnTextContainer];
[twoColumnLayoutManager addTextContainer:secondColumnTextContainer];
[twoColumnLayoutManager replaceTextStorage:[firstTextView textStorage]];
[[secondWindow contentView] addSubview:firstColumnTextView];
[[secondWindow contentView] addSubview:secondColumnTextView];
But my goal is to get to know in which one text views the user edits a text. If it's the left one, I need to call one method, but if it's the right one, I want to call another method. And it seems impossible to recognize the correct text view, because delegate always get notified by the first text view.
- (BOOL) textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector {
NSLog(#"edit: %#", textView);
return NO;
}
This method is always prints the first text view, even if I change text in the second one. And I see it's going according to docs, where Apple says there always will be just the first NSTextView in series.
But how can I solve my problem then?
Just tell me, if this solution is the one I am looking for. Because, in fact, it works just fine. The one thing I don't understand is why Cocoa text system is so tricky where it is not necessary?
- (void)textStorageDidProcessEditing:(NSNotification *)aNotification {
// that's the active text view
NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow];
NSTextView *activeTextView = (NSTextView *)[keyWindow firstResponder];
NSLog(#"%p", activeTextView);
}
UPDATE: this works only if user clicked the mouse button. Arrow keys do not update window's first responder:(

UIButton inside UIView doesn't respond to touch events

I've put a UIButton inside a custom UIView and the button is not receiving any touch events (it doesn't get into the highlighted state, so my problem is not about being unable to wire up a touch inside up handler). I've tried both putting it into the XIB in Interface Builder, and also tried programatically adding the UIButton into the UIView seperately, both ended with no luck. All my views are inside a UIScrollView, so I first though UIScrollView may be blocking them, so I've also added a button programatically exactly the same way I add my custom view into UIScrollView, and the button worked, elimination the possibility of UIScrollView could be the cause. My View's hiearchy is like this:
The button is over the image view, and the front layer isn't occupying my button completely, so there's no reason for me not be physically interacting with the button. At my custom view's code side, I'm creating my view as such:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
UIView *sub = [[[NSBundle mainBundle] loadNibNamed:#"ProfileView" owner:self options:nil] objectAtIndex:0];
[self addSubview:sub];
[sub setUserInteractionEnabled:YES];
[self setUserInteractionEnabled:YES];
CALayer *layer = sub.layer;
layer.masksToBounds = YES;
layer.borderWidth = 5.0;
layer.borderColor = [UIColor whiteColor].CGColor;
layer.cornerRadius = 30.0;
/*layer.shadowOffset = CGSizeZero;
layer.shadowRadius = 20.0;
layer.shadowColor = [[UIColor blackColor] CGColor];
layer.shadowOpacity = 0.8;
*/
}
return self;
}
I've tried all combinations of setUserInteractionsEnabled, and had no luck. (Yes, also set them to checked in Interface Builder too). I've also read in another question with a similar problem that I should try overriding 'canBecomeFirstResponder' to return 'YES' and I've also done that too. But the problem persists, I can't click the button. I've not given any special properties, settings to the button, it's just a regular one. My other objects in the view (labels below, image view behind the button etc.) are working properly without problems. What could be possibly wrong here?
Thanks,
Can.
UPDATE: Here is a quick reproduction of the problem: https://dl.dropbox.com/u/79632924/Test.zip
Try to run and click the button.
Looking at the test project, I believe your problem in the way you create TestView, you do not specify the frame for it, so basically the parent view is 0 size, and the subviews you see from XIB extending out of the parent view and thus do not get anything in responder chain.
You should either specify the frame when creating TestView, or adjust the frame after loading XIB file.
I have had this problem as well. The cause for me was that the UIButton superview frame was of height 0, so I believe that even though a touch was happening, it was not being passed down to the button.
After making sure that the button's superview took a larger rectangle as a frame the button actions worked.
The root cause for this problem on my side was a faulty auto layout implementation (I forgot to set the height constraint for the button's superview).
I've found the solution. I was initializing my custom view as:
MyView *view = [[MyView alloc] init];
I've initialized it instead with a frame of my view's size, and it started responding to events:
CGRect rect = CGRectMake(0,0,width,height);
MyView *view = [[MyView alloc] initWithFrame:rect];
Storyboard Solution
Just for anyone wanting a solution to this when using storyboards and constraints.
Add a constraint between the superview (containing the button) and the UIButton with an equal heights constraint.
In my case, I had selected embed UIButton in a UIView with no inset on the storyboard. Adding the additional height constraint between the UIButton and the superview allowed the UIButton to respond to touches.
You can confirm the issue by starting the View Debugger and visually confirm that the superview of the UIButton is not selectable.
(Xcode 11, *- Should also work in earlier versions)

How to change the Title View of the navigation bar into some Custom View and fill the original size

I want to change the titleView of navigationBar with a regular text field. Then I want to set the textField size to fill the old "normal" titleView.
I can't seem to be able to do this in storyBoard. Dragging a text Field to the place where the navigation title View is doesn't work.
So I added stuff at
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
PO(self.navigationItem.titleView);
CGRect theFrame= self.navigationItem.titleView.frame;
self.navigationItem.titleView=self.searchBar;
//self.searchBar.frame = theFrame;
while (false);
...
It's working with one cached. That PO is a macro that print the content of the object. Turns out at viewDidAppear, self.navigationItem.titleView is null.
So while I can display the searchBar, I cannot make the searchBar "fill" it's space because I do not know the space is.
I prefer not to hard code it because you know, things may change in the future.
So what should I do?
I once saw codes where rather than setting the self.navigationItem.titleView, you would simply add subview to it. The problem with this approach even on viewDidAppear, self.navigationItem.titleView is 0.
I added these codes:
CGRect theFrame= self.navigationItem.titleView.frame;
CGRect theFrame2 = self.searchBar.frame;
CGRect theFrame3 = self.navigationController.navigationItem.titleView.frame;
And, I do not know how to nslog structure value, however, theFrame and theFrame3 are all 0
You can try this inside viewWillAppear:
UIView *customTitleView = [[UIView alloc]initWithFrame:CGRectMake((320-210)/2, 0, 210, 50)];
customTitleView.backgroundColor = [UIColor clearColor];
//create your UITextField or UILabel or other view and add as subview of customTitleView
self.navigationItem.titleView = customTitleView;

How to display a UIWindow based dimmed background like UIAlertView?

Here's my problem: I tried to display a UIWindow with a subview that displays a radial gradient. I wanted to put the window on the UIWindowLevelAlert. I had this all figured out before and it was working, but now I'm trying to reproduce it wasting hours...
This is the code I've got (the background is not a gradient because I wanted to keep it simple, then add a view that really is like the one of an UIAlertView):
- (IBAction)buttonPressed {
UIWindow *backgroundWindow = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
backgroundWindow.windowLevel = UIWindowLevelAlert;
UIView *backgroundView = [[UIView alloc]initWithFrame:[UIScreen mainScreen].bounds];
backgroundView.backgroundColor = [UIColor blackColor];
backgroundView.alpha = 0.5;
[backgroundWindow makeKeyAndVisible];
[backgroundWindow addSubview:backgroundView];
backgroundWindow.hidden = NO;
}
When a UIWindow is dealloc'd, it will be removed from the screen. Since you don't keep a reference to your UIWindow, I believe it is getting released and dealloc'd, and therefore it won't show.
The solution is to keep a reference to the window somewhere. Can you store it as a property in the class you're working in?

UIPickerView takes up all horizontal space on iPhone, but not on iPad?

I noticed something that has never been a problem before.
I did a project for iPad where I used several UIPickerView positioned next to each other, horizontally. Here they respect the CGRect frame I initialize them with, meaning placing other elements on either side of them was no problem.
Now I am trying to do this on an iPhone project and here a UIPickerView insists on being the only element. It sizes it self to fill the screen horizontally, with the "around" graphics.
I tried different approaches, place the UIPickerView inside a different view then sizing that super view, that just leads to clipping, not resizing. Another thing is that the UIPicker insists on being placed in the center of the screen. This basically means that when a UIPickerView is added to the screen, even though its single component is only 70 px wide, those 320 px of the screen is used up.
What I am trying to accomplish is to have a UIPicker on the right side of the screen and a button to the left of it.
Am I overlooking something obvious here? Hope someone could lend a hand, thanks in advance:)
Nothing more complicated than this:
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 250.0f, 165.0f)];
UIPickerView *picker = [[UIPickerView alloc] initWithFrame:container.frame];
[picker setDelegate:self];
[picker setDataSource:self];
[container addSubview:picker];
the frame I set, is not respected. It takes up all horizontal space.
I tried your code with the same result.
However, you can set the frame after the picker has been created and added to your container, and the new size is respected. Here's my test case, which works for me using SDK 4.2, in the iPhone simulator:
- (void)viewDidLoad {
[super viewDidLoad];
UIPickerView* pv = [[[UIPickerView alloc] initWithFrame: CGRectMake(160, 100, 100, 216) ] autorelease];
pv.delegate = self;
pv.dataSource = self;
[self.view addSubview: pv];
pv.frame = CGRectMake(10, 10, 100, 216);
}