Просмотр исходного кода

Allow scrubbing between selected views

Instead of a singular swipe gesture to navigate between views in the view hierarchy at the tap point, we can now pan or drag along that same area to "srub" the hierarchy.
Tanner Bennett лет назад: 5
Родитель
Сommit
9282c61183
1 измененных файлов с 59 добавлено и 15 удалено
  1. 59 15
      Classes/ExplorerInterface/FLEXExplorerViewController.m

+ 59 - 15
Classes/ExplorerInterface/FLEXExplorerViewController.m

@@ -45,6 +45,9 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
 /// Only valid while a toolbar drag pan gesture is in progress.
 @property (nonatomic) CGRect toolbarFrameBeforeDragging;
 
+/// Only valid while a selected view pan gesture is in progress.
+@property (nonatomic) CGFloat selectedViewLastPanX;
+
 /// Borders of all the visible views in the hierarchy at the selection point.
 /// The keys are NSValues with the corresponding view (nonretained).
 @property (nonatomic) NSDictionary<NSValue *, UIView *> *outlineViewsForVisibleViews;
@@ -58,6 +61,9 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
 /// A colored transparent overlay to indicate that the view is selected.
 @property (nonatomic) UIView *selectedViewOverlay;
 
+/// Used to actuate changes in view selection on iOS 10+
+@property (nonatomic, readonly) UISelectionFeedbackGenerator *selectionFBG;
+
 /// self.view.window as a \c FLEXWindow
 @property (nonatomic, readonly) FLEXWindow *window;
 
@@ -118,6 +124,11 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
     self.movePanGR = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleMovePan:)];
     self.movePanGR.enabled = self.currentMode == FLEXExplorerModeMove;
     [self.view addGestureRecognizer:self.movePanGR];
+    
+    // Feedback
+    if (@available(iOS 10.0, *)) {
+        _selectionFBG = [UISelectionFeedbackGenerator new];
+    }
 }
 
 - (void)viewWillAppear:(BOOL)animated {
@@ -450,16 +461,16 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
     ];
     [toolbar.selectedViewDescriptionContainer addGestureRecognizer:self.detailsTapGR];
     // Swipe gestures for selecting deeper / higher views at a point
-    UISwipeGestureRecognizer *leftSwipe = [[UISwipeGestureRecognizer alloc]
-        initWithTarget:self action:@selector(handleChangeViewAtPointGesture:)
-    ];
-    UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc]
+    UIPanGestureRecognizer *leftSwipe = [[UIPanGestureRecognizer alloc]
         initWithTarget:self action:@selector(handleChangeViewAtPointGesture:)
     ];
-    leftSwipe.direction = UISwipeGestureRecognizerDirectionLeft;
-    rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
+//    UIPanGestureRecognizer *rightSwipe = [[UIPanGestureRecognizer alloc]
+//        initWithTarget:self action:@selector(handleChangeViewAtPointGesture:)
+//    ];
+//    leftSwipe.direction = UISwipeGestureRecognizerDirectionLeft;
+//    rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
     [toolbar.selectedViewDescriptionContainer addGestureRecognizer:leftSwipe];
-    [toolbar.selectedViewDescriptionContainer addGestureRecognizer:rightSwipe];
+//    [toolbar.selectedViewDescriptionContainer addGestureRecognizer:rightSwipe];
     
     // Long press gesture to present tabs manager
     [toolbar.globalsItem addGestureRecognizer:[[UILongPressGestureRecognizer alloc]
@@ -598,22 +609,55 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
     }
 }
 
-- (void)handleChangeViewAtPointGesture:(UISwipeGestureRecognizer *)sender {
+- (void)handleChangeViewAtPointGesture:(UIPanGestureRecognizer *)sender {
     NSInteger max = self.viewsAtTapPoint.count - 1;
     NSInteger currentIdx = [self.viewsAtTapPoint indexOfObject:self.selectedView];
-    switch (sender.direction) {
-        case UISwipeGestureRecognizerDirectionLeft:
-            self.selectedView = self.viewsAtTapPoint[MIN(max, currentIdx + 1)];
-            break;
-        case UISwipeGestureRecognizerDirectionRight:
-            self.selectedView = self.viewsAtTapPoint[MAX(0, currentIdx - 1)];
+    CGFloat locationX = [sender locationInView:self.view].x;
+    
+    // Track the pan gesture: every N points we move along the X axis,
+    // actuate some haptic feedback and move up or down the hierarchy.
+    // We only store the "last" location when we've met the threshold.
+    // We only change the view and actuate feedback if the view selection
+    // changes; that is, as long as we don't go outside or under the array.
+    switch (sender.state) {
+        case UIGestureRecognizerStateBegan: {
+            self.selectedViewLastPanX = locationX;
             break;
+        }
+        case UIGestureRecognizerStateChanged: {
+            static CGFloat kNextLevelThreshold = 20.f;
+            CGFloat lastX = self.selectedViewLastPanX;
+            NSInteger newSelection = currentIdx;
+            
+            // Left, go down the hierarchy
+            if (locationX < lastX && (lastX - locationX) >= kNextLevelThreshold) {
+                // Choose a new view index up to the max index
+                newSelection = MIN(max, currentIdx + 1);
+                self.selectedViewLastPanX = locationX;
+            }
+            // Right, go up the hierarchy
+            else if (lastX < locationX && (locationX - lastX) >= kNextLevelThreshold) {
+                // Choose a new view index down to the min index
+                newSelection = MAX(0, currentIdx - 1);
+                self.selectedViewLastPanX = locationX;
+            }
+            
+            if (currentIdx != newSelection) {
+                self.selectedView = self.viewsAtTapPoint[newSelection];
+                [self actuateSelectionChangedFeedback];
+            }
             
-        default:
             break;
+        }
+            
+        default: break;
     }
 }
 
+- (void)actuateSelectionChangedFeedback {
+    [self.selectionFBG selectionChanged];
+}
+
 - (void)updateOutlineViewsForSelectionPoint:(CGPoint)selectionPointInWindow {
     [self removeAndClearOutlineViews];