Focus Ring in field editor for NSTextFieldCell in an NSTableView - nstableview

I have a cell-based NSTableView with a text cell in a particular column. I want to provide a custom field editor so that I can do auto completion without the user pressing F5.
#implementation AutoCompleteFieldEditorTextView
-(id)init
{
self = [super init];
if (self)
{
self.focusRingType = NSFocusRingTypeDefault;
self.fieldEditor = YES;
}
return self;
}
#end
This works ok except the focus ring does not exist. Even if I add:
-(void)drawFocusRingMask
{
NSRectFill([self bounds]);
}
-(NSRect)focusRingMaskBounds
{
return [self bounds];
}
it still does not work. How can I get the exact focus ring that appears with the default NSTextView used as a field editor in an NSTableView?

Have same problem and for solving I'm using next approach. This method overloaded in custom NSTextFieldCell which creates and return your custom NSTextView:
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
[super drawInteriorWithFrame:cellFrame inView:controlView];
if([controlView.window firstResponder] == self.maskTextField)
{
[super drawFocusRingMaskWithFrame:cellFrame
inView:controlView];
}
}
Hope this help someone in future.

Related

how to create a camera overlay view that recognized swipe gestures?

I am trying to create a camera overlay that can recognize swipe gestures to push to other views.
I am wondering if I can still use the UIImagePicker or if I have to use the AVCaptureSessionManager.
Also i would prefer to create the overlay view in the story board is there a way to do that?
can I select a view inside the storyboard controller be the camera overlay and simply present the UIImagePicker on view did load?
I've never used the Storyboard to create a camera overlay, but I have created a xib which works fine. You can create the overlay viewController in the normal (xib) way, complete with gesture recognizers, then you can handle them directly in that VC or use a delegate (most likely the VC which presented the camera).
Some code -
-(void)setupCamera
{
self.picker = [[UIImagePickerController alloc] init];
_picker.sourceType = UIImagePickerControllerSourceTypeCamera;
_picker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
self.overlay = [[OverlayViewController alloc] init];
_overlay.delegate = self;
_picker.cameraOverlayView = _overlay.view;
_picker.delegate = self;
[self presentViewController:self.picker animated:YES completion:nil];
}
The overlay -
-(id)init
{
self = [super initWithNibName:#"OverlayViewController" bundle:nil];
if (self)
{
// set up stuff
}
return self;
}
... & some code which handles the swipe -
-(IBAction)swipe:(UISwipeGestureRecognizer *)sender
{
// swipe stuff
[self.delegate doSwipeStuff]; // if you want the delegate to handle it
}
Hope this helps.

Where does this backBarButtonItem come from again?

I have a UINavigationController (A) which has a few subviews which also are UIViewControllers (B and C). The main UINavigationController (A) rides inside of a UITabViewController (D).
I'm trying to push a view controller within B:
[self.navigationController pushViewController... etc]
Now, the backBarButtonItem comes through with the wrong text. Instead of saying 'Back', it just says 'Item'. This is likely because one of the view controllers in my chain has its title set to 'Item' or maybe it is nil altogether.
My question is, where is the backBarButtonItem generated from?
I tried a few different things that didn't work. I tried each of these lines of code within B right before I pushed the view controller. None of them worked.
self.presentingViewController.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Back"... etc
self.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Back"... etc
self.navigationController.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Back"... etc
I'd like to learn the principle here so that I truly understand where this item is being populated from and what the right way to do it is.
Let's say your C controller is on top of the navigation controller's stack, and your B controller is under that. E.g.
navigationController.viewControllers = #[ bViewController, cViewController ];
So the navigation controller is displaying cViewController.view.
The navigation controller uses the second-to-top controller on its stack to configure the back button. In this case, it uses bViewController to configure the back button. This is its algorithm:
UINavigationItem *navigationItem = bViewController.navigationItem;
UIBarButtonItem *barItem = navigationItem.backBarButtonItem;
if (barItem.image != nil) {
show a back button containing barItem.image;
}
else if (barItem.title != nil) {
if (barItem.title.length > 0) {
show a back button containing barItem.title;
} else {
don't show a back button;
}
}
else if (navigationItem.title != nil) {
if (navigationItem.title.length > 0) {
show a back button containing navigationItem.title;
} else {
don't show a back button;
}
}
else {
show a back button containing #"Back";
}

UINavigationController and UINavigationBarDelegate.ShouldPopItem() with MonoTouch

How do I pop up an UIAlertView when the back button of a UINavigationBar (controlled by a UINavigationController) was tapped? Under certain conditions, I want to ask the user an "Are you sure?" type of question so he could either abort the action and stay on the current view or pop the navigation stack and go to the parent view.
The most appealing approach I found was to override ShouldPopItem() on UINavigationBar's Delegate.
Now, there is a quite similar question here: iphone navigationController : wait for uialertview response before to quit the current view
There are also a few other questions of similar nature, for example here:
Checking if a UIViewController is about to get Popped from a navigation stack?
and How to tell when back button is pressed in a UINavigationControllerStack
All of these state "subclass UINavigationController" as possible answers.
Then there is this one that reads like subclassing UINavigationController is generally not a good idea:
Monotouch: UINavigationController, override initWithRootViewController
The apple docs also say that UINavigationController is not intended to be subclassed.
A few others state that overriding ShouldPopItem() is not even possible when using a UINavigationController as that does not allow to assign a custom/subclassed UINavigationBarDelegate to the UINavigationBar.
None of my attempts of subclassing worked, my custom Delegate was not accepted.
I also read somewhere that it might be possible to implement ShouldPopItem() within my custom UINavigationController since it assigns itself as Delegate of its UINavigationBar.
Not much of a surprise, this didn't work. How would a subclass of UINavigationController know of the Methods belonging to UINavigationBarDelegate. It was rejected: "no suitable method found to override". Removing the "override" keyword compiled, but the method is ignored completely (as expected). I think, with Obj-C one could implement several Protocols (similar to Interfaces in C# AFAIK) to achieve that. Unfortunately, UINavigationBarDelegate is not an Interface but a Class in MonoTouch, so that seems impossible.
I'm pretty much lost here. How to override ShouldPopItem() on UINavigationBar's Delegate when it is controlled by a UINavigationController? Or is there any other way to pop up an UIAlertView and wait for it's result before possibly popping the navigation stack?
This post is a bit old, but in case you're still interested in a solution (still involves subclassing though):
This implements a "Are you sure you want to Quit?" alert when the back button is pressed, modified from the code here: http://www.hanspinckaers.com/custom-action-on-back-button-uinavigationcontroller/
Turns out if you implement the UINavigationBarDelegate in the CustomNavigationController, you can make use of the shouldPopItem method:
CustomNavigationController.h :
#import <Foundation/Foundation.h>
#interface CustomNavigationController : UINavigationController <UIAlertViewDelegate, UINavigationBarDelegate> {
BOOL alertViewClicked;
BOOL regularPop;
}
#end
CustomNavigationController.m :
#import "CustomNavigationController.h"
#import "SettingsTableController.h"
#implementation CustomNavigationController
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
if (regularPop) {
regularPop = FALSE;
return YES;
}
if (alertViewClicked) {
alertViewClicked = FALSE;
return YES;
}
if ([self.topViewController isMemberOfClass:[SettingsTableViewController class]]) {
UIAlertView * exitAlert = [[[UIAlertView alloc] initWithTitle:#"Are you sure you want to quit?" message:nil delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Yes", nil] autorelease];
[exitAlert show];
return NO;
}
else {
regularPop = TRUE;
[self popViewControllerAnimated:YES];
return NO;
}
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
//Cancel button
}
else if (buttonIndex == 1) {
//Yes button
alertViewClicked = TRUE;
[self popViewControllerAnimated:YES];
}
}
#end
The weird logic with the "regularPop" bool is because for some reason just returning "YES" on shouldPopItem only pops the navbar, not the view associated with the navBar - for that to happen you have to directly call popViewControllerAnimated (which then calls shouldPopItem as part of its logic.)
For reference, the route I took after giving up on ShouldPopItem() is to replace the back button with a UIBarButtonItem that has a custom UIButton assigned as it's CustomView. The UIButton is crafted to look like the original back button using two images for the normal and the pressed state. Finally, hiding the original back button is required.
Way too much code for what it's supposed to do. So yeah, thanks Apple.
BTW: Another possibility is creating a UIButton with the secret UIButtonType 101 (which is actually the back button) but I avoided this as it may break at any later iOS version.
Override only UINavigationBarDelegate methods in a UINavigationController subclass and it should simply work. Be cautious that the protocol methods are also called when you push or pop a view controller from inside your code and not only when the back button is pressed. This is because them are push/pop notifications not button pressed actions.
Xamarin does provide the IUINavigationBarDelegate interface to allow you to implement the UINavigationBarDelegate as part of your custom UINavigationController class.
The interface however does not require that the ShouldPopItem method be implemented. All the interface does is add the appropriate Protocol attribute to the class so it can be used as a UINavigationBarDelegate.
So in addition you need to add the ShouldPopItem declaration to the class as follows:
[Export ("navigationBar:shouldPopItem:")]
public bool ShouldPopItem (UINavigationBar navigationBar, UINavigationItem item)
{
}
I've merged this solution with a native Obj-C solution. This is the way I'm currently handling the cancellation of the BACK button in iOS
It seems that it is possible to handle the shouldPopItem method of the NavigationBar in this way:
Subclass a UINavigationController
Mark your custom UINavigationController with the IUINavigationBarDelegate
Add this method with the Export attribute
[Export ("navigationBar:shouldPopItem:")]
public bool ShouldPopItem (UINavigationBar navigationBar, UINavigationItem item)
{
}
Now you can handle popping in the ShoulPopItem method. An example to this is to create an interface like this
public interface INavigationBackButton
{
// This method should return TRUE to cancel the "back operation" or "FALSE" to allow normal back
bool BackButtonPressed();
}
Then mark your UIViewController which needs to handle the back button with this interface. Implement something like this
public bool BackButtonPressed()
{
bool needToCancel = // Put your logic here. Remember to return true to CANCEL the back operation (like in Android)
return needToCancel;
}
Then in your ShouldPopItem Implementation have something like this
tanks to: https://github.com/onegray/UIViewController-BackButtonHandler/blob/master/UIViewController%2BBackButtonHandler.m
[Export("navigationBar:shouldPopItem:")]
public bool ShouldPopItem(UINavigationBar navigationBar, UINavigationItem item)
{
if (this.ViewControllers.Length < this.NavigationBar.Items.Length)
return true;
bool shouldPop = true;
UIViewController controller = this.TopViewController;
if (controller is INavigationBackButton)
shouldPop = !((INavigationBackButton)controller).BackButtonPressed();
if (shouldPop)
{
//MonoTouch.CoreFoundation.DispatchQueue.DispatchAsync
CoreFoundation.DispatchQueue.MainQueue.DispatchAsync(
() =>
{
PopViewController(true);
});
}
else
{
// Workaround for iOS7.1. Thanks to #boliva - http://stackoverflow.com/posts/comments/34452906
foreach (UIView subview in this.NavigationBar.Subviews)
{
if(subview.Alpha < 1f)
UIView.Animate(.25f, () => subview.Alpha = 1);
}
}
return false;
}

Adding actions to buttons in a subview

in my app i call a UIView and that UIView is like a settings screen in my app and i have buttons in the UIView and my question is how do i add actions to the buttons iv added to the UIViews subview? thanks,
Assuming you're writing code in a view controller for your settings UIView, the UIView is properly bound to the view property of your controller, and you have referenced one of the buttons with a variable button, here is what you would write:
- (void)viewDidLoad {
[super viewDidLoad];
[button addTarget:self
action:#selector(buttonPressed)
forControlEvents:UIControlEventTouchUpInside];
}
- (void)buttonPressed
{
// do things here in response to the button being pressed
}
Another way to write that method is passing in a pointer to the button which was actually pressed, like so:
- (void)viewDidLoad {
[super viewDidLoad];
[button addTarget:self
action:#selector(buttonPressed:) // note the extra colon here
forControlEvents:UIControlEventTouchUpInside];
}
- (void)buttonPressed:(id)sender
{
UIButton *buttonWhichWasPressed = (UIButton *)sender;
// now you can do things like hide the button, change its text, etc.
}
Rather than calling addTarget:action:forControlEvents:, though, in Interface Builder (you should be doing this) after defining the buttonPressed or buttonPressed: method above, in the .xib file with the button go to the second tab in the Inspector after clicking on the Button (it should say Button Connections), and click-drag the Touch Up Inside event to File's Owner, and select "buttonPressed" from the list.

UIactivityindicator doesn´t work in my project

I´m trying to deal with activityIndicator in my iPhone app.
But it doesn´t work at all.
Inside my project I have a UISearchbar.
When people put the keyword and click the search result will show string in UIWEbview.
I really want the activity indicator show and animate while waiting for data and Stop when data is loaded.
Here is some of the code I use :
#implementation myFirstappController
#synthesize myWebview, activityIndicator;
- (void)webViewDidStartLoad:(UIWebView *)myWebview
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[activityIndicator startAnimating];
}
- (void)webViewDidFinishLoad:(UIWebView *)myWebview
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[activityIndicator stopAnimating];
}
///Here is code inside the UISearchbar
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
NSString *keywords = searchBar.text;
NSString *infos = [NSString stringWithFormat: #"%#", keywords];
NSString *rs=nil;
if ([infos isEqualToString:#"Iloveyou"]){
rs =#"<span style='color:#3B5998; font-size:25px;font-weight: bold;'>I love you too </span> <span style='color:#666; font-size:18px;'> -rte,-rt </span> ;
[myWebview loadHTMLString:rs baseURL:nil];
}
- (void)dealloc {
[myWebview release]; //<-------JUST FILL THIS LINE**********************
[activityIndicator release];
[searchBar release];
[super dealloc];
}
#end
In your example you're "loading" a string, which will be instantaneous, so (because the iPhone combines animations) the indicator will never animate.
You should try your code with a remote URL.

Resources