I'm using SWRevealViewContrtoller for slide-out side menu in my app. Which is working fine. But I have an issue, how can I change side-bar button image when button clicked or user dragged side menu. I'm referring to this link.
Thanks in advance
Try to do following-
Method 1 (as per your reference link):
In your homeVC.m set SWRevealViewControllerDelegate like
#interface homeVC ()<SWRevealViewControllerDelegate> and add in viewDidLoad()
self.revealViewController.delegate = self;
then add this method-
-(void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position{
//check position here
if(position == FrontViewPositionLeft) {
[self.sideBarButton setImage:[UIImage imageNamed:#"open.png"] forState:UIControlStateNormal]; //self.sideBarButton is your toggle button IBOutlet
}
else if(position == FrontViewPositionRight) {
[self.sideBarButton setImage:[UIImage imageNamed:#"close.jpg"] forState:UIControlStateNormal];
}
}
Method 2:
In your sideVC.m import-
#import "homeVC.h"
#import "SWRevealViewController.h"
Now add viewWillAppear() and viewWillDisappear()-
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
homeVC *vc=(UserProfileViewController*)self.revealViewController.frontViewController;
[vc.sideBarButton setImage:[UIImage imageNamed:#"close.jpg"] forState:UIControlStateNormal];
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
homeVC *vc=(UserProfileViewController*)self.revealViewController.frontViewController;
[vc.sideBarButton setImage:[UIImage imageNamed:#"open.jpg"] forState:UIControlStateNormal];
}
difference between Method1 and Method2 is that, In Method1 when sideVC done animation i.e. position set to FrontViewPositionLeft or FrontViewPositionRight than button image changes by clicking button or dragging view. But in Method2 when sideVC start appearing button image change and when sideVC disappear.
Try FRDLivelyButton. In this library, you can change the UIBarButton image.
Hope it helps.
add <SWRevealViewControllerDelegate>
set self.revealViewController.delegate = self;
- (void)revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position{
//change button image below.
if(position == FrontViewPositionLeft) {
//drawer close
} else {
//drawer open
}
}
This works for me. Happy coding
UPDATE Swift 3.0
add SWRevealViewControllerDelegate
in your viewDidLoad() add this
self.revealViewController().delegate = self
func revealController(_ revealController: SWRevealViewController!, willMoveTo position: FrontViewPosition) {
if position == FrontViewPosition.left {
//drawer close
}
else {
//drawer open
}
}
Related
I'm building an messaging app, I use JSQMessageViewController to render messages and it's awesome.
Now I have a little problem trying to customize the send button:
Basically I want to replace left and right BarButtonItem to customized button with images.
After some hours of reading and searching, I got this far now:
button without text
button with text
As shown in the pictures, the voice button which is replacing the original send button is disabled if there is no text in the textField, this behavior is not what I want. How do I disable this behavior and make the button available all the time?
And this is how I customize the send button:
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeCustom];
[rightButton setBackgroundImage:[UIImage imageNamed:#"AudioButton#2x.png"] forState:UIControlStateNormal];
self.inputToolbar.contentView.rightBarButtonItem = rightButton;
if you want button available all the time,
Find This method in "JSQMessagesInputToolbar.h" And Comment These lines in OLD Code
- (void)toggleSendButtonEnabled
{
BOOL hasText = [self.contentView.textView hasText];
// if (self.sendButtonOnRight) {
// self.contentView.rightBarButtonItem.enabled = hasText;
// }
// else {
// self.contentView.leftBarButtonItem.enabled = hasText;
// }
}
in New JSQ Code
- (void)updateSendButtonEnabledState
{
if (!self.enablesSendButtonAutomatically) {
return;
}
BOOL enabled = [self.contentView.textView hasText];
// switch (self.sendButtonLocation) {
// case JSQMessagesInputSendButtonLocationRight:
// self.contentView.rightBarButtonItem.enabled = enabled;
// break;
// case JSQMessagesInputSendButtonLocationLeft:
// self.contentView.leftBarButtonItem.enabled = enabled;
// break;
// default:
// break;
// }
}
this will work if you are replacing your custom button in rightBarButtonItem
add this in viewDidAppear
[self.inputToolbar.contentView.rightBarButtonItem setEnabled:YES];
and override textview delegate
-(void)textViewDidChange:(UITextView *)textView;
I have 2 different UIViewController setup already. There is a UIBarButtonItem on the parent view and when user clicks on it, it's suppose to load a form (2nd UIView).
But on the UIBarButtonItem, I have a popover view. So When they click on the button, popover shows with 6 different UIButton and when they select one, the form loads. Please take a look at the following image to see what I'm talking about.
http://oi58.tinypic.com/f0cbae.jpg
This is because form is different for those 6 different UIButton.
How can I load same form in different mode?
If Button1 is clicked, how would the form know which mode was selected?
I figured I would need parameters for class but couldn't make it work.
============
EDIT:
This is what I tried:
public partial class AddAbsence_iPhone : UIViewController {
public void absenceTypeSelection (string mode) {
if (mode == “Button1”) {
this.lbl_AbsenceType.Text = “Button1”;
} else if (currentAbsenceType == "Button2”) {
this.lbl_AbsenceType.Text = "Button2";
} else if (currentAbsenceType == "Button3”) {
this.lbl_AbsenceType.Text = "Button3”;
} else if (currentAbsenceType == "Button4”) {
this.lbl_AbsenceType.Text = "Button4”;
} else if (currentAbsenceType == "Button5”) {
this.lbl_AbsenceType.Text = "Button5”;
} else if (currentAbsenceType == "Button6”) {
this.lbl_AbsenceType.Text = "Button6;
}
}
}
and this is how I am adding event to one of the buttons.
public partial class Absensehome_iPhone : UIViewController {
AddAbsence_iPhone addAbsence;
public override void ViewDidLoad () {
button2.TouchUpInside += (sender, e) => {
this.addAbsence = new AddAbsence_iPhone(this);
this.NavigationController.PushViewController(addAbsence,true);
addAbsence.absenceTypeSelection("Button2");
};
}
}
Absencehome_iPhone is the parent view controller.
AddAbsence_iPhone is the form, which I want to show once the button is clicked
When I run this, I get the following error:
Object reference not set to an instance of an object
If you are presenting from a UIPopoverController, you must have a UIViewController subclass. I'm assuming that same class is where you are listening for button taps. With a UIButton, that would be done by registering a listener using:
- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
So, you could register a different method for each button in that list.
- (void)viewDidLoad
{
[self.button1 addTarget:self action:#selector(button1Tapped:) forControlEvents:UIControlEventTouchUpInside];
[self.button2 addTarget:self action:#selector(button2Tapped:) forControlEvents:UIControlEventTouchUpInside];
}
If you were generating those buttons programmatically, or there were some other good reason why you couldn't control your flow by registering different handlers, you could register one handler for all the buttons, and check the text of the button that was tapped and passed as the 'sender' parameter:
- (void)viewDidLoad
{
[self.button1 addTarget:self action:#selector(aButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
[self.button2 addTarget:self action:#selector(aButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
}
- (IBAction)aButtonTapped:(id)sender
{
if ([sender isKindOfClass:UIButton.class])
{
UIButton* buttonTapped = (UIButton*)sender;
if ([buttonTapped.titleLabel.text isEqualToString:#"Button1"])
{
[self button1Tapped];
}
else if ([buttonTapped.titleLabel.text isEqualToString:#"Button2"])
{
[self button2Tapped];
}
}
}
If my button is in the "selected" state, I want an activity indicator to appear to let the user know that something is happening and that my app is searching for data. I've tried to accomplish this FIRST by using NSLog to see if I can get this method working FIRST. So I did this:
- (void)viewDidLoad
{
[super viewDidLoad];
searchedItem.delegate = self;
if(searchButton.selected == YES)
{
NSLog(#"The button was selected");
}
}
For some reason, it won't work.
Put this checkmark in your button click event. It perfect work when click on button as first time then got to Not Selected and after click on second time go to Selected.
-(IBAction)ClickBtn:(UIButton *)sender
{
sender.selected = ! sender.selected;
if (sender.selected)
{
NSLog(#" Not Selected");
}
else
{
NSLog(#" Selected");
}
}
try this
- (void)viewDidLoad
{
[super viewDidLoad];
searchedItem.delegate = self;
[searchButton setSelected:YES];
if(searchButton.selected == YES)
{
NSLog(#"The button was selected");
}
}
i have a Navigation Bar, wich contains a Navigation Item, which contains 2 Bar Buttons, these are created in the Storyboard, and i wanted to change 1 of the buttons at runtime, now this works:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
UINavigationItem *thisNavBar = [self myNavigationItem];
thisNavBar.rightBarButtonItem = nil; // this works, it gets removed
UIBarButtonItem *insertBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(insertSkemaItem:)];
thisNavBar.rightBarButtonItem = insertBtn; // this also works, it sets the btn
}
Now, in my other method, which is called by another controller, it does not work
- (void)callChildChange {
...
// remove old btn
UINavigationItem *thisNavBar = [self skemaNavigationItem];
thisNavBar.rightBarButtonItem = nil; // does not work?
}
There is nothing wrong with the method, it runs just fine, but the nav btn item does not get removed ?
skemaNavigationItem is a Navigation item, declared in the .h file which links the navigation item i made via the storyboard.
Your UI items need to be added to your code (by ctrl-dragging) in the header file (.h) so they can be publicly accessed from other classes/view controllers.
Presuming you've done this, hiding a UI item is best done by using
relevantClass.yourViewObject.hidden = YES;
or if you really need to delete it for good,
[relevantClass.yourViewObject.view removeFromSuperView];
Edits
Options for changing target method:
Declare #property (nonatomic, assign) BOOL myButtonWasPressed; and:
- (IBAction) myButtonPressed
{
if (!self.myButtonWasPressed)
{
// This code will run the first time the button is pressed
self.myButton.text = #"New Button Text";
self.myButtonWasPressed = YES;
}
else
{
// This code will run after the first time your button is pressed
// You can even set your BOOL property back, and make it toggleable
}
}
or
- (IBAction) myButtonWasPressedFirstTime
{
// do what you need to when button is pressed then...
self.myButton.text = #"New Button Text";
[self.myButton removeTarget:self action:#selector(myButtonPressedFirstTime) forControlEvents:UIControlEventTouchUpInside];
[self.myButton addTarget:self action:#selector(myButtonPressedAgain) forControlEvents: UIControlEventTouchUpInside];
}
- (IBAction) myButtonWasPressedAgain
{
// this code will run the subsequent times your button is pressed
}
I drag 2 IBActions from a UIButton, one with touchDown event and second with drag Inside.
- (IBAction)clickButton:(UIButton *)sender {
NSLog(#"Click Button");
}
- (IBAction)dragInsideButton:(UIButton *)sender {
NSLog(#"Drag Button");
}
But when I drag inside, the touchDown action also gets fired.
How to disable touchDown event when dragInside.
Thanks!
i have solved a problem like this with using drag Events
add events to your button in .xib file or programatically.
programmatically is:
[mybut addTarget:self action:#selector(dragBegan:withEvent: )
forControlEvents: UIControlEventTouchDown];
[mybut addTarget:self action:#selector(dragMoving:withEvent: )
forControlEvents: UIControlEventTouchDragInside];
[mybut addTarget:self action:#selector(dragEnded:withEvent: )
forControlEvents: UIControlEventTouchUpInside |
UIControlEventTouchUpOutside];
then defininitons of events are:
- (void) dragBegan: (UIButton *) c withEvent:ev
{
NSLog(#"dragBegan......");
count=NO;//bool Value to decide the Down Event
c.tag=0;
[self performSelector:#selector(DownSelected:) withObject:mybut afterDelay:0.1];
//user must begin dragging in 0.1 second else touchDownEvent happens
}
- (void) dragMoving: (UIButton *) c withEvent:ev
{
NSLog(#"dragMoving..............");
c.tag++;
}
- (void) dragEnded: (UIButton *) c withEvent:ev
{
NSLog(#"dragEnded..............");
if (c.tag>0 && !count)
{
NSLog(#"make drag events");
}
}
-(void)DownSelected:(UIButton *)c
{
if (c.tag==0) {
NSLog(#"DownEvent");
count=YES;//count made Yes To interrupt drag event
}
}
This method is tested, and should do what I think you're trying to do. You can change the delay in the timer to get the effect you want. I had to connect 3 actions to the button to make this work -- the third action is a touchUp that resets the system to the starting condition.
#interface LastViewController ()
#property (nonatomic) BOOL touchedDown;
#property (strong,nonatomic) NSTimer *downTimer;
#end
#implementation LastViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.touchedDown = NO;
}
-(IBAction)clickDown:(id)sender {
self.downTimer = [NSTimer scheduledTimerWithTimeInterval:.3 target:self selector:#selector(buttonAction:) userInfo:nil repeats:NO];
}
-(IBAction)dragInside:(id)sender {
[self.downTimer invalidate];
[self buttonAction:self];
}
-(void) buttonAction:(id) sender {
if ([sender isKindOfClass:[NSTimer class]]) {
self.touchedDown = YES;
NSLog(#"click down");
}else{
if (! self.touchedDown) {
NSLog(#"Drag");
}
}
}
-(IBAction)touchUpAction:(id)sender {
self.touchedDown = NO;
}
Try this way:
isClicked is property of type BOOL. Set to YES.
- (IBAction)clickButton:(UIButton *)sender { //touch down
if(isClick==YES){
NSLog(#"Click Button");
//do all your stuffs here
}
isClick=YES;
}
- (IBAction)dragInsideButton:(UIButton *)sender {
NSLog(#"Drag Button");
isClick=NO;
}
On top of this you can also implement removeTarget:Action:
Which ever method gets called first set isClick=NO, I expect clickButton is called first in button action.
I got from Two action methods for an UIButton; next track and seek forward:
Change it As per your requirement.
Personally I'd just track the button's state with an integer on your view controller or within a button subclass. If you track what the button is doing you can control what each of the actions do. In your .h file put in some stuff like this:
enum {
MyButtonScanning,
MyButtonStalling,
MyButtonIdle
};
#interface YourClass : UIViewController {
NSInteger buttonModeAt;
}
#property (nonatomic) NSInteger buttonModeAt;
-(IBAction)buttonPushedDown:(id)sender;
-(void)tryScanForward:(id)sender;
-(IBAction)buttonReleasedOutside:(id)sender;
-(IBAction)buttonReleasedInside:(id)sender;
#end
And then in your .m file throw in some of this stuff:
#implementation YourClass
///in your .m file
#synthesize buttonModeAt;
///link this to your button's touch down
-(IBAction)buttonPushedDown:(id)sender {
buttonModeAt = MyButtonStalling;
[self performSelector:#selector(tryScanForward:) withObject:nil afterDelay:1.0];
}
-(void)tryScanForward:(id)sender {
if (buttonModeAt == MyButtonStalling) {
///the button was not released so let's start scanning
buttonModeAt = MyButtonScanning;
////your actual scanning code or a call to it can go here
[self startScanForward];
}
}
////you will link this to the button's touch up outside
-(IBAction)buttonReleasedOutside:(id)sender {
if (buttonModeAt == MyButtonScanning) {
///they released the button and stopped scanning forward
[self stopScanForward];
} else if (buttonModeAt == MyButtonStalling) {
///they released the button before the delay period finished
///but it was outside, so we do nothing
}
self.buttonModeAt = MyButtonIdle;
}
////you will link this to the button's touch up inside
-(IBAction)buttonReleasedInside:(id)sender {
if (buttonModeAt == MyButtonScanning) {
///they released the button and stopped scanning forward
[self stopScanForward];
} else if (buttonModeAt == MyButtonStalling) {
///they released the button before the delay period finished so we skip forward
[self skipForward];
}
self.buttonModeAt = MyButtonIdle;
}
After that just link the button's actions to what I've noted in the comments before the IBactions. I haven't tested this but it should work.
i'm not sure it will work but you can try
- (IBAction)dragInsideButton:(UIButton *)sender {
[sender removeTarget:self forSelector:#selector(clickButton:) forControlEvent:UIControlEventTouchDown];
}