Skip to content

Commit

Permalink
UIPanGestureRecognizer impl
Browse files Browse the repository at this point in the history
  • Loading branch information
XITRIX committed Dec 17, 2024
1 parent 8d104df commit 85f2733
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 0 deletions.
1 change: 1 addition & 0 deletions Submodules/UIKit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ add_library(UIKit
lib/UIImageView.cpp
lib/UIKey.cpp
lib/UILabel.cpp
lib/UIPanGestureRecognizer.cpp
lib/UIPress.cpp
lib/UIPressesEvent.cpp
lib/UIResponder.cpp
Expand Down
1 change: 1 addition & 0 deletions Submodules/UIKit/include/UIKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
#include <UILabel.h>
#include <UIViewController.h>
#include <UITapGestureRecognizer.h>
#include <UIPanGestureRecognizer.h>
29 changes: 29 additions & 0 deletions Submodules/UIKit/include/UIPanGestureRecognizer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include <UIGestureRecognizer.h>
#include <Timer.h>
#include <Geometry.h>

namespace NXKit {

class UIPanGestureRecognizer: public UIGestureRecognizer {
public:
void touchesBegan(std::vector<std::shared_ptr<UITouch>> touches, std::shared_ptr<UIEvent> event) override;
void touchesMoved(std::vector<std::shared_ptr<UITouch>> touches, std::shared_ptr<UIEvent> event) override;
void touchesEnded(std::vector<std::shared_ptr<UITouch>> touches, std::shared_ptr<UIEvent> event) override;

NXPoint translationInView(std::shared_ptr<UIView> view);
void setTranslation(NXPoint translation, std::shared_ptr<UIView> inView);

NXPoint velocityIn(std::shared_ptr<UIView> view);

private:
std::shared_ptr<UITouch> trackingTouch;
NXPoint initialTouchPoint;
Timer touchesMovedTimestamp;
Timer previousTouchesMovedTimestamp;

NXPoint velocityIn(std::shared_ptr<UIView> view, float timeDiffSeconds);
};

}
85 changes: 85 additions & 0 deletions Submodules/UIKit/lib/UIPanGestureRecognizer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#include <UIPanGestureRecognizer.h>
#include <UITouch.h>
#include <UIWindow.h>

namespace NXKit {

#define THRESHOLD 10

NXPoint UIPanGestureRecognizer::translationInView(std::shared_ptr<UIView> view) {
if (!trackingTouch) return NXPoint();

auto positionInTargetView = trackingTouch->locationIn(view);
NXPoint initialPositionInTargetView;
if (trackingTouch->window().expired()) initialPositionInTargetView = initialTouchPoint;
else { initialPositionInTargetView = view ? trackingTouch->window().lock()->convertToView(initialTouchPoint, view) : initialTouchPoint; }

return positionInTargetView - initialPositionInTargetView;
}

void UIPanGestureRecognizer::setTranslation(NXPoint translation, std::shared_ptr<UIView> inView) {
if (!trackingTouch) return;

auto positionInTargetView = trackingTouch->locationIn(nullptr);
initialTouchPoint = positionInTargetView - translation;
}

NXPoint UIPanGestureRecognizer::velocityIn(std::shared_ptr<UIView> view, float timeDiffSeconds) {
if (!trackingTouch || timeDiffSeconds == 0) return NXPoint();

NXPoint curPos = trackingTouch->locationIn(view);
NXPoint prevPos = trackingTouch->previousLocationIn(view);

return (curPos - prevPos) / (float)timeDiffSeconds;
}

NXPoint UIPanGestureRecognizer::velocityIn(std::shared_ptr<UIView> view) {
float timeDiffSeconds = touchesMovedTimestamp - previousTouchesMovedTimestamp;
timeDiffSeconds /= 100000.0f;
return velocityIn(view, timeDiffSeconds);
}

void UIPanGestureRecognizer::touchesBegan(std::vector<std::shared_ptr<UITouch>> touches, std::shared_ptr<UIEvent> event) {
UIGestureRecognizer::touchesBegan(touches, event);
if (!trackingTouch) {
trackingTouch = touches[0];
initialTouchPoint = trackingTouch->locationIn(nullptr);
touchesMovedTimestamp = trackingTouch->timestamp();
previousTouchesMovedTimestamp = trackingTouch->timestamp();
onStateChanged(UIGestureRecognizerState::possible);
}
}

void UIPanGestureRecognizer::touchesMoved(std::vector<std::shared_ptr<UITouch>> touches, std::shared_ptr<UIEvent> event) {
UIGestureRecognizer::touchesMoved(touches, event);
if (trackingTouch == touches[0]) {
if (state() == UIGestureRecognizerState::possible) {
NXPoint diff = initialTouchPoint - trackingTouch->locationIn(nullptr);
// printf("x %f, y %f\n", diff.x, diff.y);
if (abs(diff.x) >= THRESHOLD || abs(diff.y) >= THRESHOLD) {
// Reset initial touch point to remove "jiggle" effect after start of recognition
initialTouchPoint = trackingTouch->locationIn(nullptr);
touchesMovedTimestamp = trackingTouch->timestamp();
previousTouchesMovedTimestamp = trackingTouch->timestamp();
setState(UIGestureRecognizerState::began);
setState(UIGestureRecognizerState::changed);
}
} else if (state() == UIGestureRecognizerState::changed) {
previousTouchesMovedTimestamp = touchesMovedTimestamp;
touchesMovedTimestamp = trackingTouch->timestamp();
onStateChanged(UIGestureRecognizerState::changed);
}
}
}

void UIPanGestureRecognizer::touchesEnded(std::vector<std::shared_ptr<UITouch>> touches, std::shared_ptr<UIEvent> event) {
UIGestureRecognizer::touchesEnded(touches, event);
if (trackingTouch == touches[0]) {
previousTouchesMovedTimestamp = touchesMovedTimestamp;
touchesMovedTimestamp = trackingTouch->timestamp();
setState(UIGestureRecognizerState::ended);
trackingTouch = nullptr;
}
}

}
32 changes: 32 additions & 0 deletions app/Screens/TestViewController/TestViewController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,38 @@ void TestViewController::loadView() {
};
button->addGestureRecognizer(tapGesture);

auto dragMeView = new_shared<UILabel>();
dragMeView->setText("Drag me!");
dragMeView->setFontWeight(600);
dragMeView->setTextAlignment(NSTextAlignment::center);
dragMeView->setFrame({ 100, 400, 200, 200 });
dragMeView->layer()->setCornerRadius(12);
dragMeView->setBackgroundColor(UIColor::orange);
rootView->addSubview(dragMeView);

auto panGesture = new_shared<UIPanGestureRecognizer>();
panGesture->onStateChanged = [this, dragMeView, panGesture](UIGestureRecognizerState status) {
static NXPoint initial;
switch (status) {
case UIGestureRecognizerState::began: {
initial = dragMeView->frame().origin;
break;
}
case UIGestureRecognizerState::changed: {
auto translation = panGesture->translationInView(view());

auto frame = dragMeView->frame();
frame.origin.x = initial.x + translation.x;
frame.origin.y = initial.y + translation.y;
dragMeView->setFrame(frame);
break;
}
default:
break;
}
};
dragMeView->addGestureRecognizer(panGesture);

setView(rootView);
}

Expand Down

0 comments on commit 85f2733

Please sign in to comment.