How do I disable drag and drop on NSTextView? - drag-and-drop

I have a NSWindowController that contains several NSViewControllers. I would like to universally accept drag and drop events with the NSWindowController class and not be intercepted by other views such as NSTextView (contained in a NSViewController)
How can I tell NSTextView to ignore the drag & drop event?

I found out that there were two things needed to skip past NSTextView's interception of the drag and drop event.
In the NSViewController containing your NSTextView:
- (void)awakeFromNib
{
[self noDragInView:self.view];
}
- (void)noDragInView:(NSView *)view
{
for (NSView *subview in view.subviews)
{
[subview unregisterDraggedTypes];
if (subview.subviews.count) [self noDragInView:subview];
}
}
Now subclass your NSTextView and add this method:
- (NSArray *)acceptableDragTypes
{
return nil;
}
The NSTextView should now properly ignore the drag and drop event and leave it to be handled by the NSWindow.

It is sufficient to subclass the NSTextView and override the getter for its acceptableDragTypes property, no need to unregisterDraggedTypes. In Swift:
override var acceptableDragTypes : [String] {
return [String]()
}

Swift 5
import Cocoa
class NSTextViewNoDrop: NSTextView {
override var acceptableDragTypes: [NSPasteboard.PasteboardType] { return [] }
}

Slight update.
import Cocoa
class MyTextView : NSTextView {
// don't accept any drag types into the text view
override var acceptableDragTypes : [NSPasteboard.PasteboardType] {
return [NSPasteboard.PasteboardType]()
}
}

Related

Remove any view from any where e.g from window

I have 2 views on the screen, one is overlayView at the bottom and introView at the top of that overlayView. When I tap(tapToContinueAction) on the screen they should both hide or remove themselves.
extension UIView {
....
func hideView(view: UIView, hidden: Bool) {
UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: {
view.isHidden = hidden
})
}
}
class IntroScreen
#IBAction func tapToContinueAction(_ sender: UITapGestureRecognizer) {
self.hideView(view: self, hidden: true)
}
--
class OverlayView : UiView {
...
}
In current situation i can hide introScreen only and i dont know how the other class's action can effect the overlayView at the same time and hide that view as well. Any idea?
You have two different classes for your views. Make an extension of your window to remove your specific views just like I have made removeOverlay and removeIntroView both these computed properties will go and search in subviews list of window and check each view with their type and remove them. Thats how you can remove any view form any where.
class OverLayView: UIView {}
class IntroView: UIView {
#IBAction func didTapYourCustomButton(sender: UIButton) {
let window = (UIApplication.shared.delegate as! AppDelegate).window!
window.removeOverlay
window.removeIntroView
}
}
extension UIWindow {
var removeOverlay: Void {
for subview in self.subviews {
if subview is OverLayView {
subview.removeFromSuperview()// here you are removing the view.
subview.hidden = true// you can hide the view using this
}
}
}
var removeIntroView: Void {
for subview in self.subviews {
if subview is IntroView {
subview.removeFromSuperview()// here you are removing the view.
subview.hidden = true// you can hide the view using this
}
}
}
}

How to determine the active textfield

How to determine which text field is active ? (which one have the focus on it).
I found this code in objective-C but don't know how if it is still working and how to translate it in swift
NSResponder *firstResponder = [[NSApp keyWindow] firstResponder];
if ([firstResponder isKindOfClass:[NSText class]] && [(id)firstResponder delegate] == mySearchField) {
NSLog(#"Yup.");
}
Here you go:
var responder = window.firstResponder
if responder.isKind(of: NSText.self) {
let fieldEditor = responder as! NSText
responder = fieldEditor.delegate as! NSResponder
}
At the end is responder the focused control. If the focused control is a NSTextField then the first responder is the field editor, a NSTextView inside the text field. The delegate of the field editor is the control.
Umm here is how I would do it in iOS if anyone is interested. I am not familiar with how Mac OS deals with firstResponder, but it looks to be quite different.
func findFirstResponder(in view: UIView) -> UIView? {
for subview in view.subviews {
if subview.isFirstResponder {
return subview
}
if let firstReponder = findFirstResponder(in: subview) {
return firstReponder
}
}
return nil
}
You can do an if else and iterate over each textField so you can know what textField is the firstResponder.
func methodForDiscoverTheFirstResponder {
if myTextField.isFirstResponder {
//do stuff
} else if mySecondTextField.isFirstResponder {
//do stuff
}
...
}

Action method not working OSX

I am trying to handle a click event if the user presses on a textfield. Somehow it is not jumping inside the function. Here is my code:
class ViewController: NSViewController {
override func viewDidLoad() {
let textField2 = NSTextField(frame: CGRectMake(30, 30, 37, 17))
textField2.stringValue = "Label"
textField2.bordered = false
textField2.backgroundColor = NSColor.controlColor()
view.addSubview(textField2)
textField2.action = #selector(myAction)
}
func myAction(sender: NSView)
{
print("aktuell: \(sender)")
currentObject = sender
}
}
If I click on the textfield it is not jumping inside the function.
Does anybody know how to link the textfield to the function? Please note that it has to be that function because I am linking other controls to it as well (e.g. buttons).
You can't link a text field like that. What is it you're trying to accomplish? You probably want the NSTextFieldDelegate methods instead. Look at the help on that protocol. If those have what you want, then just set textField2.delegate = self and then implement the protocol.
Implement - (void)textFieldDidBeginEditing:(UITextField *)textField method of UITextFieldDelegate protocol. For example:
- (void)textFieldDidBeginEditing:(UITextField *)textField{
if textField.isEqual(firstTextField){
//some code
}
if textField.isEqual(secondTextField){
//other code
}
}

MonoTouch UITableViewController and TableFooterView

I'm trying to develop a small iPhone application using MonoDevelop (v2.8) and MonoTouch (v4.2.2).
My home screen is represented by a UITableViewController which use a UITableView for presentation. I want to fill the UITableView.TableFooterView (which is a UIView object) with some other controls (two labels and two buttons).
To do this I have created a "subview" called SearchView, which is represented by a UIViewController and use a simple UIView for presentation. I assign this view as footer view of the tableview.
public partial class HomeScreen : UITableViewController
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
SearchViewController searchViewController = new SearchViewController();
this.TableView.TableFooterView = searchViewController.View;
}
}
Is this right?
It is right to assume that usaually you create a view (UIView) and consume it by a UIViewController ?
- (void)loadView {
[super loadView];
sBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0,0,320,30)];
sBar.delegate = self;
[self.view addSubview:sBar];
you can add subviews like this ,sbar is the search bar,u can also add any controllers like button ,labels ,textview,textfield in it.
In your UITableViewDataSource you can override public virtual UIView GetViewForFooter(UITableView tableView, int sectionIndex)
public override UIView GetViewForFooter(UITableView tableView, int sectionIndex)
{
// Write a method to get the proper Section via the sectionIndex
var section = GetSection(sectionIndex);
if (section != null)
{
if (section.FooterView == null && !string.IsNullOrEmpty(section.FooterText))
{
// Create your FooterView here
section.FooterView = CreateFooterView(tableView, section.FooterText);
}
return section.FooterView;
}
return null;
}
As of iOS 5 you will also need to override
public virtual float GetHeightForFooter(UITableView tableView, int sectionIndex)
and return the height of the FooterView

Is there a UIView resize event?

I have a view that has rows and columns of imageviews in it.
If this view is resized, I need to rearrange the imageviews positions.
This view is a subview of another view that gets resized.
Is there a way to detect when this view is being resized?
As Uli commented below, the proper way to do it is override layoutSubviews and layout the imageViews there.
If, for some reason, you can't subclass and override layoutSubviews, observing bounds should work, even when being kind of dirty. Even worse, there is a risk with observing - Apple does not guarantee KVO works on UIKit classes. Read the discussion with Apple engineer here: When does an associated object get released?
original answer:
You can use key-value observing:
[yourView addObserver:self forKeyPath:#"bounds" options:0 context:nil];
and implement:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (object == yourView && [keyPath isEqualToString:#"bounds"]) {
// do your stuff, or better schedule to run later using performSelector:withObject:afterDuration:
}
}
In a UIView subclass, property observers can be used:
override var bounds: CGRect {
didSet {
// ...
}
}
Without subclassing, key-value observation with smart key-paths will do:
var boundsObservation: NSKeyValueObservation?
func beginObservingBounds() {
boundsObservation = observe(\.bounds) { capturedSelf, _ in
// ...
}
}
Create subclass of UIView, and override layoutSubviews
Swift 4 keypath KVO -- This is how I detect autorotate and moving to iPad side panel. Should work work any view. Had to observe the UIView's layer.
private var observer: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
observer = view.layer.observe(\.bounds) { object, _ in
print(object.bounds)
}
// ...
}
override func viewWillDisappear(_ animated: Bool) {
observer?.invalidate()
//...
}
You can create a subclass of UIView and override the
setFrame:(CGRect)frame
method. This is the method called when the frame (i.e. the size) of the view is changed. Do something like this:
- (void) setFrame:(CGRect)frame
{
// Call the parent class to move the view
[super setFrame:frame];
// Do your custom code here.
}
Pretty old but still a good question. In Apple's sample code, and in some of their private UIView subclasses, they override setBounds roughly like:
-(void)setBounds:(CGRect)newBounds {
BOOL const isResize = !CGSizeEqualToSize(newBounds.size, self.bounds.size);
if (isResize) [self prepareToResizeTo:newBounds.size]; // probably saves
[super setBounds:newBounds];
if (isResize) [self recoverFromResizing];
}
Overriding setFrame: is NOT a good idea. frame is derived from center, bounds, and transform, so iOS will not necessarily call setFrame:.
If you're in a UIViewController instance, overriding viewDidLayoutSubviews does the trick.
override func viewDidLayoutSubviews() {
// update subviews
}