首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UISwitch有时不会发送UIControlEvents

UISwitch有时不会发送UIControlEvents
EN

Stack Overflow用户
提问于 2012-08-22 19:05:52
回答 4查看 2.4K关注 0票数 1

我有一个模型对象,它包含一个布尔标志。我想使用UISwitch来显示标志的值。可以通过两种方式更改该值:

  1. 首先由用户通过切换开关。我为此注册了UIControlEventTouchUpInside。我也尝试了UIControlEventValueChanged -它有完全相同的效果。
  2. 第二,由一些外部状态的变化。我使用计时器检查状态变化,并相应地设置开关的on属性。

但是,在timer方法中设置开关的值具有这样的效果:即使用户已经触摸了开关,有时也不会触发touchUpInside操作。

因此,我面临以下问题:当状态外部更改时,如果在计时器中设置开关状态,则会从用户那里释放一些状态更改。如果我不使用计时器,就会从用户那里得到所有的状态更改。然而,我错过了所有外部状态的改变。

现在我的想法已经用完了。如何实现我想要的,在模型中获得两种类型的状态更改,并将它们正确地反映在开关视图中?

下面是一个很小的例子,说明了这个问题。我用一个简单的布尔标志替换了模型对象,在计时器中我根本不改变标志,我只调用setOn:动画:。我数一数动作方法的调用。就像这样,我可以很容易地发现有多少触觉被遗漏了:

代码语言:javascript
复制
#import "BPAppDelegate.h"
#import "BPViewController.h"

@implementation BPAppDelegate {
    NSTimer *repeatingTimer;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    BPViewController *viewController = [[BPViewController alloc] init];
    self.window.rootViewController = viewController;
    [self.window makeKeyAndVisible];
    [self startTimer];
    return YES;
}

- (void) startTimer {
    repeatingTimer = [NSTimer scheduledTimerWithTimeInterval: 0.2
                                                      target: self.window.rootViewController
                                                    selector: @selector(timerFired:)
                                                    userInfo: nil
                                                     repeats: YES];
}

@end


#import "BPViewController.h"

@implementation BPViewController {
    UISwitch *uiSwitch;
    BOOL value;
    int count;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    value = true;
    uiSwitch = [[UISwitch alloc] init];
    uiSwitch.on = value;
    [uiSwitch addTarget:self action:@selector(touchUpInside:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:uiSwitch];
}

- (void)touchUpInside: (UISwitch *)sender {
    count++;
    value = !value;
    NSLog(@"touchUpInside: value: %d, switch: %d, count: %d", value, sender.isOn, count);
}

- (void) timerFired: (NSTimer*) theTimer {
    NSLog(@"timerFired: value: %d, switch: %d, count: %d", value, uiSwitch.isOn, count);
    // set the value according to some external state. For the example just leave it.
    [uiSwitch setOn:value animated:false];
}

@end
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-06-28 15:11:53

我的原始代码与iOS 7中预期的一样工作,因此它似乎是iOS 6中的一个bug。

票数 0
EN

Stack Overflow用户

发布于 2012-08-22 19:11:45

使用UIControlEventValueChanged确定开关何时已切换(以编程方式或由用户切换)。不要使用touchUpInside。而且,当用户拖动touchUpInside时,UISwitch也不能很好地工作。

另外,不要复制已经由UISwitch (即"on“属性)维护的属性(例如,您的值属性),该属性是冗余的,只会给您带来麻烦。

票数 5
EN

Stack Overflow用户

发布于 2012-08-22 19:11:08

编辑:下面的代码做你想做的事情,如果不是你想要的方式的话。如果确保对控件的计时器更改和触摸更改都会接收操作方法。每个更改只发送一次该方法,这是您希望的结果。

注意切换到UIControlEventValueChanged。

代码语言:javascript
复制
[sw addTarget:self action:@selector(touched:) forControlEvents:UIControlEventValueChanged];

- (void) timerFired: (NSTimer*) theTimer
{
    // set the value according to some external state. For the example just leave it.
    BOOL oldOn = sw.on;
    BOOL newOn = YES;

    [sw setOn:newOn];

    if(newOn != oldOn) {
        for(id target in [sw allTargets]) {
            for(NSString *action in [sw actionsForTarget:target forControlEvent:UIControlEventValueChanged]) {
                [target performSelector:NSSelectorFromString(action) withObject:self];
            }
        }
    }
}

EDIT2:我刚在你的答案中看到了新代码,并试用了一下。我不确定它是否做了我想做的事。然而,我不确定我是否正确地理解了它。在这两种情况下我都不想做同样的事。

  1. 问:当用户触摸开关时,我想在模型中切换布尔值。我不一定需要以编程的方式更改开关,因为它是通过触摸自动完成的。我想数一数触摸,以确保没有人丢失。

嗯,那不太可能。但是,您当然可以在action方法中添加一个计数器,并查看您所做的敲击是否与计数器相等。当用户点击开关时,然后是“发件人== theSwitch”。如果以其他方式发送操作方法,则可以使用不同的发送方(以区分它们)。

  1. 如果在我的最小示例中得到了timer事件,我只想保持当前的布尔值。但是,我需要以编程方式设置开关状态,以便视图反映正确的模型状态。-伯恩哈德·皮伯3分钟前

没关系--但是你一直说你想要调用动作方法。这个代码就是这么做的。如果您错误地说明了这一点,并且不希望调用action方法,那么删除" If“块。

代码语言:javascript
复制
- (void)insureValueIs:(BOOL)val
{
    BOOL oldVal = sw.on;
    if(val != oldVal) {
        for(id target in [sw allTargets]) {
            for(NSString *action in [sw actionsForTarget:target forControlEvent:UIControlEventValueChanged]) {
                [target performSelector:NSSelectorFromString(action) withObject:self];
            }
        }
    }
}

当然,我也想实现同样的目标:模型状态在视图中得到了正确的反映。这有意义吗?

坦率地说,你并没有很好地描述你想要的东西,我一直在回应你的评论,但即使现在我仍然不完全清楚。我相信你有你想做的任何事所需要的所有信息。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12079770

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档