iOS 7 - UIWebView extended menu - ios

I want to add additional menu item for the menu that appears when some text is selected.
I have added the code below to viewDidLoad:
NSMutableArray *extraItems = [[NSMutableArray alloc] init];
UIMenuItem *boldItem = [[UIMenuItem alloc] initWithTitle:#"Bold"
action:#selector(bold:)];
[extraItems addObject:boldItem];
[UIMenuController sharedMenuController].menuItems = extraItems;
I also have overwritten my custom UIWebView with these methods:
- (void)bold:(id)sender {
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (action == #selector(bold:))
return YES;
return [super canPerformAction:action
withSender:sender];
}
So sometimes when I highlight the text the menu appeasers, but sometimes it does not. I don't know what the problem is.

Your array "extraItems" should be an NSArray, not an NSMutableArray, so your first three lines that you added to viewDidLoad should be replaced by:
UIMenuItem* extraItem = [[UIMenuItem alloc] initWithTitle:#"Bold"
action:#selector(bold:)];
NSArray* extraItems = [NSArray arrayWithObject:extraItem];
Then add this version of extraItems array to the sharedMenuController just as you did.

Related

Extend drop-down from a UITableCell to go over the cell height

In my table cells, there is a button that displays a drop-down menu when you click on it. The problem is, the drop-down menu exceeds the height of the cell and bleeds into the cell below.
In that case, if I click the item in the drop-down, it actually acts as I clicked the cell below.
I tried using the code below but it doesn't seem to work.
[super bringSubviewToFront:dropDown];
[super willMoveToSuperview:dropDown];
The function that shows the drop-down is defined in the custom class for the table cell:
- (IBAction)eventAction:(id)sender {
NSArray * arr = [[NSArray alloc] init];
arr = [NSArray arrayWithObjects:#"Hello 0", #"Hello 1",nil];
NSArray * arrImage = [[NSArray alloc] init];
arrImage = [NSArray arrayWithObjects:[UIImage imageNamed:#"apple.png"], [UIImage imageNamed:#"apple2.png"], nil];
if(dropDown == nil) {
CGFloat f = 100;
dropDown = [[NIDropDown alloc]showDropDown:sender :&f :arr :arrImage :#"down"];
dropDown.delegate = self;
dropDown.layer.zPosition = 1;
[super bringSubviewToFront:dropDown];
[super willMoveToSuperview:dropDown];
}else {
[dropDown hideDropDown:sender];
[self rel];
}
}
Any help is greatly appreciated!!
Thank you!!
Rather than being a case of views being on top of each other, I think it might be that the touch is being interpreted by the table cell below as well.
Try disabling user interaction in the table view when the eventAction is fired.
tableView.userInteractionEnabled = NO;
And then turn it back on when the drop down view is dismissed.

Passing Data from Slide menu to UITableViewController through UINavigationViewController

How can I pass data from UINavigationController to The root UITableViewController?
I have implemented the ECSlidingViewController (https://github.com/edgecase/ECSlidingViewController). User selects one of the cells in the menu that correspond to different urls I want to display information from on my tableView that sitts on top of the UINavigationController. (u know the default combination that u get my dragging UINavigationController to ur storyboard). I am able to get the data from the sliding menu to my navigationController now I am trying to pass that same info on my tableview?
In my menu I have:
UINavigationController *newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"NavigationTop"];
newTopViewController = [(NavigationTopViewController*)newTopViewController initWithCinema:self.myCinema];
In UINaviationController:
- (id)initWithCinema:(Cinema *)cinema {
self = [super init];
if(self) {
_myCinema = [[Cinema alloc] init];
_myCinema = cinema;
}
return self;
}
- (void) viewDidLoad {
[super viewDidLoad];
// this log works I get the info to here.
NSLog(#"url(navigation):%#", self.myCinema.cinemaURL);
//MoviesTableViewController *moviesTableViewController = [[MoviesTableViewController alloc] initWithCinema:self.myCinema];
//UITableViewController *newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"MoviesTable"];
//NavigationTopViewController *newTopViewController = [[NavigationTopViewController alloc] initWithCinema:self.myCinema];
//newTopViewController = [(MoviesTableViewController *)newTopViewController initWithCinema:self.myCinema];
//[self performSegueWithIdentifier:nil sender:self.myCinema];
[self prepareForSegue:nil sender:self.myCinema.cinemaURL];
}
In my UITableView:
- (void)setCinema:(Cinema *)cinema {
// works here too
NSLog(#"Table(setCinema):%#", cinema.cinemaURL);
self.myCinema = [[Cinema alloc] init];
if(!cinema) {
cinema.cityIndex = kAstanaIndex;
cinema.name = kKeruen;
cinema.nameForText = kKeruenText;
cinema.cinemaURL = kKeruenURL;
cinema.cinemaURLTomorrow = kKeruenURLtomorrow;
}
self.myCinema = cinema;
// works here too!!!
NSLog(#"Table(myCinema):%#", self.myCinema.cinemaURL);
}
However its gone in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
// set delegate to self
self.tableView.delegate = self;
// set loading theater's url
// does not work here: I GET NULL !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
NSLog(#"url(moviesTable):%#", self.myCinema.cinemaURL);
_model = [[MovieModel alloc] initWithURL:self.myCinema.cinemaURL];
}
None of the methods I have tried (commented in Navigation worked...) at least for me. Please give me any suggestions. Thank you in advance.
UINavigationController does not hold any data, but rather a stack of view controllers. I'd recommend you check out frameworks such as the free Sensible TableView. The framework will automatically handle detail view generation and passing data between them. Saves me tons of development time in my projects.

Passing arguments with a selector to new .xib of a custom object

I have a tableview that will load a new .xib when pressed. The issue is, I need to pass a custom object over to the new .xib. So far, I have:
-(UITableViewCell *)doTestCellForTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath {
//some other code for current view
TestObj *testobj = [[TestObj alloc]init];
if(shouldGo){
cell.userInteractionEnabled = YES;
UITapGestureRecognizer *tapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(loadTestView:)];
tapped.numberOfTapsRequired = 1;
[cell addGestureRecognizer:tapped];
}
And in that method:
-(void)loadTestView:(TestObj *)withTestObj{
TestViewController *newView =
[[TestViewController alloc] init];
//Set the property of type TestObj
newView.testobjprop = withTestObj;
[self presentViewController:newView animated:YES completion:nil];
}
It throws NSInvalidArgumentException. How can I make it to where the selector will send "testobj" that was initialized in the tableview method so I can access it there?
The new .xib loads in just fine if I comment out "newView.testobjprop = withTestObj;" in the loadTestView method. So I assume the issue lies there, and it is a matter of how to pass an object from one .xib to another.
The argument from -(void)loadTestView:(TestObj *)withTestObj is UIGestureRecognizer type so that's why you get NSInvalidArgumentException.
If you change it to -(void)loadTestView:(UITapGestureRecognizer *)withTestObj it will be the normal behavior.
That's why you need to use didSelectRow:AtIndexPath so you can pass the correct value to the viewcontroller.
Here you aren't using TestObj *testobj = [[TestObj alloc]init]; at all.

UITextView textViewDidChangeSelection called twice

What I have :
TextView
NSArray (string)
AVAudioplayer (not yet implemented)
When I select a word in TextView :
• Check if word exist in Array
• Start Audioplayer with associated sound
Unfortunately when I tap twice to select a word inside TextView, textViewDidChangeSelection is called twice. I don’t know why I see "Youpie" twice.
I just changed inputView to hide keyboard because I only need TextView to be used in selecting mode.
- (void)textViewDidChangeSelection:(UITextView *)tve;
{
NSString *selectedText = [tve textInRange:tve.selectedTextRange];
if(selectedText.length > 0)
{
for (NSString *text in textArray)
{
if ([selectedText isEqualToString:text])
NSLog(#"Youpie");
tve.selectedTextRange = nil;
if (ps1.playing == YES)
{
[self stopEveryPlayer];
[self updateViewForPlayerState:ps1];
}
else if ([ps1 play])
{
[self updateViewForPlayerState:ps1];
fileName.text = [NSString stringWithFormat: #"%# (%d ch.)", [[ps1.url relativePath] lastPathComponent], ps1.numberOfChannels, nil];
}
else
NSLog(#"Could not play %#\n", ps1.url);
break;
}
}
}
}
- (void)awakeFromNib
{
textArray = [[NSArray alloc] initWithObjects:#"dog",#"cat",#"person",#"bird",#"mouse", nil];
textView.inputView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
textView.delegate = self;
// ...
}
I noticed something when I was double tapping on each good word in my text.
textViewDidChangeSelection
If a word is already selected and no action choosen, I have 1 "Youpie".
If not, I have 2 "Youpie".
I found a simple solution. I removed selectedRange after getting value. textViewDidChangeSelection called once.
What I have changed
tve.selectedTextRange = nil;
I use a subclass of UITextView to disable menu.
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
return NO;
return [super canPerformAction:action withSender:sender];
}
I added an implementation for AVAudioPlayer (ps1) too.
My "autoplay" is working if a known word is selecting :)
I don't have an answer for why the method gets called twice or how to prevent this, but an alternative solution might be to display an additional item in the edit menu that pops up in a text view when a word is double clicked. Then, your action for initiating a sound based on the word could be triggered from the action selector defined in that additional menu item. In this design, you'd remove your textViewDidChangeSelection and thus would not get called twice. See http://developer.apple.com/library/ios/#documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/AddingCustomEditMenuItems/AddingCustomEditMenuItems.html for some additional info about modifying the standard menu.

iOS 5: Strange behavior when jumping in between TextFields

In my app I have a pretty large form to be filled out. The form itself is made with a table view and static cells mode. Each of the cells containing a label and a textfield. I wanted to add a toolbar above the keyboard to enable navigating between the text fields. I did that, however it is behaving very strange (at least I think).
I have no problems jumping to the next text field while jumping to the previous textfield is only possible if it is visible. If it is not visible the old textfield stays first responder, however the moment I scroll my table view and the intended text field becomes visible, it becomes the first responder (I do not click into it!). Well this is of course not the behavior that I wanted.
My question is: Is this kind of behavior normal? Could you somehow circumvent it?
If you want to see this kind of behavior yourself I have uploaded an Xcode project that illustrates the problem. You can download the zipped project here: download. The main parts of the code are explained below.
I set up a grouped table view with static cell. Each of them containing a label and a textfield. I created outlets for every textfield to gain access to them. In my viewDidLoad method I create the toolbar and its buttons, store the textfields in an array and set the controller to be the textfields delegate.
- (void)viewDidLoad
{
[super viewDidLoad];
// create the keyboard toolbar with navigation elements
self.keyboardToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];
UIBarButtonItem *prevButton = [[UIBarButtonItem alloc] initWithTitle:#"Previous" style:UIBarButtonItemStyleBordered target:self action:#selector(prevClicked:)];
UIBarButtonItem *nextButton = [[UIBarButtonItem alloc] initWithTitle:#"Next" style:UIBarButtonItemStyleBordered target:self action:#selector(nextClicked:)];
[self.keyboardToolbar setItems:[NSArray arrayWithObjects:prevButton, nextButton, nil]];
// create the field chain
self.fields = [NSArray arrayWithObjects:self.aField, self.bField, self.cField, self.dField, self.eField, self.fField, nil];
// for scrolling and keeping track of currently active field
NSInteger max = [self.fields count];
for(NSInteger i = 0; i < max; i++) {
UITextField *curr = (UITextField *)[self.fields objectAtIndex:i];
curr.delegate = self;
}
}
The text field delegate methods store a reference of the active text field and prevent line breaks from being inserted.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
textField.inputAccessoryView = self.keyboardToolbar;
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
// set the current active textfield
self.currentField = textField;
// scroll this textfield to top
UITableViewCell *cell = (UITableViewCell *)textField.superview.superview;
[self.tableView scrollToRowAtIndexPath:[self.tableView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
self.currentField = nil;
return NO;
}
And finally there are the selectors for the toolbar buttons and the logic to get the next textfield.
- (void)moveResponderByStep:(NSInteger)step
{
// only move if a textfield is the current responder
if(![self.currentField isEditing]) {
return;
}
// where we are and where to move
NSInteger max = [self.fields count];
NSInteger moveToNumber;
for(NSInteger i = 0; i < max; i++) {
if(self.currentField == [self.fields objectAtIndex:i]) {
moveToNumber = i + step;
}
}
// stay in bounds
if(moveToNumber >= max || moveToNumber < 0) {
[self.currentField resignFirstResponder];
return;
}
// move on
UITextField *next = [self.fields objectAtIndex:moveToNumber];
[next becomeFirstResponder];
}
- (void)prevClicked:(id)sender
{
[self moveResponderByStep:-1];
}
- (void)nextClicked:(id)sender
{
[self moveResponderByStep:1];
}
Thank you!
Try checking first to see if the row is visible. Scroll the row to visible if it isn't. Then set the text field as first responder.

Resources