iphone6s called wrong UIControlEvent method - ios

I wrote a simple demo to show my issue.The button need to be added two touch events:drag and touch.
UIButton * btn1 = [UIButton buttonWithType:UIButtonTypeCustom];
btn1.frame = CGRectMake(300, 100, 100, 100);
btn1.backgroundColor = [UIColor redColor];
[btn1 addTarget:self action:#selector(stretchBtnDragMoving:withEvent:) forControlEvents:UIControlEventTouchDragInside];
[btn1 addTarget:self action:#selector(stretchBtnDragEnded:withEvent:) forControlEvents:UIControlEventTouchUpInside|UIControlEventTouchUpOutside];
[self.view addSubview:btn1];
And then,
- (void)stretchBtnDragMoving:(UIControl *)control withEvent:(UIEvent *)event
{
NSLog(#"moving");
}
- (void)stretchBtnDragEnded:(UIControl *)control withEvent:(UIEvent *)event
{
NSLog(#"end or in");
}
When I touched the button in iPhone6s/6s plus like normal time,both of the methods be called.
But when I touched the button very light, only the second method be called.
When I used iPhone6/6 plus,iPad and other devices,however I touched the button,only the second method be called.

Related

Objective-C highlight UIButton when selected / unselected

I have a UIButton inside a UIView, when the UIButton is selected I would like have a background colour of dark gray...is this possible?
UIView *toolbar = [[UIView alloc]initWithFrame:CGRectMake(10, 50, 40, 160)];
[toolbar setBackgroundColor:[UIColor colorWithWhite: 0.70 alpha:0.5]];
toolbar.layer.cornerRadius = 5;
UIButton *penTool = [UIButton buttonWithType:UIButtonTypeCustom];
penTool.frame = CGRectMake(5, 0, 30, 30);
[penTool setImage:[UIImage imageNamed:#"pen-but" inBundle:currentBundle compatibleWithTraitCollection:nil] forState:UIControlStateNormal];
[penTool addTarget:self action:#selector(drawButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
penTool.autoresizingMask = UIViewAutoresizingNone;
penTool.exclusiveTouch = YES;
penTool.tag = 1;
[toolbar addSubview:penTool];
What if you can do this?
[button setBackgroundColor:[UIColor greenColor]
forState:UIControlStateSelected];
Let's give a great API for every state, not just selected, just like UIButton default API's ability to change image and title for every state.
BGButton.h
#import <UIKit/UIKit.h>
#interface BGButton : UIButton
- (void)setBackgroundColor:(UIColor *)backgroundColor
forState:(UIControlState)state;
#end
BGButton.m
#import "BGButton.h"
#implementation BGButton {
NSMutableDictionary *_stateBackgroundColor;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_stateBackgroundColor = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)setBackgroundColor:(UIColor *)backgroundColor {
[super setBackgroundColor:backgroundColor];
/*
* If user set button.backgroundColor we will set it to
* normal state's backgroundColor.
* Check if state is on normal state to prevent background being
* changed for incorrect state when updateBackgroundColor method is called.
*/
if (self.state == UIControlStateNormal) {
[self setBackgroundColor:backgroundColor forState:UIControlStateNormal];
}
}
- (void)setBackgroundColor:(UIColor *)backgroundColor
forState:(UIControlState)state {
NSNumber *key = [NSNumber numberWithInt:state];
[_stateBackgroundColor setObject:backgroundColor forKey:key];
}
/*
* state is synthesized from other flags. So we can't use KVO
* to listen for state changes.
*/
- (void)setSelected:(BOOL)selected {
[super setSelected:selected];
[self stateDidChange];
}
- (void)setEnabled:(BOOL)enabled {
[super setEnabled:enabled];
[self stateDidChange];
}
- (void)setHighlighted:(BOOL)highlighted {
[super setHighlighted:highlighted];
[self stateDidChange];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
[self stateDidChange];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
[self stateDidChange];
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
[self stateDidChange];
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesCancelled:touches withEvent:event];
[self stateDidChange];
}
- (void)stateDidChange {
[self updateBackgroundColor];
}
- (void)updateBackgroundColor {
NSNumber *key = [NSNumber numberWithInt:self.state];
self.backgroundColor = [_stateBackgroundColor objectForKey:key];
}
#end
You can use it like the default UIButton API
BGButton *button = [[BGButton alloc] init];
[button setBackgroundColor:[UIColor greenColor]
forState:UIControlStateSelected];
[button setBackgroundColor:[UIColor blueColor]
forState:UIControlStateHighlighted];
[button setBackgroundColor:[UIColor orangeColor]
forState:UIControlStateDisabled];
Even if you use
button.backgroundColor = [UIColor redColor];
You will stay safe, it will be translated into
[button setBackgroundColor:[UIColor redColor]
forState:UIControlStateNormal];
if you have this code
[self.view addSubview:toolbar];
then just implement your button selector
-(void)drawButtonTapped:(UIButton*)button{
if (button.selected) {
button.backgroundColor = [UIColor clearColor];
button.selected = NO;
}else{
button.backgroundColor = [UIColor darkGrayColor];
button.selected = YES;
}
}
I don't know why guys would go through such trouble when we have this functionality built-in inside UIButton. All you need to do is use UIButtonTypeSystem That's all.
[UIButton buttonWithType:UIButtonTypeSystem]
Seriously, there's nothing more to it. Have a look at it's behavior in the screenshots.
INTERFACE BUILDER
RUN TIME
Want to change color, set tintColor to color of your choice.
ADVANTAGES
Covers titles with dynamic lengths. Not applied on all button width.
When selected, title color is transparent, your background can be seen through, try to use an image as a background.
Let's hope you have at least iOS7 as deployment target. UIButtonTypeSystem was introduce with revised UI design guidelines of iOS7 and has been there for almost 3 years.
Good Luck!
I used a UIButton subclass here:
#import "CustomButton.h"
#interface CustomButton()
#property (nonatomic,strong) UIColor *originalColor;
#end
#implementation CustomButton
- (void)didMoveToSuperview
{
self.originalColor = self.superview.backgroundColor;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.superview.backgroundColor = [UIColor grayColor];
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
if ([self hitTest:location withEvent:nil]) {
self.superview.backgroundColor = [UIColor grayColor];
self.originalColor = self.superview.backgroundColor;
}
else
{
self.superview.backgroundColor = self.originalColor;
}
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.superview.backgroundColor = self.originalColor;
}
#end
If you subclass your button from this class, It should give you the desired effect. This also gives you the highlight effect. If you wish you can disable it by removing the line on touchesBegan.
Just try to Override the UIButton with the following Method...
- (void)setHighlighted:(BOOL)highlighted {
[super setHighlighted:highlighted];
if (highlighted) {
self.backgroundColor = [UIColor darkGray];
}
}
I think you'll be want to change the selectedImage for flexibility not the background.
Add another image (e.g. pen-but-selected) in the project. Add this 2nd line for setImage:
[penTool setImage:[UIImage imageNamed:#"pen-but-selected" inBundle:currentBundle compatibleWithTraitCollection:nil] forState:UIControlStateSelected];
- (void)drawButtonTapped:(UIButton *)button {
button.selected = !button.selected;
}
If you still want to change background color. #jamil's answer would work. Make sure the buttonImage has transparent part so you can see the buttonBackground through the buttonImage.
Try using a boolean, or some other reference to the selection state of the button. You could also make use of a 'highlightColour' as well as the 'selectedColour' if you wanted closer control (should probably do this for better UX).
bool buttonIsSelected = false;
UIColor * selectedColour = [UIColor redColor];
UIColor * defaultColour = [UIColor blueColor];
UIButton * button = [UIButton new];
button.frame = CGRectMake(0,0,100,100);
button.backgroundColor = [UIColor redColor];
[self.view addSubview:button];
[button addTarget:self action:#selector(buttonTouchUp:) forControlEvents:UIControlEventTouchUpInside];
[button addTarget:self action:#selector(buttonTouchCancel:) forControlEvents:UIControlEventTouchCancel];
[button addTarget:self action:#selector(buttonTouchDown:) forControlEvents:UIControlEventTouchDown];
-(void)buttonTouchUp:(UIButton *)button {
if (buttonIsSelected){
buttonIsSelected = false;
button.backgroundColor = defaultColour;
} else {
buttonIsSelected = true;
button.backgroundColor = selectedColour;
}
}
-(void)buttonTouchCancel:(UIButton *)button {
button.backgroundColor = defaultColour;
if (buttonIsSelected){
button.backgroundColor = selectedColour;
}
}
-(void)buttonTouchDown:(UIButton *)button {
button.backgroundColor = selectedColour;
}
-(void)OnSelect:(UIButton*)button{
if (button.selected) {
button.backgroundColor = [UIColor blue];
button.selected = NO;
}else{
button.backgroundColor = [UIColor darkGrayColor];
button.selected = YES;
}
}
use the above this will work..
-(void)buttonTapped:(UIButton*)button{
button.selected =! button.selected;
if (button.selected)
button.backgroundColor = [UIColor grayColor];
else
button.backgroundColor = [UIColor clearColor];
}

touchesBegan and touchesEnded not called on a UIButton

When I touch a UIButton, the touchesBegan, touchesMoved and touchesEnded methods are not called. I want to perform an event when a continuous touch happens and cancel the event when the touch ends.
You can track UIButton touch start and touch end by using UIButton control events.
- (void)viewDidLoad {
[super viewDidLoad];
[self.button addTarget:self action:#selector(touchStarted:) forControlEvents:UIControlEventTouchDown];
[self.button addTarget:self action:#selector(touchEnded:) forControlEvents:UIControlEventTouchUpInside];
[self.button addTarget:self action:#selector(touchEnded:) forControlEvents:UIControlEventTouchUpOutside];
}
- (void)touchStarted:(id)sender {
NSLog(#"Touch started");
}
- (void)touchEnded:(id)sender {
NSLog(#"Touch ended");
}

UIButtons Won't disspear after scene transition

Hey so I have created two buttons that when pressed transition the current scene to either the next scene or the main menu and they work but neither button disappears after it has been pressed. They both carry over onto the next scene which I don't want. I've tried hiding the buttons and removing them from the superView but neither worked. Heres what the code looks like for what happens when it is pressed.
-(IBAction)buttonPressed:(UIButton *)sender
{
if ([sender isEqual:self.continueButton]) {
SKTransition* reveal = [SKTransition doorsCloseVerticalWithDuration:0.5];
SKScene* transition2Scene = [[Transition2Scene alloc] initWithSize:self.size];
[self.view presentScene:transition2Scene transition: reveal];
[self.continueButton removeFromSuperview];
self.continueButton.hidden = YES;
self.continueButton.enabled = NO;
}
else {
SKTransition* doors = [SKTransition doorsCloseVerticalWithDuration:0.5];
SKScene* spriteMyScene = [[SpriteMyScene alloc] initWithSize:self.size];
[self.view presentScene:spriteMyScene transition: doors];
self.menuButton.hidden = YES;
self.menuButton.enabled = NO;
[self.menuButton removeFromSuperview];
}
}
And heres what the coding of the buttons themselves looks like.
self.continueButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.continueButton.frame = CGRectMake(self.frame.size.width/3, self.frame.size.height * 0.5, 120, 70);
[self.continueButton setTitle:#"Continue" forState:UIControlStateNormal];
[self.continueButton addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.continueButton];
self.menuButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.menuButton.frame = CGRectMake(self.frame.size.width/3, self.frame.size.height * 0.6, 120, 70);
[self.menuButton setTitle:#"Main Menu" forState:UIControlStateNormal];
[self.menuButton addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.menuButton];
I've looked around for answers and tried some things but they didn't work cause the issue I'm having isn't quite the same so any help would be greatly appreciated thanks!
The SKScene and its contents are remove from the view when transitioning to a new scene. Views, such as your buttons, are not removed. You will need to manually remove them. Here's an example...
- (IBAction) buttonPressed:(UIButton *)sender
{
[self.continueButton removeFromSuperview];
[self.menuButton removeFromSuperview];
// Find and remove all UIButtons in your view
for (UIView *view in self.view.subviews) {
if ([view isKindOfClass:[UIButton class]]) {
NSLog(#"%#", view);
[view removeFromSuperview];
}
}
// Verify that the UIButtons were removed
for (UIView *view in self.view.subviews) {
if ([view isKindOfClass:[UIButton class]]) {
NSLog(#"this shouldn't happen: %#", view);
}
}
// The rest of your code
Alternatively, you can create buttons using SKSpriteNode and add them to your scene. Here's an example...
Setting up buttons in SKScene

How to make UIButton dragable but don't trigger click event

I usually use this method to implement the UIButton movable;
[button addTarget:self action:#selector(dragMoving:withEvent:) forControlEvents:UIControlEventTouchDragInside];
But it will trigger the touchUpInside event at same time, and I need touchUpInside event to do some other things.
So does anyone know how to avoid this?
Thanks a lot;
use these code below to solve it;
[button addTarget:self action:#selector(touchDown:withEvent:) forControlEvents:UIControlEventTouchDown];
[button addTarget:self action:#selector(touchDragInside:withEvent:) forControlEvents:UIControlEventTouchDragInside];
[button addTarget:self action:#selector(touchUpInside:withEvent:) forControlEvents:UIControlEventTouchUpInside];
- (void) touchUpInside :(UIControl*)c withEvent:ev{
NSLog(#"touch Up inside");
if (count) {
NSLog(#"here I can do something about clicking event");
}
}
- (void) touchDown:(UIControl*)c withEvent:ev{
NSLog(#"touch Down");
count = YES;
}
-(void) touchDragInside:(UIControl*)c withEvent:ev{
NSLog(#"touch drag inside");
c.center = [[[ev allTouches] anyObject] locationInView:self.view];
count = NO;
}
Actually the best way to accomplish this is to use UIPanGestureRecognizer and add it to the button. It handles the dragging very well and you also can tap on it without needing to do anything else.

Swipe between UIButtons

Say I have 2 UIButtons next to each other and both of them will turn from white to black when I put my finger on them.
That obviously works fine, but if I put my finger on button 1 it turns black and then when I move my finger over the button 2 without lifting my finger, button 2 doesn't turn black, button 1 is still black.
So how can I "swipe" over one button and then over another one and change the highlighted button from the first one to the second one.
In your viewcontroller override the touchesMoved event. This will tell you when touches occur. The problem is that your buttons will have to have userInteractionEnabled set to NO so that they don't gobble the touch event. This will be ok if you're trying to do a custom slider or something where you don't need the actual button events.
Then in the touchesMoved you can loop through your buttons and see which button is pressed. Here is some code stolen from an excellent answer at Highlight the button when drag enter
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *t in touches) {
CGPoint touchPoint = [t locationInView:self.view];
CGPoint testPoint = [self.view convertPoint:touchPoint toView:aButton];
if ([aButton pointInside:testPoint withEvent:event]) {
//Do something
}
//rest of code
[self.button1 addTarget:self
action:#selector(dragEnter:)
forControlEvents:UIControlEventTouchDragEnter];
[self.button2 addTarget:self
action:#selector(dragEnter:)
forControlEvents:UIControlEventTouchDragEnter];
[self.button1 addTarget:self
action:#selector(dragExit:)
forControlEvents:UIControlEventTouchDragExit];
[self.button2 addTarget:self
action:#selector(dragExit:)
forControlEvents:UIControlEventTouchDragExit];
- (void)dragEnter:(id)sender
{
UIButton *button = (UIButton *)sender;
button.highlighted = YES;
}
- (void)dragExit:(id)sender
{
UIButton *button = (UIButton *)sender;
button.highlighted = NO;
}

Resources