Abdul Samad Abdul Samad - 17 days ago 6
iOS Question

Is it possible to implement 3d touch on UIButton?

I am new to iOS development, but I need to implement 3d touch on UIButton, when user apply force on a button shortcut menu would pop out, even if someone could just provide me the sample code in ObjectiveC for 3d touch would be appreciated. Thanks in Advance.

Answer

Yes, I've a demonstration of how to detect 3d touch on a UIButton in a sample application on github below. For the menu popup portion I will leave that to you to implement but this will get you the force/3d touch piece.

https://github.com/foggzilla/DFContinuousForceTouchGestureRecognizer

The way I'm doing this is to use a DFContinuousForceTouchGestureRecognizer that I have made available in the sample project.

The DFContinuousForceTouchGestureRecognizer provides continuous updates about the pressure changes so you can do nice things like transform the button as the user varies their pressure on it, as opposed to a single event. If you just want a single event you can ignore eveything in the DFContinuousForceTouchDelegate except the - (void) forceTouchRecognized callback.

You can download this and run the sample app on a device that supports force press to see how it feels.

In your UIViewController implement:

- (void) viewDidLoad {
    [super viewDidLoad];
    _forceTouchRecognizer = [[DFContinuousForceTouchGestureRecognizer alloc] init];
    _forceTouchRecognizer.forceTouchDelegate = self;

    [self.button addGestureRecognizer:_forceTouchRecognizer];
}

implement the delegate protocol for force touch:

#pragma DFContinuousForceTouchDelegate

- (void) forceTouchRecognized:(DFContinuousForceTouchGestureRecognizer*)recognizer {
    self.button.transform = CGAffineTransformIdentity;
    [self.button setNeedsDisplay];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [[[UIAlertView alloc] initWithTitle:@"Force Touch Button" message:@"YEAH!!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
    });
}
- (void) forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer*)recognizer didStartWithForce:(CGFloat)force maxForce:(CGFloat)maxForce {
    CGFloat transformDelta = 1.0f + ((force/maxForce) / 3.0f);
    self.button.transform = CGAffineTransformMakeScale(transformDelta, transformDelta);
    [self.button setNeedsDisplay];
}

- (void) forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer*)recognizer didMoveWithForce:(CGFloat)force maxForce:(CGFloat)maxForce {
    CGFloat transformDelta = 1.0f + ((force/maxForce) / 3.0f);
    self.button.transform = CGAffineTransformMakeScale(transformDelta, transformDelta);
    [self.button setNeedsDisplay];
}

- (void) forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer*)recognizer didCancelWithForce:(CGFloat)force maxForce:(CGFloat)maxForce  {
    self.button.transform = CGAffineTransformIdentity;
    [self.button setNeedsDisplay];
}

- (void) forceTouchRecognizer:(DFContinuousForceTouchGestureRecognizer*)recognizer didEndWithForce:(CGFloat)force maxForce:(CGFloat)maxForce {
    self.button.transform = CGAffineTransformIdentity;
    [self.button setNeedsDisplay];
}

- (void) forceTouchDidTimeout:(DFContinuousForceTouchGestureRecognizer*)recognizer {
    self.button.transform = CGAffineTransformIdentity;
    [self.button setNeedsDisplay];
}

Note that this will only be useful on a device that supports force touch.

Also you should not add the DFContinuousForceTouchGestureRecognizer to a view if are you running on iOS8 or under since it uses the new force property on UITouch only available in iOS9.

If you add this on iOS8 it will crash, so conditionally add this recognizer based on what iOS version you are running on if you are supporting versions older than iOS9.

Comments