I have a round rect UIButton with an action method defined to it -(IBAction)btnclicked:(id)sender. Now I wanna create another method -(void)disableButton which disables this button of mine. So I can call this function whenever I need. How can I use this mybtn.enabled = NO; into this function? What will this function look like?
Here is a simple solution
I assume mybtn will be in your header file as a instance variable
Take another button and bind this below IBAction or you can call this function directly in the same class like this [self disableButton];
-(IBAction)disableButton {
//Disable mybtn
mybtn.enabled = NO;
}
If you are using IB for button then create an IBOutlet for your button and map it with the button in InterfaceBuilder.
IBOutlet UIBUTTON *mybtn;
Now in :
-(void)disableButton{
mybtn.enabled = NO;
}
.h
{
IBOutlet UIBUTTON *mybtn;
}
-(IBAction)btnclicked:(id)sender;
-(void)disableButton;
.m
-(IBAction)btnclicked:(id)sender{
[self disableButton];
}
-(void)disableButton {
mybtn.enabled = NO;
}
Related
I need to add a save extension selector with a text label next to it to my NSSavePanel. In the screenshot attached I try to demonstrate that I succeeded in adding an NSComboBox to my panel with the function setAccessoryView. However I have no idea how to create a custom NSView, which includes both an NSComboBox and an NSTextView or equivalent. I found no tutorials on the internet (or if I found one it was extremely outdated) showing how to create custom NSViews in objective-C in Cocoa on MacOS.
How can I create a custom NSView containing a combobox and a text label? Or how can I add two "stock" NSViews to the same NSSavePanel? Please be as detailed in your answer as possible, as I have very limited objective-c experience.
You asked how to create an NSView in Objective-C with an NSTextField and an NSComboBox as subviews.
Basically, you could define them in Interface Builder and programmatically set the resulting view in Objective-C as the accessoryView of the NSSavePanel. Alternatively, the custom NSView could be created entirely in Objective-C, which is probably the easier option here.
After instantiating an NSView, you can use addSubview: to add an NSTextField and an NSComboBox accordingly. Then you can use NSLayoutConstraints to set up Auto Layout, which takes care of sizing the accessoryView and arranging the subviews properly based on the width of the dialog.
If you create the views programmatically and use Auto Layout, you must explicitly set translatesAutoresizingMaskIntoConstraints to NO.
Should you want to set the allowedContentTypes, a textual mapping of the displayed extension to UTType via a NSDictionary might be useful.
If you set the delegate of the NSComboBox to self, then you will be informed about changes of the user selection in the NSComboBox via comboBoxSelectionDidChange:.
If the things discussed are implemented appropriately in code, it might look something like this for a self-contained example:
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
#import "ViewController.h"
#interface ViewController () <NSComboBoxDelegate>
#property (nonatomic, strong) NSSavePanel *savePanel;
#property (nonatomic, strong) NSDictionary<NSString *, UTType*> *typeMapping;
#end
#implementation ViewController
- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
_typeMapping = #{
#"jpeg": UTTypeJPEG,
#"png": UTTypePNG,
#"tiff": UTTypeTIFF
};
}
return self;
}
- (NSView *)accessoryView {
NSTextField *label = [NSTextField labelWithString:#"Filetypes:"];
label.textColor = NSColor.lightGrayColor;
label.font = [NSFont systemFontOfSize:NSFont.smallSystemFontSize];
label.alignment = NSTextAlignmentRight;
NSComboBox *comboBox = [NSComboBox new];
comboBox.editable = NO;
for (NSString *extension in self.typeMapping.allKeys) {
[comboBox addItemWithObjectValue:extension];
}
[comboBox setDelegate:self];
NSView *view = [NSView new];
[view addSubview:label];
[view addSubview:comboBox];
comboBox.translatesAutoresizingMaskIntoConstraints = NO;
label.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:#[
[label.bottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:-12],
[label.widthAnchor constraintEqualToConstant:64.0],
[label.leadingAnchor constraintEqualToAnchor:view.leadingAnchor constant:0.0],
[comboBox.topAnchor constraintEqualToAnchor:view.topAnchor constant:8.0],
[comboBox.leadingAnchor constraintEqualToAnchor:label.trailingAnchor constant:8.0],
[comboBox.bottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:-8.0],
[comboBox.trailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:-20.0],
]];
return view;
}
- (void)comboBoxSelectionDidChange:(NSNotification *)notification {
NSComboBox *comboBox = notification.object;
NSString *selectedItem = comboBox.objectValueOfSelectedItem;
NSLog(#"### set allowedContentTypes to %# (%#)", selectedItem, self.typeMapping[selectedItem]);
[self.savePanel setAllowedContentTypes:#[ self.typeMapping[selectedItem] ]];
}
- (IBAction)onSave:(id)sender {
NSWindow *window = NSApplication.sharedApplication.windows.firstObject;
self.savePanel = [NSSavePanel new];
self.savePanel.accessoryView = [self accessoryView];
[self.savePanel beginSheetModalForWindow:window completionHandler:^(NSModalResponse result) {
if (result != NSModalResponseOK) {
return;
}
NSURL *fileURL = self.savePanel.URL;
NSLog(#"### selectedFile: %#", fileURL);
}];
}
- (void)setRepresentedObject:(id)representedObject {
[super setRepresentedObject:representedObject];
}
#end
Finally, a screenshot of the above demo code in action looks like this:
Press Cmd-N to add a new file to your project. Choose a View file to add a xib file that has a custom view.
Open the xib file and add the controls to the custom view. Press the Add button in the project window toolbar to access the user interface elements.
Use the NSNib class to load the xib file and get the custom view.
I have two custom NSToolbarItems in the toolbar of the application. Each class has a NSButton within, where I setup the button and then set the toolbar item's view to the button (the stop button item for example):
#implementation RBSStopButtonToolbarItem
#synthesize button = _button;
-(id)initWithItemIdentifier:(NSString *)itemIdentifier
{
self = [super initWithItemIdentifier:itemIdentifier];
if(self)
{
// create button
_button = [[NSButton alloc] init];
// set the frame and bounds to be the same size
//[_button setFrameSize:NSMakeSize(64.0, 64.0)];
//[_button setBoundsSize:NSMakeSize(64.0, 64.0)];
// button will not have a visible border
[_button setBordered:NO];
// set the original and alternate images...names are "opposite"
[_button setImage:[NSImage imageNamed:#"StopButtonAlternateIcon"]];
[_button setAlternateImage:[NSImage imageNamed:#"StopButtonIcon"]];
// image position
[_button setImagePosition:NSImageOnly];
// set button type
[_button setButtonType:NSMomentaryChangeButton];
// button is transparent
[_button setTransparent:YES];
// set the toolbar item view to the button
[self setView:_button];
}
return self;
}
I have an IBOutlet for each custom NSToolbarItem:
// toolbar item for start button
IBOutlet RBSStartButtonToolbarItem *_startButtonToolbarItem;
// toolbar item for stop button
IBOutlet RBSStopButtonToolbarItem *_stopButtonToolbarItem;
Yet I do not see the images in the custom view toolbar items:
The images are .icns type. The example I attempted to following is here:
NSButton in NSToolbar item: click issue
Is there anyone with experience who can offer advice?
I don't know why, but:
[NSToolbarItem initWithCoder:] is calling [NSToolbarItem setImage:] which is then calling [NSButton setImage:] on the button you have set as the toolbar item's view. This wipes out what you have done.
The example that you are referring to DOES NOT subclass NSToolbarItem.
I recommend that you also DO NOT subclass NSToolbarItem, and instead add a regular NSToolbarItem to the toolbar via interface builder and then in awakeFromNib find that toolbar item via its item identifier and set the button as its view.
I have verified that doing it this way works as expected.
I do not follow why your example doesn't work.
But I have worked out the custom NSToolbarItem with my own way without even using NSToolbarDelegate.
My way is assuming you build your toolbar within a nib and not with code(mostly).
What I am doing is creating my own NSView in my nib with whatever I want in it.
Then I drag this NSView into into my NSToolbar in my nib.
xCode will automatically place your NSView inside an NSToolbarItem.
You can then drag this custom NSToolbarItem into the default items and place it with whatever order you want(so you don't even need to place it by code).
The tricky part is to subclass NSToolbarItem and then within the awakeFromNib of this specific NSToolbarItem subclss you set it's view to the NSView underneath it.
You would also need to refer the NSView into an IBOutlet * NSView within that subclass.
Here is the code of the subclass.
The header file:
#import <Cocoa/Cocoa.h>
#interface CustomToolbarItem : NSToolbarItem
{
IBOutlet NSView * customView;
}
#end
The Obj-c file:
#import "CustomToolbarItem.h"
#implementation CustomToolbarItem
-(instancetype)initWithItemIdentifier:(NSString *)itemIdentifier
{
self = [super initWithItemIdentifier:itemIdentifier];
if (self)
{
}
return self;
}
-(void)awakeFromNib
{
[self setView:customView];
}
#end
I have also wrote a blog post about how I did this:
http://pompidev.net/2016/02/24/make-a-custom-nstoolbar-item-in-xcodes-interface-builder/
I have a UISegmentedControl button with three segments.
In ViewController.m this is working just fine -- pressing the buttons fires the correct methods.
I have another separate UIButton that when it is pressed it needs to first CHECK the state of the UISegmentedControl (to see which button is currently pressed) and then fire a method according to that segment value.
Here is my code for that separate UIButton. The button itself is working, but I cannot seem to figure out how to GET the current value of the segment of the UISegmentedControl.
Many thanks for any assistance here.
I am new to OBJ-C. I know how to do this in VisualBasic, so answers that are on the more verbose side would be most appreciated as I need to know the 'why'. Thank you.
- (IBAction)decodeButton:(id)sender {
UISegmentedControl *segment = [UISegmentedControl alloc]; // THIS DOES NOT WORK.
if (segment.selectedSegmentIndex == 0) {
decode(textToDecode);
} else if(segment.selectedSegmentIndex == 1) {
decode1(textToDecode);
} else if(segment.selectedSegmentIndex == 2) {
decode2(textToDecode);
}
}
Here is a Tutorial using UISegmentedControl in iOS.
Just Create a Reference object and wire it properly to File Owner.
IBOutlet UISegmentedControl *segmentedControl;
Then set property
#property (strong, nonatomic) IBOutlet UISegmentedControl * segmentedControl;
Synthesize in .m file
#synthesize segmentedControl;
Now You can Access the selected index at any time.
- (IBAction)decodeButton:(id)sender {
if (segmentedControl.selectedSegmentIndex == 0) {
decode(textToDecode);
} else if(segmentedControl.selectedSegmentIndex == 1) {
decode1(textToDecode);
} else if(segmentedControl.selectedSegmentIndex == 2) {
decode2(textToDecode);
}
}
Your code alloc every time UISegmentedControl in the button press action. So use the following code for sUISegmentedControl creation and its action .
SegmentChangeView=[[UISegmentedControl alloc]initWithItems:[NSArray arrayWithObjects:#"Segment1",#"Segment2",#"Segment3",nil]];
SegmentChangeView.frame=CGRectMake(5, 44, self.view.bounds.size.width-10, 33);
SegmentChangeView.selectedSegmentIndex=0;
SegmentChangeView.segmentedControlStyle=UISegmentedControlStyleBar;
SegmentChangeView.momentary = YES;
[SegmentChangeView setTintColor:[UIColor blackColor]];
NSDictionary *attributes =[NSDictionary dictionaryWithObjectsAndKeys:[UIFont fontWithName:#"Arial" size:13],UITextAttributeFont,nil];
[SegmentChangeView setTitleTextAttributes:attributes forState:UIControlStateNormal];
[SegmentChangeView addTarget:self action:#selector(SegmentChangeViewValueChanged:) forControlEvents:UIControlEventValueChanged];
SegmentChangeView.autoresizingMask=UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleBottomMargin;
[self.view addSubview:SegmentChangeView];
-(IBAction)SegmentChangeViewValueChanged:(UISegmentedControl *)SControl
{
if (SControl.selectedSegmentIndex==0)
{
decode(textToDecode);
}
else if (SControl.selectedSegmentIndex==1)
{
decode1(textToDecode);
}
else if (SControl.selectedSegmentIndex==2)
{
decode2(textToDecode);
}
}
You should remove UISegmentedControl *segment = [UISegmentedControl alloc] ; from your code, as it allocs anew instance of your UISegmentedControl every time, instead,
create an outlet for you UISegmentController like
#property (strong, nonatomic) IBOutlet UISegmentedControl * segment;
and then later at any point in your viewcontroller.m file, you can get the currently selected segment by using
segment.selectedSegmentIndex;
Hope this make sense,
Regards
Try like this
- (IBAction)segmentedControlChanged:(id)sender
{
UISegmentedControl *s = (UISegmentedControl *)sender;
if (s.selectedSegmentIndex == 1)
{
//code
}
else
{
//code
}
}
This code means you are creating a new Object on every click
UISegmentedControl *segment = [UISegmentedControl alloc] ;
The thing you have to do take IBOutlet (Property) of your segmentedControl then I will work for you. dont create a new object in the button method. when you will make a IBOutlet it will be link with at segmentControl and your code will work that time . Thanks
I am hoping to "automate" a click on the segmentController with the index of 0.
My tabBar-based app has multiple segmentControllers in a tab in the ViewDidAppear method, I would like to automatically have it "click" the first segmented controller.
if (segmentController.selectedSegmentIndex == 0) {
//stuff here
}
if (segmentController.selectedSegmentIndex == 1) {
//stuff here
}
Does anyone know how I might accomplish this? Thank you!
If you're creating it programmatically, you could lazy load it like this:
#interface ExampleViewController : UIViewController
#property (nonatomic, strong) UISegmentedControl *segmentedControl;
- (void)segmentedControlClicked:(UISegmentedControl *)segmentedControl;
#end
#implementation ExampleViewController
- (UISegmentedControl *)segmentedControl
{
if (!_segmentedControl)
{
NSArray *items = #[#"First", #"Second", #"Third"];
_segmentedControl = [[UISegmentedControl alloc] initWithItems:items];
[_segmentedControl addTarget:self
action:#selector(segmentedControlClicked:)
forControlEvents:UIControlEventValueChanged];
[_segmentedControl setSelectedSegmentIndex:0]; // Set Default selection
CGRect frame = _segmentedControl.frame;
frame.origin = CGPointMake(0.0f, 0.0f); // Move to wherever you need it
[self.view addSubview:_segmentedControl];
}
return _segmentedControl;
}
- (void)segmentedControlClicked:(UISegmentedControl *)segmentedControl
{
// Whatever your code is goes here...
}
#end
If you're wanting a method to be called also initially, you can call it within your viewDidLoad: method as such:
- (void)viewDidLoad
{
[self.segmentedControl setSelectedSegmentIndex:0]; // Set desired default index (optional if set in lazy load as shown above)
[self segmentedControlClicked:self.segmentedControl];
}
This would hence simulate a click on desired default index.
Be careful putting the above into viewDidAppear: (you could if you really wanted to) because anytime the view comes to the front, this method will be called (in example, if this view controller presents a modal view controller, once the modal is dismissed, this view controller's viewDidAppear: method will be called).
Cheers!
Set the selectedSegmentIndex property on your UISegmentedControl in your viewDidAppear (or viewDidLoad) method.
self.segmentedController.selectedSegemntIndex = 1;
UISegmentedControl Reference
Say I have a switch and a small table view(no scroll) below it. I know if the switch is turned on/off using a bool switchState whose value get changed in the action method of the switch:
-(IBAction)switchSlide:(id)sender{
if (toggleSwitch.on == YES) {
switchState = YES;
}
else{
switchState = NO;
}
}
Now what I want is that the table view below it should hide when the switchState == NO. How do I do that?
Every UIView has a property hidden:
#property(nonatomic, getter=isHidden) BOOL hidden
since a UITableView is a sublass of UIView you can use the methods from a UIView too.
So your code just need a little adjustment (assuming you are calling this IBAction in a UITableViewController):
-(IBAction)switchSlide:(id)sender{
if (toggleSwitch.on == YES) {
switchState = YES;
self.tableView.hidden = NO;
}
else{
switchState = NO;
self.tableView.hidden = YES;
}
}
Edit:
Solved this via chat and the solution is:
Since you used a UIViewController you have to make a propert for the UITableView. synthesize it and connect the outlet by dragging from the files owner to the UITableView in the interface builder. Now you can use the code above.