在 Objective-C 中从 UIScreenEdgePanGestureRecognizer 切换到 UISegmentedControl

Switching from UIScreenEdgePanGestureRecognizer to UISegmentedControl in Objective-C

我是一名新 objective-c 开发人员。正在开发的应用程序的目的是在 3 个图表之间切换,每个图表显示科学数据。当用户在这些图表上拖动手指时,会显示该点的数据。目前,为了在这三个图形之间切换,使用了 UIScreenEdgePanGestureRecognizer。但是,由于苹果在最近的更新中取消了这个功能,所以我想使用分段控件在三个图形之间切换。我已经能够让分段控件出现,但是,我无法让它们真正让图表切换。我在下面附上了(原始)viewcontroller.m 的相关部分。我该怎么做?谢谢

作为参考,三张图的名称分别是ts、ph和pv。

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    /*
    // Show/hide nav bar
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                          action:@selector(doubleTap)];
    
    [tap setNumberOfTapsRequired:2];
    [self.view addGestureRecognizer:tap];
    */
    
    touchHasRegistered = NO;
    allowQualityScrubbing = NO;
    shouldFineTune = 0;
    hasFineTuned = NO;
    
    [[UIApplication sharedApplication] setStatusBarHidden:YES];
    [self.navigationController setNavigationBarHidden:YES];
    
    [self.containerView addSubview:self.chartView];
    
    [self.view insertSubview:self.secondContainerView
                aboveSubview:self.containerView];
    
    [self.view insertSubview:self.infoView
                aboveSubview:self.secondContainerView];
    
    [self.containerView bringSubviewToFront:self.infoButton];
    
    [self.view setBackgroundColor:[UIColor whiteColor]];
    
    [self.chartView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.containerView);
    }];
    
    [self.infoView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.containerView);
    }];
    
    if (self.secondContainerView.superview != nil && self.chartView.image != nil) {
        [self.secondContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(self.containerView).with.offset(20.0);
            make.top.equalTo(self.containerView).with.offset(20.0);
            make.height.equalTo([NSNumber numberWithFloat:self.secondContainerView.frame.size.height]);
            make.width.equalTo([NSNumber numberWithFloat:self.secondContainerView.frame.size.width]);
        }];
    }
    
    [self.secondContainerView addSubview:self.displayView];
    
    [self chooseNewFileWithChartType:self.chartView.chart.substanceType valueType:@"ts"];
    
    UIScreenEdgePanGestureRecognizer *rightRecog = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self
                                                                                                     action:@selector(resetChart:)];
    [rightRecog setEdges:UIRectEdgeRight];
    [rightRecog setCancelsTouchesInView:YES];
    
    [self.chartView addGestureRecognizer:rightRecog];
    
    UIScreenEdgePanGestureRecognizer *leftRecog = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self
                                                                                                    action:@selector(resetChart:)];
    
    [leftRecog setEdges:UIRectEdgeLeft];
    [leftRecog setCancelsTouchesInView:YES];
    
    [self.chartView addGestureRecognizer:leftRecog];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    [self.view addSubview:self.popupView];
    [self.popupView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.equalTo(@(self.popupView.frame.size.height));
        make.width.equalTo(@(self.popupView.frame.size.width));
        make.center.equalTo(self.view);
    }];
    /*
    // Add Adjuster Views
    NSSet *tags = [self tagsForAdjusterViews];
    
    CGFloat height = self.displayView.containerViewHeight/self.displayView.numberOfRows;
    
    for (id tag in tags) {
        RUAAdjusterView *adjusterView = [[RUAAdjusterView alloc] initWithFrame:CGRectZero
                                                                           tag:[(NSNumber *)tag integerValue]];
        adjusterView.delegate = self;
        [adjusterView setBackgroundColor:[UIColor clearColor]];
        [self.secondContainerView addSubview:adjusterView];
        [self.secondContainerView bringSubviewToFront:adjusterView];
        
        [adjusterView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.equalTo(self.secondContainerView);
            make.right.equalTo(self.secondContainerView);
            make.top.equalTo([NSNumber numberWithFloat:(height*([(NSNumber *)tag floatValue] - 1) + self.displayView.containerViewOriginY + 2.0f)]);
            make.height.equalTo([NSNumber numberWithFloat:height - 4.0f]);
        }];
    }
     */
}

- (NSSet *)tagsForAdjusterViews
{
    return [NSSet setWithObjects:@1, @2, @6, @7, nil];
}

- (BOOL)prefersStatusBarHidden
{
    return YES;
}

#pragma mark - Lazy Init

- (LocationIndicatorImageView *)chartView
{
    if (!_chartView) {
        _chartView = (LocationIndicatorImageView *)[[LocationIndicatorImageView alloc] initWithFrame:self.containerView.frame
                                                                                               image:[UIImage imageNamed:@"Water_ts_chart.png"]
                                                                                              sender:self];
        
        [_chartView setChart:[RUChart chartWithChartType:@"ts"]];
    }
    return _chartView;
}

-(UIView *)displayView
{
    if (!_displayView) {
        _displayView = [[DisplayView alloc] initWithFrame:self.secondContainerView.frame];
        [_displayView setDataSource:self];
    }
    return _displayView;
}

-(UIView *)secondContainerView
{
    if (!_secondContainerView) {
        CGFloat height = 343.0f;
        CGFloat width = 225.0f;
        _secondContainerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)];
    }
    return _secondContainerView;
}

-(UIImageView *)infoView
{
    if (!_infoView) {
        _infoView = [[UIImageView alloc] initWithFrame:CGRectZero];
        [_infoView setImage:[UIImage imageNamed:@"Legend.png"]];
        [_infoView setHidden:YES];
        [_infoView setUserInteractionEnabled:NO];
        [_infoView setBackgroundColor:[UIColor whiteColor]];
        
        UIView *container = [[UIView alloc] initWithFrame:CGRectMake(30, 30, 310, 310)];
        UITapGestureRecognizer *ytTap = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                action:@selector(showYoutubeVideo)];
        [ytTap setNumberOfTapsRequired:1];
        [container setUserInteractionEnabled:YES];
        [container addGestureRecognizer:ytTap];
        
        [_infoView addSubview:container];
        
        UIImageView *youtube = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
        [youtube setImage:[UIImage imageNamed:@"youtube.png"]];
        
        UITextView *textView1 = [[UITextView alloc] initWithFrame:CGRectMake(youtube.frame.origin.x + youtube.frame.size.width,
                                                                             youtube.frame.origin.y,
                                                                             250,
                                                                             youtube.frame.size.height/2.0)];
        UITextView *textView2 = [[UITextView alloc] initWithFrame:CGRectMake(youtube.frame.origin.x + youtube.frame.size.width,
                                                                             youtube.frame.origin.y + youtube.frame.size.height/2.0,
                                                                             250,
                                                                             youtube.frame.size.height/2.0)];
        UIFont *font = [UIFont fontWithName:@"HelveticaNeue-Light" size:16.0];
        
        [textView1 setText:@"Learn about Thermodynamic"];
        [textView1 setFont:font];
        [textView1 setTextContainerInset:UIEdgeInsetsMake(11.0, 4.0, 4.0, 0.0)];
        [textView1 setUserInteractionEnabled:NO];
        
        [textView2 setText:@"Properties of Water"];
        [textView2 setFont:font];
        [textView2 setTextContainerInset:UIEdgeInsetsMake(0.0, 4.0, 0.0, 0.0)];
        [textView2 setUserInteractionEnabled:NO];
        
        [container addSubview:youtube];
        [container addSubview:textView1];
        [container addSubview:textView2];
        
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                              action:@selector(dismissInfo)];
        [tap setNumberOfTapsRequired:1];
        
        [_infoView addGestureRecognizer:tap];
    }
    return _infoView;
}

- (void)showYoutubeVideo
{
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://www.youtube.com/watch?v=rJR-6OEw09k"]
                                       options:@{}
                             completionHandler:nil];
}

- (H2O_Wagner_Pruss *)wagPruss
{
    if (!_wagPruss) {
        _wagPruss = [[H2O_Wagner_Pruss alloc] initEOS];
    }
    return _wagPruss;
}

- (NSArray *)superheatedValues
{
    if (!_superheatedValues) {
        _superheatedValues = [[NSArray alloc] init];
    }
    return _superheatedValues;
}

- (NSArray *)superheatedKeys
{
    if (!_superheatedKeys) {
        _superheatedKeys = [[NSArray alloc] init];
    }
    return _superheatedKeys;
}

- (NSArray *)chartValueTypes
{
    if (!_chartValueTypes) {
        _chartValueTypes = [NSArray arrayWithObjects:@"ts",@"ph",@"pv", nil];
    }
    return _chartValueTypes;
}

- (RUAPopupView *)popupView
{
    if (!_popupView) {
        _popupView = [[RUAPopupView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 200.0f, 160.0f) text:@"t-s"];
    }
    return _popupView;
}

- (RUASpaceController *)spaceController
{
    if (!_spaceController) {
        _spaceController = [[RUASpaceController alloc] init];
        // NOTE: Seems like (10/8.0 and 10/9.0) and 20/30.0 felt best of ones I tried. Could use some refining.
        _spaceController.numPoints = 10;
        _spaceController.maxDiff = 7.0;
    }
    
    return _spaceController;
}

#pragma mark - Gesture Selectors

- (IBAction)displayInfo:(id)sender {
    [self.infoView setHidden:NO];
    [self.infoView setUserInteractionEnabled:YES];
}

-(void)dismissInfo
{
    [self.infoView setHidden:YES];
    [self.infoView setUserInteractionEnabled:NO];
}

-(void)doubleTap
{
    [self.popupView showHideAnimated:YES];
    /*
    if (self.navigationController.isNavigationBarHidden) {
        [self.navigationController setNavigationBarHidden:NO animated:YES];
        [[UIApplication sharedApplication] setStatusBarHidden:NO];
    } else {    
        [self.navigationController setNavigationBarHidden:YES animated:YES];
        [[UIApplication sharedApplication] setStatusBarHidden:YES];
    }
     */
}

- (void)resetChart:(UIScreenEdgePanGestureRecognizer *)recog
{
    [self.popupView.layer removeAllAnimations];
    if (recog.state == UIGestureRecognizerStateEnded) {
        NSInteger index = [self.chartValueTypes indexOfObject:self.chartView.chart.valueType];
        NSLog(@"%@, %@", self.chartValueTypes[((index+1)+3)%3], self.chartValueTypes[((index-1)+3)%3]);
        
        NSString *type;
        
        if (recog.edges == UIRectEdgeRight) {
            type = self.chartValueTypes[((index+1)+3)%3];
        } else if (recog.edges == UIRectEdgeLeft) {
            type = self.chartValueTypes[((index-1)+3)%3];
        }
        
        NSString *letter1 = [type substringToIndex:1];
        NSString *letter2 = [type substringFromIndex:1];
        
        NSString *displayName = [NSString stringWithFormat:@"%@-%@",letter1.uppercaseString,letter2];
        self.popupView.text = displayName;
        
        [self.chartView resetImage:[UIImage imageNamed:[NSString stringWithFormat:@"Water_%@_chart.png",type]]];
        self.chartView.chart = [RUChart chartWithChartType:type];
        [self inspectInfoButtonWithChartValueType:type];
        [self chooseNewFileWithChartType:self.chartView.chart.substanceType valueType:type];
        
        [self.secondContainerView mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.top.equalTo(self.containerView).with.offset(20.0);
            make.height.equalTo([NSNumber numberWithFloat:self.secondContainerView.frame.size.height]);
            make.width.equalTo([NSNumber numberWithFloat:self.secondContainerView.frame.size.width]);
        }];
        
        if (self.chartView.chart.displayPosition == RUChartDisplayPositionLeft) {
            [self.secondContainerView mas_updateConstraints:^(MASConstraintMaker *make) {
                make.left.equalTo(self.containerView).with.offset(20.0);
            }];
        } else if (self.chartView.chart.displayPosition == RUChartDisplayPositionRight) {
            [self.secondContainerView mas_updateConstraints:^(MASConstraintMaker *make) {
                make.right.equalTo(self.containerView).with.offset(-20.0);
            }];
        }
        
        [self.popupView showHideAnimated:YES];
        
        if (touchHasRegistered) {
            if ([self.chartView.chart.valueType isEqualToString:@"ph"]) {
                if ([self.chartView pointIsWithinBoundsForPrimaryAxisValue:currentEnthalpy secondaryAxisValue:currentPressure]) {
                    [self.chartView moveMarkerToPrimaryAxisValue:currentEnthalpy
                                              secondaryAxisValue:currentPressure];
                } else {
                    [self.chartView removeMarker];
                }
            } else if ([self.chartView.chart.valueType isEqualToString:@"pv"]) {
                if ([self.chartView pointIsWithinBoundsForPrimaryAxisValue:currentSpecVolume secondaryAxisValue:currentPressure]) {
                    [self.chartView moveMarkerToPrimaryAxisValue:currentSpecVolume
                                              secondaryAxisValue:currentPressure];
                } else {
                    [self.chartView removeMarker];
                }
            } else if ([self.chartView.chart.valueType isEqualToString:@"ts"]) {
                if ([self.chartView pointIsWithinBoundsForPrimaryAxisValue:currentEntropy secondaryAxisValue:currentTemp]) {
                    [self.chartView moveMarkerToPrimaryAxisValue:currentEntropy
                                              secondaryAxisValue:currentTemp];
                } else {
                    [self.chartView removeMarker];
                }
            } else {
                touchHasRegistered = NO;
                [self.chartView removeMarker];
            }
        }
    }
}

UISegmentedControl 看起来要设置很多,但实际上不是。

以下代码只是显示了对段内颜色和标签位置的更详细控制。如果其他地方没有进一步使用,则不需要 属性 来保存 UISegmentedControl *。在 -initWithFrame:-viewDidLoad.

中调用一次
- (void)setupSegmentCtrl {
    
    UISegmentedControl *segmentedCtrl = [[UISegmentedControl alloc] initWithItems:@[@"A",@"B",@"C"]];
    segmentedCtrl.momentary = YES;
    NSUInteger segItems = segmentedCtrl.numberOfSegments;
    segmentedCtrl.frame = CGRectMake(0, 0, 60*segItems, 40);
    
    // sorry - funny color scheme used to demonstrate
    segmentedCtrl.tintColor = UIColor.orangeColor;
    //segmentedCtrl.backgroundColor = UIColor.clearColor;
    UIColor *dark = [UIColor colorWithWhite:0.5 alpha:0.5];
    [segmentedCtrl setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:dark,NSForegroundColorAttributeName, [UIFont fontWithName:@"HelveticaNeue-Light" size:16.0],NSFontAttributeName, nil] forState:UIControlStateNormal];
    [segmentedCtrl setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:UIColor.redColor, NSForegroundColorAttributeName, nil] forState:UIControlStateSelected];
    [segmentedCtrl setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:UIColor.greenColor, NSForegroundColorAttributeName, nil] forState:UIControlStateHighlighted];
    
    // you can move the segments labels about some pixels with the following..
    //[segmentedCtrl setContentPositionAdjustment:UIOffsetMake(-1, -2) forSegmentType:UISegmentedControlSegmentAny barMetrics:UIBarMetricsDefault];
    
    // manually set an active index, .. as default
    [segmentedCtrl setSelectedSegmentIndex:0];
    
    [self.view addSubview:segmentedCtrl];

    // next lines work for all UIControls, setting a target and action manually. 
    // there are a lot UIControlEvent to choose/combine from available
    [segmentedCtrl addTarget:self action:@selector(segmentSelectedAction:) forControlEvents:UIControlEventValueChanged];
    
}

根据定义,您需要一种在您触摸细分时采取行动的方法。

-(void)segmentSelectedAction:(UISegmentedControl *)seg {
    NSLog(@"selectedSegmentIndex=%d", seg.selectedSegmentIndex);
    // what ever you gonna do with the seg.selectedSegmentIndex
}

在使用 UISegmentedControl 时可能很高兴知道,当进入暗模式时,它有不同的背景配色方案。所以切换并测试它的外观。

如果由于设备旋转而必须更改布局,则必须将 UISegmentedControl *segmentCtrl 公开为 属性 或 class 变量并在 [=18= 中更改框架等] 满足您的需求。

关于 UIViews 和 UIGestureRecognizers 的最后一句话。有时编写自己的 UIView subclass 并分配它会更实用。然后你可以在你的 subclass 中使用以下方法直接捕捉触摸。

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];
    for (UITouch *touch in touches) {
        NSLog(@"touchesBegan= %@",touch.description);
    }
}
// and the other possible..
-(void)touchesMoved:withEvent:
-(void)touchesEnded:withEvent:
-(void)touchesCancelled:withEvent: